From 9011cc303a72448e0d7ccaae40640c7542ad93d1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 26 Mar 2025 13:14:02 +0100 Subject: [PATCH 001/110] add new checkboxes Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 163 ++++++++++-------- .../file_details_sharing_process_fragment.xml | 52 +++++- app/src/main/res/values/strings.xml | 6 + 3 files changed, 151 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 144d3f5bf72c..b4a4450f55fc 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -80,14 +80,16 @@ class FileDetailsSharingProcessFragment : shareType: ShareType, secureShare: Boolean ): FileDetailsSharingProcessFragment { - val args = Bundle() - args.putParcelable(ARG_OCFILE, file) - args.putSerializable(ARG_SHARE_TYPE, shareType) - args.putString(ARG_SHAREE_NAME, shareeName) - args.putBoolean(ARG_SECURE_SHARE, secureShare) - val fragment = FileDetailsSharingProcessFragment() - fragment.arguments = args - return fragment + val bundle = Bundle().apply { + putParcelable(ARG_OCFILE, file) + putSerializable(ARG_SHARE_TYPE, shareType) + putString(ARG_SHAREE_NAME, shareeName) + putBoolean(ARG_SECURE_SHARE, secureShare) + } + + return FileDetailsSharingProcessFragment().apply { + arguments = bundle + } } /** @@ -100,14 +102,16 @@ class FileDetailsSharingProcessFragment : isReshareShown: Boolean, isExpirationDateShown: Boolean ): FileDetailsSharingProcessFragment { - val args = Bundle() - args.putParcelable(ARG_OCSHARE, share) - args.putInt(ARG_SCREEN_TYPE, screenType) - args.putBoolean(ARG_RESHARE_SHOWN, isReshareShown) - args.putBoolean(ARG_EXP_DATE_SHOWN, isExpirationDateShown) - val fragment = FileDetailsSharingProcessFragment() - fragment.arguments = args - return fragment + val bundle = Bundle().apply { + putParcelable(ARG_OCSHARE, share) + putInt(ARG_SCREEN_TYPE, screenType) + putBoolean(ARG_RESHARE_SHOWN, isReshareShown) + putBoolean(ARG_EXP_DATE_SHOWN, isExpirationDateShown) + } + + return FileDetailsSharingProcessFragment().apply { + arguments = bundle + } } } @@ -192,28 +196,44 @@ class FileDetailsSharingProcessFragment : } private fun themeView() { - viewThemeUtils.platform.colorTextView(binding.shareProcessEditShareLink) - viewThemeUtils.platform.colorTextView(binding.shareProcessAdvancePermissionTitle) - - viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionReadOnly) - viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionUploadEditing) - viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionFileDrop) - - viewThemeUtils.platform.themeCheckbox(binding.shareProcessAllowResharingCheckbox) - - viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetPasswordSwitch) - viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetExpDateSwitch) - viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetDownloadLimitSwitch) - viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessHideDownloadCheckbox) - viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessChangeNameSwitch) + viewThemeUtils.platform.run { + binding.run { + colorTextView(shareProcessEditShareLink) + colorTextView(shareProcessAdvancePermissionTitle) + + themeRadioButton(shareProcessPermissionReadOnly) + themeRadioButton(shareProcessPermissionUploadEditing) + themeRadioButton(shareProcessPermissionFileDrop) + + themeCheckbox(shareCustomCheckbox) + themeCheckbox(shareReadCheckbox) + themeCheckbox(shareCreateCheckbox) + themeCheckbox(shareEditCheckbox) + themeCheckbox(shareProcessAllowResharingCheckbox) + themeCheckbox(shareDeleteCheckbox) + } + } - viewThemeUtils.material.colorTextInputLayout(binding.shareProcessEnterPasswordContainer) - viewThemeUtils.material.colorTextInputLayout(binding.shareProcessSetDownloadLimitInputContainer) - viewThemeUtils.material.colorTextInputLayout(binding.shareProcessChangeNameContainer) - viewThemeUtils.material.colorTextInputLayout(binding.noteContainer) + viewThemeUtils.androidx.run { + binding.run { + colorSwitchCompat(shareProcessSetPasswordSwitch) + colorSwitchCompat(shareProcessSetExpDateSwitch) + colorSwitchCompat(shareProcessSetDownloadLimitSwitch) + colorSwitchCompat(shareProcessHideDownloadCheckbox) + colorSwitchCompat(shareProcessChangeNameSwitch) + } + } - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.shareProcessBtnNext) - viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.shareProcessBtnCancel) + viewThemeUtils.material.run { + binding.run { + colorTextInputLayout(shareProcessEnterPasswordContainer) + colorTextInputLayout(shareProcessSetDownloadLimitInputContainer) + colorTextInputLayout(shareProcessChangeNameContainer) + colorTextInputLayout(noteContainer) + colorMaterialButtonPrimaryFilled(shareProcessBtnNext) + colorMaterialButtonPrimaryOutlined(shareProcessBtnCancel) + } + } } override fun onConfigurationChanged(newConfig: Configuration) { @@ -245,11 +265,7 @@ class FileDetailsSharingProcessFragment : } // show or hide expiry date - if (isExpDateShown && !isSecureShare) { - binding.shareProcessSetExpDateSwitch.visibility = View.VISIBLE - } else { - binding.shareProcessSetExpDateSwitch.visibility = View.GONE - } + binding.shareProcessSetExpDateSwitch.setVisibleIf(isExpDateShown && !isSecureShare) shareProcessStep = SCREEN_TYPE_PERMISSION } @@ -432,30 +448,39 @@ class FileDetailsSharingProcessFragment : } private fun implementClickEvents() { - binding.shareProcessBtnCancel.setOnClickListener { - onCancelClick() - } - binding.shareProcessBtnNext.setOnClickListener { - if (shareProcessStep == SCREEN_TYPE_PERMISSION) { - validateShareProcessFirst() - } else { - validateShareProcessSecond() + binding.run { + shareProcessBtnCancel.setOnClickListener { + onCancelClick() + } + shareProcessBtnNext.setOnClickListener { + if (shareProcessStep == SCREEN_TYPE_PERMISSION) { + validateShareProcessFirst() + } else { + validateShareProcessSecond() + } + } + shareProcessSetPasswordSwitch.setOnCheckedChangeListener { _, isChecked -> + showPasswordInput(isChecked) + } + shareProcessSetExpDateSwitch.setOnCheckedChangeListener { _, isChecked -> + showExpirationDateInput(isChecked) + } + shareProcessSetDownloadLimitSwitch.setOnCheckedChangeListener { _, isChecked -> + showFileDownloadLimitInput(isChecked) + } + shareProcessChangeNameSwitch.setOnCheckedChangeListener { _, isChecked -> + showChangeNameInput(isChecked) + } + shareProcessSelectExpDate.setOnClickListener { + showExpirationDateDialog() + } + shareCustomCheckbox.setOnCheckedChangeListener { _, isChecked -> + shareReadCheckbox.isChecked = isChecked + shareCreateCheckbox.isChecked = isChecked + shareEditCheckbox.isChecked = isChecked + shareProcessAllowResharingCheckbox.isChecked = isChecked + shareDeleteCheckbox.isChecked = isChecked } - } - binding.shareProcessSetPasswordSwitch.setOnCheckedChangeListener { _, isChecked -> - showPasswordInput(isChecked) - } - binding.shareProcessSetExpDateSwitch.setOnCheckedChangeListener { _, isChecked -> - showExpirationDateInput(isChecked) - } - binding.shareProcessSetDownloadLimitSwitch.setOnCheckedChangeListener { _, isChecked -> - showFileDownloadLimitInput(isChecked) - } - binding.shareProcessChangeNameSwitch.setOnCheckedChangeListener { _, isChecked -> - showChangeNameInput(isChecked) - } - binding.shareProcessSelectExpDate.setOnClickListener { - showExpirationDateDialog() } } @@ -495,8 +520,8 @@ class FileDetailsSharingProcessFragment : } private fun showExpirationDateInput(isChecked: Boolean) { - binding.shareProcessSelectExpDate.visibility = if (isChecked) View.VISIBLE else View.GONE - binding.shareProcessExpDateDivider.visibility = if (isChecked) View.VISIBLE else View.GONE + binding.shareProcessSelectExpDate.setVisibleIf(isChecked) + binding.shareProcessExpDateDivider.setVisibleIf(isChecked) // reset the expiration date if switch is unchecked if (!isChecked) { @@ -529,9 +554,9 @@ class FileDetailsSharingProcessFragment : } private fun getReSharePermission(): Int { - val spb = SharePermissionsBuilder() - spb.setSharePermission(true) - return spb.build() + return SharePermissionsBuilder().apply { + setSharePermission(true) + }.build() } /** diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 14af3dff721c..b1d33de0ae9b 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -76,12 +76,62 @@ android:textColor="@color/primary" android:textStyle="bold"/> + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2cc9290035cc..33a372111292 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1093,6 +1093,12 @@ Share link (%1$s) Share link Allow resharing + Custom permissions + Read + Create + Edit + Share + Delete View only Editing Allow upload and editing From e606b8f70a8116e29f28a1a3f65d3b78f48b92f8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 26 Mar 2025 13:49:35 +0100 Subject: [PATCH 002/110] add setCheckboxStates Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index b4a4450f55fc..d40bc6f97587 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -191,7 +191,7 @@ class FileDetailsSharingProcessFragment : showShareProcessSecond() } implementClickEvents() - + setCheckboxStates() themeView() } @@ -484,6 +484,16 @@ class FileDetailsSharingProcessFragment : } } + private fun setCheckboxStates() { + binding.run { + shareReadCheckbox.isChecked = (permission and OCShare.READ_PERMISSION_FLAG) != 0 + shareCreateCheckbox.isChecked = (permission and OCShare.CREATE_PERMISSION_FLAG) != 0 + shareEditCheckbox.isChecked = (permission and OCShare.UPDATE_PERMISSION_FLAG) != 0 + shareProcessAllowResharingCheckbox.isChecked = (permission and OCShare.SHARE_PERMISSION_FLAG) != 0 + shareDeleteCheckbox.isChecked = (permission and OCShare.DELETE_PERMISSION_FLAG) != 0 + } + } + private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) { val dialog = ExpirationDatePickerDialogFragment.newInstance(chosenDateInMillis) dialog.setOnExpiryDateListener(this) From b0f8bc2793d75096112c6119d0e2297f35df13d0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 26 Mar 2025 14:33:32 +0100 Subject: [PATCH 003/110] add setOnCheckedChangeListeners Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index d40bc6f97587..d199580bf662 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -481,6 +481,36 @@ class FileDetailsSharingProcessFragment : shareProcessAllowResharingCheckbox.isChecked = isChecked shareDeleteCheckbox.isChecked = isChecked } + + shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> + setUserPermission(isChecked, OCShare.READ_PERMISSION_FLAG) + } + + shareCreateCheckbox.setOnCheckedChangeListener { _, isChecked -> + setUserPermission(isChecked, OCShare.CREATE_PERMISSION_FLAG) + } + + shareEditCheckbox.setOnCheckedChangeListener { _, isChecked -> + setUserPermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) + } + + shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> + setUserPermission(isChecked, OCShare.SHARE_PERMISSION_FLAG) + } + + shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> + setUserPermission(isChecked, OCShare.DELETE_PERMISSION_FLAG) + } + } + } + + private fun setUserPermission(isChecked: Boolean, permissionFlag: Int) { + share?.let { + it.permissions = if (isChecked) { + it.permissions or permissionFlag + } else { + it.permissions and permissionFlag.inv() + } } } From 1a7657e715f62a11d38a15a7e1fa33c70834bc6f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 26 Mar 2025 15:48:00 +0100 Subject: [PATCH 004/110] fix logic and add TODOs Signed-off-by: alperozturk --- .../utils/extensions/ViewExtensions.kt | 26 +++++++++++ .../FileDetailsSharingProcessFragment.kt | 44 ++++++++++++------- app/src/main/res/drawable/ic_arrow_down.xml | 5 +++ .../file_details_sharing_process_fragment.xml | 20 ++------- 4 files changed, 64 insertions(+), 31 deletions(-) create mode 100644 app/src/main/res/drawable/ic_arrow_down.xml diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt index 02cdbc3f91ee..a47cff281060 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt @@ -7,6 +7,8 @@ */ package com.nextcloud.utils.extensions +import android.animation.Animator +import android.animation.AnimatorListenerAdapter import android.content.Context import android.graphics.Outline import android.util.TypedValue @@ -19,6 +21,30 @@ fun View?.setVisibleIf(condition: Boolean) { visibility = if (condition) View.VISIBLE else View.GONE } +fun View?.setVisibilityWithAnimation(condition: Boolean, duration: Long = 200L) { + this ?: return + + if (condition) { + this.apply { + alpha = 0f + visibility = View.VISIBLE + animate() + .alpha(1f) + .setDuration(duration) + .setListener(null) + } + } else { + animate() + .alpha(0f) + .setDuration(duration) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + visibility = View.GONE + } + }) + } +} + fun View?.makeRounded(context: Context, cornerRadius: Float) { this?.let { it.apply { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index d199580bf662..75e74cdee3e9 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -21,6 +21,7 @@ import androidx.fragment.app.Fragment import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument +import com.nextcloud.utils.extensions.setVisibilityWithAnimation import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding @@ -135,6 +136,7 @@ class FileDetailsSharingProcessFragment : private var isReShareShown: Boolean = true // show or hide reShare option private var isExpDateShown: Boolean = true // show or hide expiry date option private var isSecureShare: Boolean = false + private var showCustomPermissions = true private lateinit var capabilities: OCCapability @@ -192,6 +194,7 @@ class FileDetailsSharingProcessFragment : } implementClickEvents() setCheckboxStates() + setCustomPermissionCheckboxesVisibilities() themeView() } @@ -199,13 +202,12 @@ class FileDetailsSharingProcessFragment : viewThemeUtils.platform.run { binding.run { colorTextView(shareProcessEditShareLink) - colorTextView(shareProcessAdvancePermissionTitle) + colorTextView(shareCustomPermissionsText) themeRadioButton(shareProcessPermissionReadOnly) themeRadioButton(shareProcessPermissionUploadEditing) themeRadioButton(shareProcessPermissionFileDrop) - themeCheckbox(shareCustomCheckbox) themeCheckbox(shareReadCheckbox) themeCheckbox(shareCreateCheckbox) themeCheckbox(shareEditCheckbox) @@ -261,7 +263,7 @@ class FileDetailsSharingProcessFragment : } if (isSecureShare) { - binding.shareProcessAdvancePermissionTitle.visibility = View.GONE + binding.shareCustomPermissionsText.visibility = View.GONE } // show or hide expiry date @@ -474,12 +476,12 @@ class FileDetailsSharingProcessFragment : shareProcessSelectExpDate.setOnClickListener { showExpirationDateDialog() } - shareCustomCheckbox.setOnCheckedChangeListener { _, isChecked -> - shareReadCheckbox.isChecked = isChecked - shareCreateCheckbox.isChecked = isChecked - shareEditCheckbox.isChecked = isChecked - shareProcessAllowResharingCheckbox.isChecked = isChecked - shareDeleteCheckbox.isChecked = isChecked + + shareCustomPermissionsText.setOnClickListener { + showCustomPermissions = !showCustomPermissions + val newIcon = if (showCustomPermissions) R.drawable.ic_arrow_up else R.drawable.ic_arrow_down + shareCustomPermissionsText.setCompoundDrawablesWithIntrinsicBounds(0, 0, newIcon, 0) + setCustomPermissionCheckboxesVisibilities() } shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> @@ -504,13 +506,12 @@ class FileDetailsSharingProcessFragment : } } + // TODO: check share.permission private fun setUserPermission(isChecked: Boolean, permissionFlag: Int) { - share?.let { - it.permissions = if (isChecked) { - it.permissions or permissionFlag - } else { - it.permissions and permissionFlag.inv() - } + permission = if (isChecked) { + permission or permissionFlag + } else { + permission and permissionFlag.inv() } } @@ -521,6 +522,18 @@ class FileDetailsSharingProcessFragment : shareEditCheckbox.isChecked = (permission and OCShare.UPDATE_PERMISSION_FLAG) != 0 shareProcessAllowResharingCheckbox.isChecked = (permission and OCShare.SHARE_PERMISSION_FLAG) != 0 shareDeleteCheckbox.isChecked = (permission and OCShare.DELETE_PERMISSION_FLAG) != 0 + + setCustomPermissionCheckboxesVisibilities() + } + } + + private fun setCustomPermissionCheckboxesVisibilities() { + binding.run { + shareReadCheckbox.setVisibilityWithAnimation(showCustomPermissions) + shareCreateCheckbox.setVisibilityWithAnimation(showCustomPermissions) + shareEditCheckbox.setVisibilityWithAnimation(showCustomPermissions) + shareProcessAllowResharingCheckbox.setVisibilityWithAnimation(showCustomPermissions) + shareDeleteCheckbox.setVisibilityWithAnimation(showCustomPermissions) } } @@ -644,6 +657,7 @@ class FileDetailsSharingProcessFragment : /** * get the permissions on the basis of selection */ + // TODO: Check logic it should match with new checkboxes action private fun getSelectedPermission() = when { binding.shareProcessAllowResharingCheckbox.isChecked -> getReSharePermission() binding.shareProcessPermissionReadOnly.isChecked -> OCShare.READ_PERMISSION_FLAG diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml new file mode 100644 index 000000000000..862025c7a361 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_down.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index b1d33de0ae9b..92438c517a65 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -68,28 +68,20 @@ - - Date: Thu, 27 Mar 2025 10:30:56 +0100 Subject: [PATCH 005/110] add custom permission radio button Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 76 ++++++------ .../FileDetailsSharingProcessFragment.kt | 105 ++++++++-------- .../file_details_sharing_process_fragment.xml | 114 ++++++++++-------- 3 files changed, 153 insertions(+), 142 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 29c1e120ec32..be7e3397aed0 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -293,34 +293,34 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) // validate view shown on screen - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed()))) // read-only - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() // upload and editing publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() // file drop publicShare.permissions = 4 openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() // password protection @@ -420,9 +420,9 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) // validate view shown on screen - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) @@ -430,15 +430,15 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only publicShare.permissions = 17 // from server - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) goBack() // editing publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) goBack() // hide download @@ -536,9 +536,9 @@ class FileDetailSharingFragmentIT : AbstractIT() { waitForIdleSync() // validate view shown on screen - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed()))) @@ -546,15 +546,15 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only userShare.permissions = 17 // from server - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) goBack() // editing userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) goBack() // allow reshare @@ -659,9 +659,9 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) // validate view shown on screen - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed()))) @@ -669,25 +669,25 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only userShare.permissions = 17 // from server - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() // allow upload & editing userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER // from server openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() // file drop userShare.permissions = 4 openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_permission_read_only)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_upload_editing)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_permission_file_drop)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() // allow reshare diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 75e74cdee3e9..49de0f261480 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -136,7 +136,6 @@ class FileDetailsSharingProcessFragment : private var isReShareShown: Boolean = true // show or hide reShare option private var isExpDateShown: Boolean = true // show or hide expiry date option private var isSecureShare: Boolean = false - private var showCustomPermissions = true private lateinit var capabilities: OCCapability @@ -194,7 +193,6 @@ class FileDetailsSharingProcessFragment : } implementClickEvents() setCheckboxStates() - setCustomPermissionCheckboxesVisibilities() themeView() } @@ -204,9 +202,10 @@ class FileDetailsSharingProcessFragment : colorTextView(shareProcessEditShareLink) colorTextView(shareCustomPermissionsText) - themeRadioButton(shareProcessPermissionReadOnly) - themeRadioButton(shareProcessPermissionUploadEditing) - themeRadioButton(shareProcessPermissionFileDrop) + themeRadioButton(viewOnlyRadioButton) + themeRadioButton(editingRadioButton) + themeRadioButton(fileDropRadioButton) + themeRadioButton(customPermissionRadioButton) themeCheckbox(shareReadCheckbox) themeCheckbox(shareCreateCheckbox) @@ -276,11 +275,11 @@ class FileDetailsSharingProcessFragment : // read only / allow upload and editing / file drop if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - binding.shareProcessPermissionUploadEditing.isChecked = true + binding.editingRadioButton.isChecked = true } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { - binding.shareProcessPermissionFileDrop.isChecked = true + binding.fileDropRadioButton.isChecked = true } else if (SharingMenuHelper.isReadOnly(share)) { - binding.shareProcessPermissionReadOnly.isChecked = true + binding.viewOnlyRadioButton.isChecked = true } shareType = share?.shareType ?: ShareType.NO_SHARED @@ -418,15 +417,15 @@ class FileDetailsSharingProcessFragment : } private fun updateViewForFile() { - binding.shareProcessPermissionUploadEditing.text = getString(R.string.link_share_editing) - binding.shareProcessPermissionFileDrop.visibility = View.GONE + binding.editingRadioButton.text = getString(R.string.link_share_editing) + binding.fileDropRadioButton.visibility = View.GONE } private fun updateViewForFolder() { - binding.shareProcessPermissionUploadEditing.text = getString(R.string.link_share_allow_upload_and_editing) - binding.shareProcessPermissionFileDrop.visibility = View.VISIBLE + binding.editingRadioButton.text = getString(R.string.link_share_allow_upload_and_editing) + binding.fileDropRadioButton.visibility = View.VISIBLE if (isSecureShare) { - binding.shareProcessPermissionFileDrop.visibility = View.GONE + binding.fileDropRadioButton.visibility = View.GONE binding.shareProcessAllowResharingCheckbox.visibility = View.GONE binding.shareProcessSetExpDateSwitch.visibility = View.GONE } @@ -477,13 +476,7 @@ class FileDetailsSharingProcessFragment : showExpirationDateDialog() } - shareCustomPermissionsText.setOnClickListener { - showCustomPermissions = !showCustomPermissions - val newIcon = if (showCustomPermissions) R.drawable.ic_arrow_up else R.drawable.ic_arrow_down - shareCustomPermissionsText.setCompoundDrawablesWithIntrinsicBounds(0, 0, newIcon, 0) - setCustomPermissionCheckboxesVisibilities() - } - + // region Custom Permission Checkboxes shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> setUserPermission(isChecked, OCShare.READ_PERMISSION_FLAG) } @@ -496,13 +489,49 @@ class FileDetailsSharingProcessFragment : setUserPermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) } + // TODO: Why not OCShare.SHARE_PERMISSION_FLAG? shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, OCShare.SHARE_PERMISSION_FLAG) + setUserPermission(isChecked, getReSharePermission()) } shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> setUserPermission(isChecked, OCShare.DELETE_PERMISSION_FLAG) } + // endregion + + // region RadioButtons + shareProcessPermissionRadioGroup.setOnCheckedChangeListener { radioGroup, optionId -> + run { + when (optionId) { + R.id.view_only_radio_button -> { + val isChecked = viewOnlyRadioButton.isChecked + customPermissionLayout.visibility = View.GONE + setUserPermission(isChecked, OCShare.READ_PERMISSION_FLAG) + } + R.id.editing_radio_button -> { + val isChecked = editingRadioButton.isChecked + customPermissionLayout.visibility = View.GONE + + val permissionFlag = if (file?.isFolder == true || share?.isFolder == true) { + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + } else { + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + } + + setUserPermission(isChecked, permissionFlag) + } + R.id.file_drop_radio_button -> { + val isChecked = fileDropRadioButton.isChecked + setUserPermission(isChecked, OCShare.CREATE_PERMISSION_FLAG) + } + R.id.custom_permission_radio_button -> { + val isChecked = customPermissionRadioButton.isChecked + customPermissionLayout.setVisibilityWithAnimation(isChecked) + } + } + } + } + // endregion } } @@ -522,18 +551,6 @@ class FileDetailsSharingProcessFragment : shareEditCheckbox.isChecked = (permission and OCShare.UPDATE_PERMISSION_FLAG) != 0 shareProcessAllowResharingCheckbox.isChecked = (permission and OCShare.SHARE_PERMISSION_FLAG) != 0 shareDeleteCheckbox.isChecked = (permission and OCShare.DELETE_PERMISSION_FLAG) != 0 - - setCustomPermissionCheckboxesVisibilities() - } - } - - private fun setCustomPermissionCheckboxesVisibilities() { - binding.run { - shareReadCheckbox.setVisibilityWithAnimation(showCustomPermissions) - shareCreateCheckbox.setVisibilityWithAnimation(showCustomPermissions) - shareEditCheckbox.setVisibilityWithAnimation(showCustomPermissions) - shareProcessAllowResharingCheckbox.setVisibilityWithAnimation(showCustomPermissions) - shareDeleteCheckbox.setVisibilityWithAnimation(showCustomPermissions) } } @@ -550,7 +567,8 @@ class FileDetailsSharingProcessFragment : } private fun showChangeNameInput(isChecked: Boolean) { - binding.shareProcessChangeNameContainer.visibility = if (isChecked) View.VISIBLE else View.GONE + binding.shareProcessChangeNameContainer.setVisibleIf(isChecked) + if (!isChecked) { binding.shareProcessChangeName.setText(R.string.empty) } @@ -593,7 +611,7 @@ class FileDetailsSharingProcessFragment : } private fun showPasswordInput(isChecked: Boolean) { - binding.shareProcessEnterPasswordContainer.visibility = if (isChecked) View.VISIBLE else View.GONE + binding.shareProcessEnterPasswordContainer.setVisibleIf(isChecked) // reset the password if switch is unchecked if (!isChecked) { @@ -617,7 +635,6 @@ class FileDetailsSharingProcessFragment : */ @Suppress("ReturnCount") private fun validateShareProcessFirst() { - permission = getSelectedPermission() if (permission == OCShare.NO_PERMISSION) { DisplayUtils.showSnackMessage(binding.root, R.string.no_share_permission_selected) return @@ -654,22 +671,6 @@ class FileDetailsSharingProcessFragment : } } - /** - * get the permissions on the basis of selection - */ - // TODO: Check logic it should match with new checkboxes action - private fun getSelectedPermission() = when { - binding.shareProcessAllowResharingCheckbox.isChecked -> getReSharePermission() - binding.shareProcessPermissionReadOnly.isChecked -> OCShare.READ_PERMISSION_FLAG - binding.shareProcessPermissionUploadEditing.isChecked -> when { - file?.isFolder == true || share?.isFolder == true -> OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER - else -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - } - - binding.shareProcessPermissionFileDrop.isChecked -> OCShare.CREATE_PERMISSION_FLAG - else -> permission - } - private fun updateShare() { fileOperationsHelper?.updateShareInformation( share, diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 92438c517a65..ff7326455bdf 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -45,21 +45,28 @@ android:orientation="vertical"> + + - + android:orientation="vertical" + android:layout_height="wrap_content"> - + - + - + - + - + + + + + Date: Thu, 27 Mar 2025 11:13:19 +0100 Subject: [PATCH 006/110] use share.permission Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 49de0f261480..6ec4079090bb 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -535,22 +535,30 @@ class FileDetailsSharingProcessFragment : } } - // TODO: check share.permission private fun setUserPermission(isChecked: Boolean, permissionFlag: Int) { - permission = if (isChecked) { - permission or permissionFlag + val currentPermissions = share?.permissions ?: permission + val updatedPermissions = if (isChecked) { + currentPermissions or permissionFlag } else { - permission and permissionFlag.inv() + currentPermissions and permissionFlag.inv() + } + + if (share?.permissions != null) { + share!!.permissions = updatedPermissions + } else { + permission = updatedPermissions } } private fun setCheckboxStates() { + val currentPermissions = share?.permissions ?: permission + binding.run { - shareReadCheckbox.isChecked = (permission and OCShare.READ_PERMISSION_FLAG) != 0 - shareCreateCheckbox.isChecked = (permission and OCShare.CREATE_PERMISSION_FLAG) != 0 - shareEditCheckbox.isChecked = (permission and OCShare.UPDATE_PERMISSION_FLAG) != 0 - shareProcessAllowResharingCheckbox.isChecked = (permission and OCShare.SHARE_PERMISSION_FLAG) != 0 - shareDeleteCheckbox.isChecked = (permission and OCShare.DELETE_PERMISSION_FLAG) != 0 + shareReadCheckbox.isChecked = (currentPermissions and OCShare.READ_PERMISSION_FLAG) != 0 + shareCreateCheckbox.isChecked = (currentPermissions and OCShare.CREATE_PERMISSION_FLAG) != 0 + shareEditCheckbox.isChecked = (currentPermissions and OCShare.UPDATE_PERMISSION_FLAG) != 0 + shareProcessAllowResharingCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) != 0 + shareDeleteCheckbox.isChecked = (currentPermissions and OCShare.DELETE_PERMISSION_FLAG) != 0 } } From 8c3f7d4a3f29a662e2cccbf2b64cf84ceb6d1eeb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 11:15:14 +0100 Subject: [PATCH 007/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 3 ++- app/src/main/res/drawable/ic_arrow_down.xml | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_arrow_down.xml diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 6ec4079090bb..c811da0b34b6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -448,6 +448,7 @@ class FileDetailsSharingProcessFragment : shareProcessStep = SCREEN_TYPE_NOTE } + @Suppress("LongMethod") private fun implementClickEvents() { binding.run { shareProcessBtnCancel.setOnClickListener { @@ -489,7 +490,7 @@ class FileDetailsSharingProcessFragment : setUserPermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) } - // TODO: Why not OCShare.SHARE_PERMISSION_FLAG? + // TODO Why not OCShare.SHARE_PERMISSION_FLAG? shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> setUserPermission(isChecked, getReSharePermission()) } diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml deleted file mode 100644 index 862025c7a361..000000000000 --- a/app/src/main/res/drawable/ic_arrow_down.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - From 3e8b9494d6ddec06d68707f9eae078a72200120a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 11:30:04 +0100 Subject: [PATCH 008/110] add missing test parts Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 45 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 - 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index be7e3397aed0..79a917b13be6 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -36,6 +36,7 @@ import com.owncloud.android.lib.resources.shares.OCShare.Companion.MAXIMUM_PERMI import com.owncloud.android.lib.resources.shares.OCShare.Companion.NO_PERMISSION import com.owncloud.android.lib.resources.shares.OCShare.Companion.READ_PERMISSION_FLAG import com.owncloud.android.lib.resources.shares.OCShare.Companion.SHARE_PERMISSION_FLAG +import com.owncloud.android.lib.resources.shares.OCShare.Companion.UPDATE_PERMISSION_FLAG import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.fragment.util.SharingMenuHelper @@ -295,6 +296,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) @@ -304,6 +306,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -312,6 +315,16 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + goBack() + + // custom permission + publicShare.permissions = UPDATE_PERMISSION_FLAG + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -320,6 +333,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() @@ -422,6 +436,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) @@ -432,6 +447,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { publicShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) goBack() // editing @@ -439,6 +455,15 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) + goBack() + + // create + publicShare.permissions = CREATE_PERMISSION_FLAG + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isChecked())) goBack() // hide download @@ -538,6 +563,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) @@ -548,6 +574,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) goBack() // editing @@ -555,16 +582,19 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) goBack() // allow reshare userShare.permissions = 1 // from server openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isNotChecked())) goBack() userShare.permissions = 17 // from server openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) goBack() @@ -661,6 +691,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) @@ -671,6 +702,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -679,6 +711,16 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + goBack() + + // create + userShare.permissions = CREATE_PERMISSION_FLAG + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -687,17 +729,20 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() // allow reshare userShare.permissions = 1 // from server openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isNotChecked())) goBack() userShare.permissions = 17 // from server openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) goBack() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 33a372111292..51562d0a13ee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1173,7 +1173,6 @@ File drop Secure file drop Share permissions - Advanced settings Next Send share Please select at least one permission to share. From 8281cd73c4af9af9a2749acb2ec5e7ec8b931566 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 14:25:03 +0100 Subject: [PATCH 009/110] revert changes Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 79a917b13be6..be7e3397aed0 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -36,7 +36,6 @@ import com.owncloud.android.lib.resources.shares.OCShare.Companion.MAXIMUM_PERMI import com.owncloud.android.lib.resources.shares.OCShare.Companion.NO_PERMISSION import com.owncloud.android.lib.resources.shares.OCShare.Companion.READ_PERMISSION_FLAG import com.owncloud.android.lib.resources.shares.OCShare.Companion.SHARE_PERMISSION_FLAG -import com.owncloud.android.lib.resources.shares.OCShare.Companion.UPDATE_PERMISSION_FLAG import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.fragment.util.SharingMenuHelper @@ -296,7 +295,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) @@ -306,7 +304,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -315,16 +312,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) - goBack() - - // custom permission - publicShare.permissions = UPDATE_PERMISSION_FLAG - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -333,7 +320,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() @@ -436,7 +422,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) @@ -447,7 +432,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { publicShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) goBack() // editing @@ -455,15 +439,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) - goBack() - - // create - publicShare.permissions = CREATE_PERMISSION_FLAG - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isChecked())) goBack() // hide download @@ -563,7 +538,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) @@ -574,7 +548,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) goBack() // editing @@ -582,19 +555,16 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) goBack() // allow reshare userShare.permissions = 1 // from server openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isNotChecked())) goBack() userShare.permissions = 17 // from server openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) goBack() @@ -691,7 +661,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) @@ -702,7 +671,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -711,16 +679,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) - goBack() - - // create - userShare.permissions = CREATE_PERMISSION_FLAG - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) goBack() @@ -729,20 +687,17 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() // allow reshare userShare.permissions = 1 // from server openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isNotChecked())) goBack() userShare.permissions = 17 // from server openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.custom_permission_radio_button)).perform(ViewActions.click()) onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) goBack() From ec85a54f0772f42fe6578d862653fcd2ac4facb1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 14:35:32 +0100 Subject: [PATCH 010/110] add advanced settings back Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 11 +++++++--- .../file_details_sharing_process_fragment.xml | 20 ++++++++++++++++++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index c811da0b34b6..6d206ab0e964 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -210,8 +210,10 @@ class FileDetailsSharingProcessFragment : themeCheckbox(shareReadCheckbox) themeCheckbox(shareCreateCheckbox) themeCheckbox(shareEditCheckbox) - themeCheckbox(shareProcessAllowResharingCheckbox) + themeCheckbox(shareCheckbox) themeCheckbox(shareDeleteCheckbox) + + themeCheckbox(shareProcessAllowResharingCheckbox) } } @@ -490,11 +492,14 @@ class FileDetailsSharingProcessFragment : setUserPermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) } - // TODO Why not OCShare.SHARE_PERMISSION_FLAG? shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> setUserPermission(isChecked, getReSharePermission()) } + shareCheckbox.setOnCheckedChangeListener { _, isChecked -> + setUserPermission(isChecked, OCShare.SHARE_PERMISSION_FLAG) + } + shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> setUserPermission(isChecked, OCShare.DELETE_PERMISSION_FLAG) } @@ -558,7 +563,7 @@ class FileDetailsSharingProcessFragment : shareReadCheckbox.isChecked = (currentPermissions and OCShare.READ_PERMISSION_FLAG) != 0 shareCreateCheckbox.isChecked = (currentPermissions and OCShare.CREATE_PERMISSION_FLAG) != 0 shareEditCheckbox.isChecked = (currentPermissions and OCShare.UPDATE_PERMISSION_FLAG) != 0 - shareProcessAllowResharingCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) != 0 + shareCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) != 0 shareDeleteCheckbox.isChecked = (currentPermissions and OCShare.DELETE_PERMISSION_FLAG) != 0 } } diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index ff7326455bdf..b030b2e44ff1 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -74,6 +74,24 @@ + + + + File drop Secure file drop Share permissions + Advanced settings Next Send share Please select at least one permission to share. From 782294e1c3f073af1c3c1b0c17fda498413d91dc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 14:40:03 +0100 Subject: [PATCH 011/110] grayed out read Signed-off-by: alperozturk --- .../main/res/layout/file_details_sharing_process_fragment.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index b030b2e44ff1..d1ae3ed98f16 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -114,6 +114,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/minimum_size_for_touchable_area" + android:enabled="false" android:text="@string/share_read_permission" tools:visibility="visible" /> From b32fdb237299130c553a46e2a60f4f7f55f26b0c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 15:21:29 +0100 Subject: [PATCH 012/110] revert changes Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 6d206ab0e964..64ece245428d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -264,7 +264,7 @@ class FileDetailsSharingProcessFragment : } if (isSecureShare) { - binding.shareCustomPermissionsText.visibility = View.GONE + binding.shareProcessAdvancePermissionTitle.visibility = View.GONE } // show or hide expiry date From dd99814f721f086ab643940a9844cf4e605d5f68 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Mar 2025 16:19:10 +0100 Subject: [PATCH 013/110] fix failing tests Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 1281 +++++++++-------- 1 file changed, 713 insertions(+), 568 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index be7e3397aed0..99cac6c885a8 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -9,15 +9,18 @@ package com.owncloud.android.ui.fragment import android.view.View +import androidx.annotation.UiThread +import androidx.test.core.app.launchActivity import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.accessibility.AccessibilityChecks import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.intent.rule.IntentsTestRule import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.isChecked import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isNotChecked +import androidx.test.espresso.matcher.ViewMatchers.isRoot import androidx.test.espresso.matcher.ViewMatchers.withText import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultBaseUtils.matchesCheckNames import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils.matchesViews @@ -39,6 +42,7 @@ import com.owncloud.android.lib.resources.shares.OCShare.Companion.SHARE_PERMISS import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.fragment.util.SharingMenuHelper +import com.owncloud.android.utils.EspressoIdlingResource import com.owncloud.android.utils.ScreenshotTest import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.anyOf @@ -53,40 +57,53 @@ import org.junit.Test @Suppress("TooManyFunctions") class FileDetailSharingFragmentIT : AbstractIT() { - @get:Rule - val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false) + private val testClassName = "com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT" @get:Rule val retryRule = RetryTestRule() lateinit var file: OCFile lateinit var folder: OCFile - lateinit var activity: TestActivity @Before - fun before() { - activity = testActivityRule.launchActivity(null) - file = OCFile("/test.md").apply { - remoteId = "00000001" - parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId - permissions = OCFile.PERMISSION_CAN_RESHARE - fileDataStorageManager.saveFile(this) - } + fun registerIdlingResource() { + IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource) + } + + @After + fun unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource) + } - folder = OCFile("/test").apply { - setFolder() - parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId - permissions = OCFile.PERMISSION_CAN_RESHARE + @Before + fun before() { + launchActivity().use { scenario -> + scenario.onActivity { activity -> + file = OCFile("/test.md").apply { + remoteId = "00000001" + parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId + permissions = OCFile.PERMISSION_CAN_RESHARE + fileDataStorageManager.saveFile(this) + } + + folder = OCFile("/test").apply { + setFolder() + parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId + permissions = OCFile.PERMISSION_CAN_RESHARE + } + } } } @Test + @UiThread @ScreenshotTest fun listSharesFileNone() { show(file) } @Test + @UiThread @ScreenshotTest fun listSharesFileResharingNotAllowed() { file.permissions = "" @@ -95,171 +112,196 @@ class FileDetailSharingFragmentIT : AbstractIT() { } @Test + @UiThread @ScreenshotTest fun listSharesDownloadLimit() { - OCShare(file.decryptedRemotePath).apply { - remoteId = 1 - shareType = ShareType.PUBLIC_LINK - token = "AAAAAAAAAAAAAAA" - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 2 - shareType = ShareType.PUBLIC_LINK - token = "BBBBBBBBBBBBBBB" - fileDownloadLimit = FileDownloadLimit("BBBBBBBBBBBBBBB", 0, 0) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 3 - shareType = ShareType.PUBLIC_LINK - token = "CCCCCCCCCCCCCCC" - fileDownloadLimit = FileDownloadLimit("CCCCCCCCCCCCCCC", 10, 0) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 4 - shareType = ShareType.PUBLIC_LINK - token = "DDDDDDDDDDDDDDD" - fileDownloadLimit = FileDownloadLimit("DDDDDDDDDDDDDDD", 10, 5) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 5 - shareType = ShareType.PUBLIC_LINK - token = "FFFFFFFFFFFFFFF" - fileDownloadLimit = FileDownloadLimit("FFFFFFFFFFFFFFF", 10, 10) - activity.storageManager.saveShare(this) + launchActivity().use { scenario -> + scenario.onActivity { activity -> + onIdleSync { + EspressoIdlingResource.increment() + OCShare(file.decryptedRemotePath).apply { + remoteId = 1 + shareType = ShareType.PUBLIC_LINK + token = "AAAAAAAAAAAAAAA" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 2 + shareType = ShareType.PUBLIC_LINK + token = "BBBBBBBBBBBBBBB" + fileDownloadLimit = FileDownloadLimit("BBBBBBBBBBBBBBB", 0, 0) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 3 + shareType = ShareType.PUBLIC_LINK + token = "CCCCCCCCCCCCCCC" + fileDownloadLimit = FileDownloadLimit("CCCCCCCCCCCCCCC", 10, 0) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 4 + shareType = ShareType.PUBLIC_LINK + token = "DDDDDDDDDDDDDDD" + fileDownloadLimit = FileDownloadLimit("DDDDDDDDDDDDDDD", 10, 5) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 5 + shareType = ShareType.PUBLIC_LINK + token = "FFFFFFFFFFFFFFF" + fileDownloadLimit = FileDownloadLimit("FFFFFFFFFFFFFFF", 10, 10) + activity.storageManager.saveShare(this) + } + EspressoIdlingResource.decrement() + + show(file) + } + } } - - show(file) } /** * Use same values as {@link OCFileListFragmentStaticServerIT showSharedFiles } */ @Test + @UiThread @ScreenshotTest @Suppress("MagicNumber") fun listSharesFileAllShareTypes() { - OCShare(file.decryptedRemotePath).apply { - remoteId = 1 - shareType = ShareType.USER - sharedWithDisplayName = "Admin" - permissions = MAXIMUM_PERMISSIONS_FOR_FILE - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 2 - shareType = ShareType.GROUP - sharedWithDisplayName = "Group" - permissions = MAXIMUM_PERMISSIONS_FOR_FILE - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 3 - shareType = ShareType.EMAIL - sharedWithDisplayName = "admin@nextcloud.localhost" - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 4 - shareType = ShareType.PUBLIC_LINK - label = "Customer" - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 5 - shareType = ShareType.PUBLIC_LINK - label = "Colleagues" - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 6 - shareType = ShareType.FEDERATED - sharedWithDisplayName = "admin@nextcloud.localhost" - permissions = OCShare.FEDERATED_PERMISSIONS_FOR_FILE - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 7 - shareType = ShareType.CIRCLE - sharedWithDisplayName = "Personal team" - permissions = SHARE_PERMISSION_FLAG - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 8 - shareType = ShareType.CIRCLE - sharedWithDisplayName = "Public team" - permissions = SHARE_PERMISSION_FLAG - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 9 - shareType = ShareType.CIRCLE - sharedWithDisplayName = "Closed team" - permissions = SHARE_PERMISSION_FLAG - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 10 - shareType = ShareType.CIRCLE - sharedWithDisplayName = "Secret team" - permissions = SHARE_PERMISSION_FLAG - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 11 - shareType = ShareType.ROOM - sharedWithDisplayName = "Admin" - permissions = SHARE_PERMISSION_FLAG - userId = getUserId(user) - activity.storageManager.saveShare(this) - } - - OCShare(file.decryptedRemotePath).apply { - remoteId = 12 - shareType = ShareType.ROOM - sharedWithDisplayName = "Meeting" - permissions = SHARE_PERMISSION_FLAG - userId = getUserId(user) - activity.storageManager.saveShare(this) + launchActivity().use { scenario -> + scenario.onActivity { activity -> + onIdleSync { + EspressoIdlingResource.increment() + OCShare(file.decryptedRemotePath).apply { + remoteId = 1 + shareType = ShareType.USER + sharedWithDisplayName = "Admin" + permissions = MAXIMUM_PERMISSIONS_FOR_FILE + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 2 + shareType = ShareType.GROUP + sharedWithDisplayName = "Group" + permissions = MAXIMUM_PERMISSIONS_FOR_FILE + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 3 + shareType = ShareType.EMAIL + sharedWithDisplayName = "admin@nextcloud.localhost" + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 4 + shareType = ShareType.PUBLIC_LINK + label = "Customer" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 5 + shareType = ShareType.PUBLIC_LINK + label = "Colleagues" + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 6 + shareType = ShareType.FEDERATED + sharedWithDisplayName = "admin@nextcloud.localhost" + permissions = OCShare.FEDERATED_PERMISSIONS_FOR_FILE + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 7 + shareType = ShareType.CIRCLE + sharedWithDisplayName = "Personal team" + permissions = SHARE_PERMISSION_FLAG + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 8 + shareType = ShareType.CIRCLE + sharedWithDisplayName = "Public team" + permissions = SHARE_PERMISSION_FLAG + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 9 + shareType = ShareType.CIRCLE + sharedWithDisplayName = "Closed team" + permissions = SHARE_PERMISSION_FLAG + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 10 + shareType = ShareType.CIRCLE + sharedWithDisplayName = "Secret team" + permissions = SHARE_PERMISSION_FLAG + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 11 + shareType = ShareType.ROOM + sharedWithDisplayName = "Admin" + permissions = SHARE_PERMISSION_FLAG + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + + OCShare(file.decryptedRemotePath).apply { + remoteId = 12 + shareType = ShareType.ROOM + sharedWithDisplayName = "Meeting" + permissions = SHARE_PERMISSION_FLAG + userId = getUserId(user) + activity.storageManager.saveShare(this) + } + EspressoIdlingResource.decrement() + + show(file) + } + } } - - show(file) } private fun show(file: OCFile) { - val fragment = FileDetailSharingFragment.newInstance(file, user) - - activity.addFragment(fragment) - - waitForIdleSync() - - screenshot(activity) + launchActivity().use { scenario -> + scenario.onActivity { sut -> + onIdleSync { + EspressoIdlingResource.increment() + val fragment = FileDetailSharingFragment.newInstance(file, user) + sut.addFragment(fragment) + EspressoIdlingResource.decrement() + + val screenShotName = createName(testClassName + "_" + "show", "") + onView(isRoot()).check(matches(isDisplayed())) + screenshotViaName(sut, screenShotName) + } + } + } } // public link and email are handled the same way @@ -267,95 +309,108 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun publicLinkOptionMenuFolderAdvancePermission() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val publicShare = OCShare().apply { - isFolder = true - shareType = ShareType.PUBLIC_LINK - permissions = 17 - } + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + + val publicShare = OCShare().apply { + isFolder = true + shareType = ShareType.PUBLIC_LINK + permissions = 17 + } + + EspressoIdlingResource.decrement() + activity.runOnUiThread { sut.showSharingMenuActionSheet(publicShare) } + + // check if items are visible + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) + + // click event + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) + + // validate view shown on screen + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check( + matches( + not( + isDisplayed() + ) + ) + ) - activity.runOnUiThread { sut.showSharingMenuActionSheet(publicShare) } - shortSleep() - waitForIdleSync() - - // check if items are visible - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) - - // click event - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) - - // validate view shown on screen - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed()))) - - // read-only - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) - goBack() - - // upload and editing - publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) - goBack() - - // file drop - publicShare.permissions = 4 - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) - goBack() - - // password protection - publicShare.shareWith = "someValue" - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isChecked())) - goBack() - - publicShare.shareWith = "" - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isNotChecked())) - goBack() - - // hide download - publicShare.isHideFileDownload = true - publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isChecked())) - goBack() - - publicShare.isHideFileDownload = false - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isNotChecked())) - goBack() - - publicShare.expirationDate = 1582019340000 - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) - goBack() - - publicShare.expirationDate = 0 - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) + // read-only + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + goBack() + + // upload and editing + publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + goBack() + + // file drop + publicShare.permissions = 4 + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) + goBack() + + // password protection + publicShare.shareWith = "someValue" + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isChecked())) + goBack() + + publicShare.shareWith = "" + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isNotChecked())) + goBack() + + // hide download + publicShare.isHideFileDownload = true + publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isChecked())) + goBack() + + publicShare.isHideFileDownload = false + openAdvancedPermissions(sut, publicShare) + onView( + ViewMatchers.withId(R.id.share_process_hide_download_checkbox) + ).check(matches(isNotChecked())) + goBack() + + publicShare.expirationDate = 1582019340000 + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) + goBack() + + publicShare.expirationDate = 0 + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) + } + } + } } // public link and email are handled the same way @@ -363,32 +418,43 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun publicLinkOptionMenuFolderSendNewEmail() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val publicShare = OCShare().apply { - isFolder = true - shareType = ShareType.PUBLIC_LINK - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val publicShare = OCShare().apply { + isFolder = true + shareType = ShareType.PUBLIC_LINK + permissions = 17 + } + + verifySendNewEmail(sut, publicShare) + } + } } - - verifySendNewEmail(sut, publicShare) } private fun setupSecondaryFragment() { - val parentFolder = OCFile("/") - val secondary = FileDetailFragment.newInstance(file, parentFolder, user) - activity.addSecondaryFragment(secondary, FileDisplayActivity.TAG_LIST_OF_FILES) - activity.addView( - FloatingActionButton(activity).apply { - // needed for some reason - visibility = View.GONE - id = R.id.fab_main + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val parentFolder = OCFile("/") + val secondary = FileDetailFragment.newInstance(file, parentFolder, user) + activity.addSecondaryFragment(secondary, FileDisplayActivity.TAG_LIST_OF_FILES) + activity.addView( + FloatingActionButton(activity).apply { + // needed for some reason + visibility = View.GONE + id = R.id.fab_main + } + ) } - ) + } } // public link and email are handled the same way @@ -396,86 +462,102 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun publicLinkOptionMenuFileAdvancePermission() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val publicShare = OCShare().apply { - isFolder = false - shareType = ShareType.PUBLIC_LINK - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val publicShare = OCShare().apply { + isFolder = false + shareType = ShareType.PUBLIC_LINK + permissions = 17 + } + activity.handler.post { sut.showSharingMenuActionSheet(publicShare) } + waitForIdleSync() + + // check if items are visible + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) + + // click event + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) + + // validate view shown on screen + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check( + matches( + not( + isDisplayed() + ) + ) + ) + + // read-only + publicShare.permissions = 17 // from server + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + goBack() + + // editing + publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + goBack() + + // hide download + publicShare.isHideFileDownload = true + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isChecked())) + goBack() + + publicShare.isHideFileDownload = false + openAdvancedPermissions(sut, publicShare) + onView( + ViewMatchers.withId(R.id.share_process_hide_download_checkbox) + ).check(matches(isNotChecked())) + goBack() + + // password protection + publicShare.isPasswordProtected = true + publicShare.shareWith = "someValue" + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isChecked())) + goBack() + + publicShare.isPasswordProtected = false + publicShare.shareWith = "" + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isNotChecked())) + goBack() + + // expires + publicShare.expirationDate = 1582019340 + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) + goBack() + + publicShare.expirationDate = 0 + openAdvancedPermissions(sut, publicShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) + } + } } - activity.handler.post { sut.showSharingMenuActionSheet(publicShare) } - waitForIdleSync() - - // check if items are visible - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) - - // click event - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) - - // validate view shown on screen - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(not(isDisplayed()))) - - // read-only - publicShare.permissions = 17 // from server - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - goBack() - - // editing - publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - goBack() - - // hide download - publicShare.isHideFileDownload = true - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isChecked())) - goBack() - - publicShare.isHideFileDownload = false - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isNotChecked())) - goBack() - - // password protection - publicShare.isPasswordProtected = true - publicShare.shareWith = "someValue" - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isChecked())) - goBack() - - publicShare.isPasswordProtected = false - publicShare.shareWith = "" - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isNotChecked())) - goBack() - - // expires - publicShare.expirationDate = 1582019340 - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) - goBack() - - publicShare.expirationDate = 0 - openAdvancedPermissions(sut, publicShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) } // public link and email are handled the same way @@ -483,19 +565,26 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun publicLinkOptionMenuFileSendNewEmail() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val publicShare = OCShare().apply { - isFolder = false - shareType = ShareType.PUBLIC_LINK - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val publicShare = OCShare().apply { + isFolder = false + shareType = ShareType.PUBLIC_LINK + permissions = 17 + } + + verifySendNewEmail(sut, publicShare) + } + } } - - verifySendNewEmail(sut, publicShare) } // also applies for @@ -507,78 +596,94 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun userOptionMenuFileAdvancePermission() { - val sut = FileDetailSharingFragment.newInstance(file, user) - suppressFDFAccessibilityChecks() - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val userShare = OCShare().apply { - isFolder = false - shareType = ShareType.USER - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + suppressFDFAccessibilityChecks() + activity.addFragment(sut) + + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val userShare = OCShare().apply { + isFolder = false + shareType = ShareType.USER + permissions = 17 + } + + activity.runOnUiThread { sut.showSharingMenuActionSheet(userShare) } + + // check if items are visible + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) + + // click event + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) + shortSleep() + waitForIdleSync() + + // validate view shown on screen + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_hide_download_checkbox) + ).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_set_password_switch) + ).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_change_name_switch) + ).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) + ).check(matches(isDisplayed())) + + // read-only + userShare.permissions = 17 // from server + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + goBack() + + // editing + userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + goBack() + + // allow reshare + userShare.permissions = 1 // from server + openAdvancedPermissions(sut, userShare) + onView( + ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) + ).check(matches(isNotChecked())) + goBack() + + userShare.permissions = 17 // from server + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) + goBack() + + // set expiration date + userShare.expirationDate = 1582019340000 + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) + goBack() + + userShare.expirationDate = 0 + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) + } + } } - - activity.runOnUiThread { sut.showSharingMenuActionSheet(userShare) } - shortSleep() - waitForIdleSync() - - // check if items are visible - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) - - // click event - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) - shortSleep() - waitForIdleSync() - - // validate view shown on screen - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isDisplayed())) - - // read-only - userShare.permissions = 17 // from server - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - goBack() - - // editing - userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - goBack() - - // allow reshare - userShare.permissions = 1 // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isNotChecked())) - goBack() - - userShare.permissions = 17 // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) - goBack() - - // set expiration date - userShare.expirationDate = 1582019340000 - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) - goBack() - - userShare.expirationDate = 0 - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) } private fun suppressFDFAccessibilityChecks() { @@ -607,20 +712,28 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun userOptionMenuFileSendNewEmail() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val userShare = OCShare().apply { - remoteId = 1001L - isFolder = false - shareType = ShareType.USER - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val userShare = OCShare().apply { + remoteId = 1001L + isFolder = false + shareType = ShareType.USER + permissions = 17 + } + + verifySendNewEmail(sut, userShare) + } + } } - - verifySendNewEmail(sut, userShare) } // also applies for @@ -632,108 +745,134 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun userOptionMenuFolderAdvancePermission() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - suppressFDFAccessibilityChecks() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val userShare = OCShare().apply { - isFolder = true - shareType = ShareType.USER - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + suppressFDFAccessibilityChecks() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val userShare = OCShare().apply { + isFolder = true + shareType = ShareType.USER + permissions = 17 + } + + activity.runOnUiThread { sut.showSharingMenuActionSheet(userShare) } + + // check if items are visible + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) + + // click event + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) + + // validate view shown on screen + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) + onView( + ViewMatchers.withId(R.id.share_process_hide_download_checkbox) + ).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_set_password_switch) + ).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_change_name_switch) + ).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) + ).check(matches(isDisplayed())) + + // read-only + userShare.permissions = 17 // from server + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + goBack() + + // allow upload & editing + userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER // from server + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + goBack() + + // file drop + userShare.permissions = 4 + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) + goBack() + + // allow reshare + userShare.permissions = 1 // from server + openAdvancedPermissions(sut, userShare) + onView( + ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) + ).check(matches(isNotChecked())) + goBack() + + userShare.permissions = 17 // from server + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) + goBack() + + // set expiration date + userShare.expirationDate = 1582019340000 + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) + goBack() + + userShare.expirationDate = 0 + openAdvancedPermissions(sut, userShare) + onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) + } + } } - - activity.runOnUiThread { sut.showSharingMenuActionSheet(userShare) } - shortSleep() - waitForIdleSync() - - // check if items are visible - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.menu_share_send_link)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.menu_share_unshare)).check(matches(isDisplayed())) - - // click event - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) - - // validate view shown on screen - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(not(isDisplayed()))) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isDisplayed())) - - // read-only - userShare.permissions = 17 // from server - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) - goBack() - - // allow upload & editing - userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) - goBack() - - // file drop - userShare.permissions = 4 - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) - goBack() - - // allow reshare - userShare.permissions = 1 // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isNotChecked())) - goBack() - - userShare.permissions = 17 // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) - goBack() - - // set expiration date - userShare.expirationDate = 1582019340000 - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(not(withText("")))) - goBack() - - userShare.expirationDate = 0 - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_set_exp_date_switch)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.share_process_select_exp_date)).check(matches(withText(""))) } // open bottom sheet with actions private fun openAdvancedPermissions(sut: FileDetailSharingFragment, userShare: OCShare) { - activity.handler.post { - sut.showSharingMenuActionSheet(userShare) + launchActivity().use { scenario -> + scenario.onActivity { activity -> + onIdleSync { + EspressoIdlingResource.increment() + activity.handler.post { + sut.showSharingMenuActionSheet(userShare) + } + EspressoIdlingResource.decrement() + onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) + } + } } - shortSleep() - waitForIdleSync() - onView(ViewMatchers.withId(R.id.menu_share_advanced_permissions)).perform(ViewActions.click()) } // remove the fragment shown private fun goBack() { - activity.handler.post { - val processFragment = - activity.supportFragmentManager.findFragmentByTag(FileDetailsSharingProcessFragment.TAG) as - FileDetailsSharingProcessFragment - processFragment.onBackPressed() + launchActivity().use { scenario -> + scenario.onActivity { activity -> + onIdleSync { + activity.handler.post { + val processFragment = + activity.supportFragmentManager.findFragmentByTag(FileDetailsSharingProcessFragment.TAG) as + FileDetailsSharingProcessFragment + processFragment.onBackPressed() + } + } + } } - shortSleep() - waitForIdleSync() } // also applies for @@ -745,33 +884,47 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test @Suppress("MagicNumber") fun userOptionMenuFolderSendNewEmail() { - val sut = FileDetailSharingFragment.newInstance(file, user) - activity.addFragment(sut) - setupSecondaryFragment() - shortSleep() - sut.refreshCapabilitiesFromDB() - - val userShare = OCShare().apply { - isFolder = true - shareType = ShareType.USER - permissions = 17 + launchActivity().use { scenario -> + scenario.onActivity { activity -> + val sut = FileDetailSharingFragment.newInstance(file, user) + activity.addFragment(sut) + onIdleSync { + EspressoIdlingResource.increment() + setupSecondaryFragment() + sut.refreshCapabilitiesFromDB() + EspressoIdlingResource.decrement() + + val userShare = OCShare().apply { + isFolder = true + shareType = ShareType.USER + permissions = 17 + } + + verifySendNewEmail(sut, userShare) + } + } } - - verifySendNewEmail(sut, userShare) } /** * verify send new email note text */ private fun verifySendNewEmail(sut: FileDetailSharingFragment, userShare: OCShare) { - activity.runOnUiThread { sut.showSharingMenuActionSheet(userShare) } - - waitForIdleSync() - // click event - onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).perform(ViewActions.click()) - - // validate view shown on screen - onView(ViewMatchers.withId(R.id.note_text)).check(matches(isDisplayed())) + launchActivity().use { scenario -> + scenario.onActivity { activity -> + onIdleSync { + EspressoIdlingResource.increment() + activity.runOnUiThread { sut.showSharingMenuActionSheet(userShare) } + EspressoIdlingResource.decrement() + + // click event + onView(ViewMatchers.withId(R.id.menu_share_send_new_email)).perform(ViewActions.click()) + + // validate view shown on screen + onView(ViewMatchers.withId(R.id.note_text)).check(matches(isDisplayed())) + } + } + } } @Test @@ -856,12 +1009,4 @@ class FileDetailSharingFragmentIT : AbstractIT() { share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE assertFalse(SharingMenuHelper.isFileDrop(share)) } - - @After - override fun after() { - activity.storageManager.cleanShares() - activity.finish() - - super.after() - } } From b553211b269398aefe553ce21a8d543112d5a893 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 31 Mar 2025 11:32:43 +0200 Subject: [PATCH 014/110] fix setUserPermission Signed-off-by: alperozturk --- .../fragment/FileDetailsSharingProcessFragment.kt | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 64ece245428d..3d523a4fd82d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -542,17 +542,10 @@ class FileDetailsSharingProcessFragment : } private fun setUserPermission(isChecked: Boolean, permissionFlag: Int) { - val currentPermissions = share?.permissions ?: permission - val updatedPermissions = if (isChecked) { - currentPermissions or permissionFlag - } else { - currentPermissions and permissionFlag.inv() - } - - if (share?.permissions != null) { - share!!.permissions = updatedPermissions + permission = if (isChecked) { + permission or permissionFlag } else { - permission = updatedPermissions + permission and permissionFlag.inv() } } From 8d29e08c14463ddbbd2492b67e609b27d3a91608 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 31 Mar 2025 14:46:44 +0200 Subject: [PATCH 015/110] add SharePermissionManager Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 86 +++++++++++-------- .../fragment/util/SharePermissionManager.kt | 58 +++++++++++++ 2 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 3d523a4fd82d..affab8ea4506 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -32,6 +32,7 @@ import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment +import com.owncloud.android.ui.fragment.util.SharePermissionManager import com.owncloud.android.ui.fragment.util.SharingMenuHelper import com.owncloud.android.ui.helpers.FileOperationsHelper import com.owncloud.android.utils.ClipboardUtil @@ -136,6 +137,7 @@ class FileDetailsSharingProcessFragment : private var isReShareShown: Boolean = true // show or hide reShare option private var isExpDateShown: Boolean = true // show or hide expiry date option private var isSecureShare: Boolean = false + private val sharePermissionManager = SharePermissionManager() private lateinit var capabilities: OCCapability @@ -172,6 +174,7 @@ class FileDetailsSharingProcessFragment : fileActivity = activity as FileActivity? capabilities = CapabilityUtils.getCapability(context) + setInitialPermission() requireNotNull(fileActivity) { "FileActivity may not be null" } @@ -196,6 +199,16 @@ class FileDetailsSharingProcessFragment : themeView() } + private fun setInitialPermission() { + val permissionFlag = if (file?.isFolder == true || share?.isFolder == true) { + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + } else { + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + } + + permission = permissionFlag + } + private fun themeView() { viewThemeUtils.platform.run { binding.run { @@ -479,43 +492,15 @@ class FileDetailsSharingProcessFragment : showExpirationDateDialog() } - // region Custom Permission Checkboxes - shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, OCShare.READ_PERMISSION_FLAG) - } - - shareCreateCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, OCShare.CREATE_PERMISSION_FLAG) - } - - shareEditCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) - } - - shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, getReSharePermission()) - } - - shareCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, OCShare.SHARE_PERMISSION_FLAG) - } - - shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> - setUserPermission(isChecked, OCShare.DELETE_PERMISSION_FLAG) - } - // endregion - // region RadioButtons shareProcessPermissionRadioGroup.setOnCheckedChangeListener { radioGroup, optionId -> run { when (optionId) { R.id.view_only_radio_button -> { - val isChecked = viewOnlyRadioButton.isChecked customPermissionLayout.visibility = View.GONE - setUserPermission(isChecked, OCShare.READ_PERMISSION_FLAG) + togglePermission(OCShare.READ_PERMISSION_FLAG) } R.id.editing_radio_button -> { - val isChecked = editingRadioButton.isChecked customPermissionLayout.visibility = View.GONE val permissionFlag = if (file?.isFolder == true || share?.isFolder == true) { @@ -524,11 +509,10 @@ class FileDetailsSharingProcessFragment : OCShare.MAXIMUM_PERMISSIONS_FOR_FILE } - setUserPermission(isChecked, permissionFlag) + togglePermission(permissionFlag) } R.id.file_drop_radio_button -> { - val isChecked = fileDropRadioButton.isChecked - setUserPermission(isChecked, OCShare.CREATE_PERMISSION_FLAG) + togglePermission(OCShare.CREATE_PERMISSION_FLAG) } R.id.custom_permission_radio_button -> { val isChecked = customPermissionRadioButton.isChecked @@ -541,12 +525,8 @@ class FileDetailsSharingProcessFragment : } } - private fun setUserPermission(isChecked: Boolean, permissionFlag: Int) { - permission = if (isChecked) { - permission or permissionFlag - } else { - permission and permissionFlag.inv() - } + private fun togglePermission(permissionFlag: Int) { + permission = sharePermissionManager.togglePermission(permission, permissionFlag) } private fun setCheckboxStates() { @@ -559,6 +539,36 @@ class FileDetailsSharingProcessFragment : shareCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) != 0 shareDeleteCheckbox.isChecked = (currentPermissions and OCShare.DELETE_PERMISSION_FLAG) != 0 } + + setCheckboxesListeners() + } + + private fun setCheckboxesListeners() { + binding.run { + shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> + togglePermission(OCShare.READ_PERMISSION_FLAG) + } + + shareCreateCheckbox.setOnCheckedChangeListener { _, isChecked -> + togglePermission(OCShare.CREATE_PERMISSION_FLAG) + } + + shareEditCheckbox.setOnCheckedChangeListener { _, isChecked -> + togglePermission(OCShare.UPDATE_PERMISSION_FLAG) + } + + shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> + togglePermission(getReSharePermission()) + } + + shareCheckbox.setOnCheckedChangeListener { _, isChecked -> + togglePermission(OCShare.SHARE_PERMISSION_FLAG) + } + + shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> + togglePermission(OCShare.DELETE_PERMISSION_FLAG) + } + } } private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt new file mode 100644 index 000000000000..f259342a2e90 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -0,0 +1,58 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.fragment.util + +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Companion.TAG + +class SharePermissionManager { + + fun togglePermission(permission: Int, permissionFlag: Int): Int { + Log_OC.d(TAG, "togglePermission before: $permission") + + if (!isPermissionValid(permission)) { + Log_OC.d(TAG, "permission is not valid, togglePermission cancelled") + return permission + } + + val result = if (hasPermission(permission, permissionFlag)) { + permission and permissionFlag.inv() + } else { + permission or permissionFlag + } + + Log_OC.d(TAG, "togglePermission after: $result") + + return result + } + + private fun isPermissionValid(permission: Int): Boolean { + // Must have at least READ or CREATE permission. + if (!hasPermission(permission, OCShare.READ_PERMISSION_FLAG) && + !hasPermission(permission, OCShare.CREATE_PERMISSION_FLAG) + ) { + return false + } + + // Must have READ permission if have UPDATE or DELETE. + if (!hasPermission(permission, OCShare.READ_PERMISSION_FLAG) && + (hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG) || + hasPermission(permission, OCShare.DELETE_PERMISSION_FLAG) + ) + ) { + return false + } + + return true + } + + private fun hasPermission(permission: Int, permissionFlag: Int): Boolean { + return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag + } +} From 126f40fcc3c33125a3fcd30686319eafc827c515 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 31 Mar 2025 14:54:10 +0200 Subject: [PATCH 016/110] fix setCheckboxStates Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index affab8ea4506..2285924eecb6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -533,11 +533,11 @@ class FileDetailsSharingProcessFragment : val currentPermissions = share?.permissions ?: permission binding.run { - shareReadCheckbox.isChecked = (currentPermissions and OCShare.READ_PERMISSION_FLAG) != 0 - shareCreateCheckbox.isChecked = (currentPermissions and OCShare.CREATE_PERMISSION_FLAG) != 0 - shareEditCheckbox.isChecked = (currentPermissions and OCShare.UPDATE_PERMISSION_FLAG) != 0 - shareCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) != 0 - shareDeleteCheckbox.isChecked = (currentPermissions and OCShare.DELETE_PERMISSION_FLAG) != 0 + shareReadCheckbox.isChecked = (currentPermissions and OCShare.READ_PERMISSION_FLAG) > 0 + shareCreateCheckbox.isChecked = (currentPermissions and OCShare.CREATE_PERMISSION_FLAG) > 0 + shareEditCheckbox.isChecked = (currentPermissions and OCShare.UPDATE_PERMISSION_FLAG) > 0 + shareCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) > 0 + shareDeleteCheckbox.isChecked = (currentPermissions and OCShare.DELETE_PERMISSION_FLAG) > 0 } setCheckboxesListeners() From f87a72cd88ee92dfd313d75232e9dfc0b16d1f97 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 31 Mar 2025 15:36:27 +0200 Subject: [PATCH 017/110] fix setCheckboxStates Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 36 +++++++++++++++---- .../fragment/util/SharePermissionManager.kt | 2 +- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 2285924eecb6..5600cfd79eb1 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -199,8 +199,10 @@ class FileDetailsSharingProcessFragment : themeView() } + private fun isFolder(): Boolean = file?.isFolder == true || share?.isFolder == true + private fun setInitialPermission() { - val permissionFlag = if (file?.isFolder == true || share?.isFolder == true) { + val permissionFlag = if (isFolder()) { OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER } else { OCShare.MAXIMUM_PERMISSIONS_FOR_FILE @@ -500,10 +502,11 @@ class FileDetailsSharingProcessFragment : customPermissionLayout.visibility = View.GONE togglePermission(OCShare.READ_PERMISSION_FLAG) } + R.id.editing_radio_button -> { customPermissionLayout.visibility = View.GONE - val permissionFlag = if (file?.isFolder == true || share?.isFolder == true) { + val permissionFlag = if (isFolder()) { OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER } else { OCShare.MAXIMUM_PERMISSIONS_FOR_FILE @@ -511,9 +514,11 @@ class FileDetailsSharingProcessFragment : togglePermission(permissionFlag) } + R.id.file_drop_radio_button -> { togglePermission(OCShare.CREATE_PERMISSION_FLAG) } + R.id.custom_permission_radio_button -> { val isChecked = customPermissionRadioButton.isChecked customPermissionLayout.setVisibilityWithAnimation(isChecked) @@ -533,11 +538,28 @@ class FileDetailsSharingProcessFragment : val currentPermissions = share?.permissions ?: permission binding.run { - shareReadCheckbox.isChecked = (currentPermissions and OCShare.READ_PERMISSION_FLAG) > 0 - shareCreateCheckbox.isChecked = (currentPermissions and OCShare.CREATE_PERMISSION_FLAG) > 0 - shareEditCheckbox.isChecked = (currentPermissions and OCShare.UPDATE_PERMISSION_FLAG) > 0 - shareCheckbox.isChecked = (currentPermissions and OCShare.SHARE_PERMISSION_FLAG) > 0 - shareDeleteCheckbox.isChecked = (currentPermissions and OCShare.DELETE_PERMISSION_FLAG) > 0 + if (isFolder()) { + // Only for the folder makes sense to have create permission + // so that user can create files in the shared folder + shareReadCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) + } else { + shareReadCheckbox.visibility = View.GONE + } + shareCreateCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.CREATE_PERMISSION_FLAG) + shareEditCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.UPDATE_PERMISSION_FLAG) + shareCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG) + + if (isFolder()) { + shareDeleteCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.DELETE_PERMISSION_FLAG) + } else { + shareDeleteCheckbox.isChecked = false + shareDeleteCheckbox.isEnabled = false + } } setCheckboxesListeners() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index f259342a2e90..3b26c0464e94 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -52,7 +52,7 @@ class SharePermissionManager { return true } - private fun hasPermission(permission: Int, permissionFlag: Int): Boolean { + fun hasPermission(permission: Int, permissionFlag: Int): Boolean { return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag } } From 774e90bc50ab10f3f58ffd6220333b5ce0ccab39 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 31 Mar 2025 15:40:12 +0200 Subject: [PATCH 018/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/util/SharePermissionManager.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index 3b26c0464e94..ee3abddc9c6e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -32,6 +32,7 @@ class SharePermissionManager { return result } + @Suppress("ReturnCount") private fun isPermissionValid(permission: Int): Boolean { // Must have at least READ or CREATE permission. if (!hasPermission(permission, OCShare.READ_PERMISSION_FLAG) && @@ -42,8 +43,9 @@ class SharePermissionManager { // Must have READ permission if have UPDATE or DELETE. if (!hasPermission(permission, OCShare.READ_PERMISSION_FLAG) && - (hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG) || - hasPermission(permission, OCShare.DELETE_PERMISSION_FLAG) + ( + hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG) || + hasPermission(permission, OCShare.DELETE_PERMISSION_FLAG) ) ) { return false From 3fd40ea17b86f6383732f2c2148be9b1c05d1c1f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 31 Mar 2025 16:28:59 +0200 Subject: [PATCH 019/110] add new permissions to the quick sharing bottom sheet Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 17 ++--- ...ckSharingPermissionsBottomSheetDialog.java | 44 +++++++----- .../ui/fragment/util/SharingMenuHelper.java | 70 +++++++++---------- app/src/main/res/values/attrs.xml | 6 ++ 4 files changed, 74 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 5600cfd79eb1..01e6101631ee 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -297,7 +297,7 @@ class FileDetailsSharingProcessFragment : binding.fileDropRadioButton.isChecked = true } else if (SharingMenuHelper.isReadOnly(share)) { binding.viewOnlyRadioButton.isChecked = true - } + } // TODO: shareType = share?.shareType ?: ShareType.NO_SHARED @@ -541,17 +541,15 @@ class FileDetailsSharingProcessFragment : if (isFolder()) { // Only for the folder makes sense to have create permission // so that user can create files in the shared folder - shareReadCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) + shareCreateCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.CREATE_PERMISSION_FLAG) } else { - shareReadCheckbox.visibility = View.GONE + shareCreateCheckbox.visibility = View.GONE } - shareCreateCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.CREATE_PERMISSION_FLAG) + shareReadCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) shareEditCheckbox.isChecked = sharePermissionManager.hasPermission(currentPermissions, OCShare.UPDATE_PERMISSION_FLAG) - shareCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG) if (isFolder()) { shareDeleteCheckbox.isChecked = @@ -560,6 +558,9 @@ class FileDetailsSharingProcessFragment : shareDeleteCheckbox.isChecked = false shareDeleteCheckbox.isEnabled = false } + + shareCheckbox.isChecked = + sharePermissionManager.hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG) } setCheckboxesListeners() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 820a6b0a7f22..c42aacfe7b95 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -10,6 +10,7 @@ package com.owncloud.android.ui.fragment; +import android.app.Dialog; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; @@ -31,12 +32,15 @@ import androidx.recyclerview.widget.LinearLayoutManager; import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.DELETE_PERMISSION_FLAG; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.UPDATE_PERMISSION_FLAG; /** - * File Details Quick Sharing permissions options {@link android.app.Dialog} styled as a bottom sheet for main actions. + * File Details Quick Sharing permissions options {@link Dialog} styled as a bottom sheet for main actions. */ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog { private QuickSharingPermissionsBottomSheetFragmentBinding binding; @@ -103,25 +107,27 @@ public void onDismissSheet() { * @param position */ private void handlePermissionChanged(List quickPermissionModelList, int position) { - if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string.link_share_allow_upload_and_editing)) - || quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string.link_share_editing))) { - if (ocShare.isFolder()) { - actions.onQuickPermissionChanged(ocShare, - MAXIMUM_PERMISSIONS_FOR_FOLDER); - } else { - actions.onQuickPermissionChanged(ocShare, - MAXIMUM_PERMISSIONS_FOR_FILE); - } - } else if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string - .link_share_view_only))) { - actions.onQuickPermissionChanged(ocShare, - READ_PERMISSION_FLAG); - - } else if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string - .link_share_file_drop))) { - actions.onQuickPermissionChanged(ocShare, - CREATE_PERMISSION_FLAG); + final var permissionName = quickPermissionModelList.get(position).getPermissionName(); + final var res = fileActivity.getResources(); + + int permissionFlag = 0; + if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_allow_upload_and_editing)) || permissionName.equalsIgnoreCase(res.getString(R.string.link_share_editing))) { + permissionFlag = ocShare.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : MAXIMUM_PERMISSIONS_FOR_FILE; + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_view_only))) { + permissionFlag = READ_PERMISSION_FLAG; + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_drop)) || permissionName.equalsIgnoreCase(res.getString(R.string.share_create_permission))) { + permissionFlag = CREATE_PERMISSION_FLAG; + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_edit_permission))) { + permissionFlag = UPDATE_PERMISSION_FLAG; + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_delete_permission))) { + permissionFlag = DELETE_PERMISSION_FLAG; + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_re_share_permission))) { + permissionFlag = SHARE_PERMISSION_FLAG; } + + // FIXME: Failed to update share + actions.onQuickPermissionChanged(ocShare, permissionFlag); + dismiss(); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 899ff9cd73af..65fc4cfc42d6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -12,21 +12,19 @@ package com.owncloud.android.ui.fragment.util; import android.content.Context; -import android.content.res.Resources; import android.view.MenuItem; import com.owncloud.android.R; import com.owncloud.android.lib.resources.shares.OCShare; -import java.text.SimpleDateFormat; -import java.util.Date; - import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.DELETE_PERMISSION_FLAG; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; import static com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION; import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG; import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG; +import static com.owncloud.android.lib.resources.shares.OCShare.UPDATE_PERMISSION_FLAG; /** * Helper calls for visibility logic of the sharing menu. @@ -53,38 +51,6 @@ public static void setupHideFileDownload(MenuItem menuItem, } } - /** - * sets up the password {@link MenuItem}'s title based on the fact if a password is present. - * - * @param password the password {@link MenuItem} - * @param isPasswordProtected flag is a password is present - */ - public static void setupPasswordMenuItem(MenuItem password, boolean isPasswordProtected) { - if (isPasswordProtected) { - password.setTitle(R.string.share_password_title); - } else { - password.setTitle(R.string.share_no_password_title); - } - } - - /** - * sets up the expiration date {@link MenuItem}'s title based on the fact if an expiration date is present. - * - * @param expirationDate the expiration date {@link MenuItem} - * @param expirationDateValue the expiration date - * @param res Resources to load the corresponding strings. - */ - public static void setupExpirationDateMenuItem(MenuItem expirationDate, long expirationDateValue, Resources res) { - if (expirationDateValue > 0) { - expirationDate.setTitle(res.getString( - R.string.share_expiration_date_label, - SimpleDateFormat.getDateInstance().format(new Date(expirationDateValue)) - )); - } else { - expirationDate.setTitle(R.string.share_no_expiration_date_label); - } - } - public static boolean isUploadAndEditingAllowed(OCShare share) { if (share.getPermissions() == NO_PERMISSION) { return false; @@ -119,6 +85,30 @@ public static boolean isSecureFileDrop(OCShare share) { return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } + public static boolean isCreatePermission(OCShare share) { + if (share.getPermissions() == NO_PERMISSION) { + return false; + } + + return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG; + } + + public static boolean isUpdatePermission(OCShare share) { + if (share.getPermissions() == NO_PERMISSION) { + return false; + } + + return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == UPDATE_PERMISSION_FLAG; + } + + public static boolean isDeletePermission(OCShare share) { + if (share.getPermissions() == NO_PERMISSION) { + return false; + } + + return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == DELETE_PERMISSION_FLAG; + } + public static String getPermissionName(Context context, OCShare share) { if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { return context.getResources().getString(R.string.share_permission_can_edit); @@ -147,6 +137,14 @@ public static int getPermissionCheckedItem(Context context, OCShare share, Strin return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_view_only); } else if (SharingMenuHelper.isFileDrop(share)) { return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_file_drop); + } else if (SharingMenuHelper.isCreatePermission(share)) { + return getPermissionIndexFromArray(context, permissionArray, R.string.share_create_permission); + } else if (SharingMenuHelper.isUpdatePermission(share)) { + return getPermissionIndexFromArray(context, permissionArray, R.string.share_edit_permission); + } else if (SharingMenuHelper.isDeletePermission(share)) { + return getPermissionIndexFromArray(context, permissionArray, R.string.share_delete_permission); + } else if (SharingMenuHelper.canReshare(share)) { + return getPermissionIndexFromArray(context, permissionArray, R.string.share_re_share_permission); } return 0;//default first item selected } diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 108443d3e383..446363239dcd 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -30,11 +30,17 @@ @string/link_share_view_only @string/link_share_allow_upload_and_editing @string/link_share_file_drop + @string/share_create_permission + @string/share_edit_permission + @string/share_delete_permission + @string/share_re_share_permission @string/link_share_view_only @string/link_share_editing + @string/share_edit_permission + @string/share_re_share_permission @string/sub_folder_rule_month From 1999d9210283614b7ccac84e2ac90868200bca10 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 1 Apr 2025 12:39:32 +0200 Subject: [PATCH 020/110] fix permissionFlag usage for QuickPermissionModel Signed-off-by: alperozturk --- .../adapter/QuickSharingPermissionsAdapter.kt | 20 +++---- .../FileDetailsSharingProcessFragment.kt | 1 + ...ckSharingPermissionsBottomSheetDialog.java | 23 +++---- .../ui/fragment/util/SharingMenuHelper.java | 60 +++++++++---------- 4 files changed, 45 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index 64ffa0350002..7fe50c0020cd 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -14,6 +14,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding import com.owncloud.android.datamodel.QuickPermissionModel import com.owncloud.android.utils.theme.ViewThemeUtils @@ -44,23 +46,21 @@ class QuickSharingPermissionsAdapter( itemView: View, val onPermissionChangeListener: OnPermissionChangeListener, private val viewThemeUtils: ViewThemeUtils - ) : - RecyclerView - .ViewHolder(itemView) { + ) : RecyclerView.ViewHolder(itemView) { fun bindData(quickPermissionModel: QuickPermissionModel) { - binding.tvQuickShareName.text = quickPermissionModel.permissionName - if (quickPermissionModel.isSelected) { - viewThemeUtils.platform.colorImageView(binding.tvQuickShareCheckIcon) - binding.tvQuickShareCheckIcon.visibility = View.VISIBLE - } else { - binding.tvQuickShareCheckIcon.visibility = View.INVISIBLE + binding.run { + tvQuickShareName.text = quickPermissionModel.permissionName + tvQuickShareCheckIcon.setVisibleIf(quickPermissionModel.isSelected) + if (quickPermissionModel.isSelected) { + viewThemeUtils.platform.colorImageView(tvQuickShareCheckIcon, ColorRole.PRIMARY) + } } itemView.setOnClickListener { // if user select different options then only update the permission if (!quickPermissionModel.isSelected) { - onPermissionChangeListener.onPermissionChanged(adapterPosition) + onPermissionChangeListener.onPermissionChanged(absoluteAdapterPosition) } else { // dismiss sheet on selection of same permission onPermissionChangeListener.onDismissSheet() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 01e6101631ee..b8c0f1d70303 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -546,6 +546,7 @@ class FileDetailsSharingProcessFragment : } else { shareCreateCheckbox.visibility = View.GONE } + shareReadCheckbox.isChecked = sharePermissionManager.hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) shareEditCheckbox.isChecked = diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index c42aacfe7b95..57183671f050 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -116,16 +116,15 @@ private void handlePermissionChanged(List quickPermissionM } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_view_only))) { permissionFlag = READ_PERMISSION_FLAG; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_drop)) || permissionName.equalsIgnoreCase(res.getString(R.string.share_create_permission))) { - permissionFlag = CREATE_PERMISSION_FLAG; + permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_edit_permission))) { - permissionFlag = UPDATE_PERMISSION_FLAG; + permissionFlag = UPDATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_delete_permission))) { - permissionFlag = DELETE_PERMISSION_FLAG; + permissionFlag = DELETE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_re_share_permission))) { - permissionFlag = SHARE_PERMISSION_FLAG; + permissionFlag = SHARE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } - // FIXME: Failed to update share actions.onQuickPermissionChanged(ocShare, permissionFlag); dismiss(); @@ -136,19 +135,12 @@ private void handlePermissionChanged(List quickPermissionM * @return */ private List getQuickPermissionList() { + int permissionArrayId = ocShare.isFolder() ? R.array.folder_share_permission_dialog_values : R.array.file_share_permission_dialog_values; + String[] permissionArray = fileActivity.getResources().getStringArray(permissionArrayId); - String[] permissionArray; - if (ocShare.isFolder()) { - permissionArray = - fileActivity.getResources().getStringArray(R.array.folder_share_permission_dialog_values); - } else { - permissionArray = - fileActivity.getResources().getStringArray(R.array.file_share_permission_dialog_values); - } - //get the checked item position + // get the checked item position int checkedItem = SharingMenuHelper.getPermissionCheckedItem(fileActivity, ocShare, permissionArray); - final List quickPermissionModelList = new ArrayList<>(permissionArray.length); for (int i = 0; i < permissionArray.length; i++) { QuickPermissionModel quickPermissionModel = new QuickPermissionModel(permissionArray[i], checkedItem == i); @@ -157,7 +149,6 @@ private List getQuickPermissionList() { return quickPermissionModelList; } - @Override protected void onStop() { super.onStop(); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 65fc4cfc42d6..7390c3c16edb 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -12,7 +12,6 @@ package com.owncloud.android.ui.fragment.util; import android.content.Context; -import android.view.MenuItem; import com.owncloud.android.R; import com.owncloud.android.lib.resources.shares.OCShare; @@ -35,22 +34,6 @@ private SharingMenuHelper() { // utility class -> private constructor } - /** - * Sets checked/visibility state on the given {@link MenuItem} based on the given criteria. - * - * @param menuItem the {@link MenuItem} to be setup - */ - public static void setupHideFileDownload(MenuItem menuItem, - boolean hideFileDownload, - boolean isFileDrop) { - if (isFileDrop) { - menuItem.setVisible(false); - } else { - menuItem.setVisible(true); - menuItem.setChecked(hideFileDownload); - } - } - public static boolean isUploadAndEditingAllowed(OCShare share) { if (share.getPermissions() == NO_PERMISSION) { return false; @@ -110,14 +93,24 @@ public static boolean isDeletePermission(OCShare share) { } public static String getPermissionName(Context context, OCShare share) { + final var res = context.getResources(); + if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - return context.getResources().getString(R.string.share_permission_can_edit); + return res.getString(R.string.share_permission_can_edit); } else if (SharingMenuHelper.isReadOnly(share)) { - return context.getResources().getString(R.string.share_permission_view_only); + return res.getString(R.string.share_permission_view_only); } else if (SharingMenuHelper.isSecureFileDrop(share)) { - return context.getResources().getString(R.string.share_permission_secure_file_drop); + return res.getString(R.string.share_permission_secure_file_drop); } else if (SharingMenuHelper.isFileDrop(share)) { - return context.getResources().getString(R.string.share_permission_file_drop); + return res.getString(R.string.share_permission_file_drop); + } else if (SharingMenuHelper.isCreatePermission(share)) { + return res.getString(R.string.share_create_permission); + } else if (SharingMenuHelper.isUpdatePermission(share)) { + return res.getString(R.string.share_edit_permission); + } else if (SharingMenuHelper.isDeletePermission(share)) { + return res.getString(R.string.share_delete_permission); + } else if (SharingMenuHelper.canReshare(share)) { + return res.getString(R.string.share_re_share_permission); } return null; } @@ -127,26 +120,27 @@ public static String getPermissionName(Context context, OCShare share) { * */ public static int getPermissionCheckedItem(Context context, OCShare share, String[] permissionArray) { + int permissionName; + if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - if (share.isFolder()) { - return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_allow_upload_and_editing); - } else { - return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_editing); - } + permissionName = share.isFolder() ? R.string.link_share_allow_upload_and_editing : R.string.link_share_editing; } else if (SharingMenuHelper.isReadOnly(share)) { - return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_view_only); + permissionName = R.string.link_share_view_only; } else if (SharingMenuHelper.isFileDrop(share)) { - return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_file_drop); + permissionName = R.string.link_share_file_drop; } else if (SharingMenuHelper.isCreatePermission(share)) { - return getPermissionIndexFromArray(context, permissionArray, R.string.share_create_permission); + permissionName = R.string.share_create_permission; } else if (SharingMenuHelper.isUpdatePermission(share)) { - return getPermissionIndexFromArray(context, permissionArray, R.string.share_edit_permission); + permissionName = R.string.share_edit_permission; } else if (SharingMenuHelper.isDeletePermission(share)) { - return getPermissionIndexFromArray(context, permissionArray, R.string.share_delete_permission); + permissionName = R.string.share_delete_permission; } else if (SharingMenuHelper.canReshare(share)) { - return getPermissionIndexFromArray(context, permissionArray, R.string.share_re_share_permission); + permissionName = R.string.share_re_share_permission; + } else { + return 0; } - return 0;//default first item selected + + return getPermissionIndexFromArray(context, permissionArray, permissionName); } private static int getPermissionIndexFromArray(Context context, String[] permissionArray, int permissionName) { From ae6c9249362c8337d464a1ba0b9eecdd6e94bd4d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 1 Apr 2025 14:19:35 +0200 Subject: [PATCH 021/110] add custom permissions to bottom sheet Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragment.java | 5 ++ .../FileDetailsSharingProcessFragment.kt | 15 ++++-- ...ckSharingPermissionsBottomSheetDialog.java | 13 +++-- .../fragment/util/SharePermissionManager.kt | 19 +++++++ .../ui/fragment/util/SharingMenuHelper.java | 53 ++++--------------- app/src/main/res/values/attrs.xml | 8 +-- 6 files changed, 53 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 1d6b78a4361a..b3d58cfec44d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -691,6 +691,11 @@ public void onQuickPermissionChanged(OCShare share, int permission) { fileOperationsHelper.setPermissionsToShare(share, permission); } + @Override + public void openShareDetails(OCShare share) { + modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_CUSTOM_PERMISSION); + } + //launcher for contact permission private final ActivityResultLauncher requestContactPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index b8c0f1d70303..6e1f804580a6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -71,6 +71,8 @@ class FileDetailsSharingProcessFragment : // types of screens to be displayed const val SCREEN_TYPE_PERMISSION = 1 // permissions screen const val SCREEN_TYPE_NOTE = 2 // note screen + const val SCREEN_TYPE_CUSTOM_PERMISSION = 3 // custom permissions screen + /** * fragment instance to be called while creating new share for internal and external share @@ -189,7 +191,11 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (shareProcessStep == SCREEN_TYPE_PERMISSION) { + if (shareProcessStep == SCREEN_TYPE_PERMISSION || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { + if (shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { + binding.customPermissionRadioButton.isChecked = true + } + showShareProcessFirst() } else { showShareProcessSecond() @@ -290,8 +296,11 @@ class FileDetailsSharingProcessFragment : private fun setupModificationUI() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() - // read only / allow upload and editing / file drop - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + // custom permissions / read only / allow upload and editing / file drop + if (sharePermissionManager.isCustomPermission(share)) { + binding.customPermissionRadioButton.isChecked = true + binding.customPermissionLayout.setVisibilityWithAnimation(true) + } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { binding.editingRadioButton.isChecked = true } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { binding.fileDropRadioButton.isChecked = true diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 57183671f050..88cf4ec06bce 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -115,14 +115,12 @@ private void handlePermissionChanged(List quickPermissionM permissionFlag = ocShare.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : MAXIMUM_PERMISSIONS_FOR_FILE; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_view_only))) { permissionFlag = READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_drop)) || permissionName.equalsIgnoreCase(res.getString(R.string.share_create_permission))) { + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_drop))) { permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_edit_permission))) { - permissionFlag = UPDATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_delete_permission))) { - permissionFlag = DELETE_PERMISSION_FLAG + READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_re_share_permission))) { - permissionFlag = SHARE_PERMISSION_FLAG + READ_PERMISSION_FLAG; + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_custom_permission))) { + dismiss(); + actions.openShareDetails(ocShare); + return; } actions.onQuickPermissionChanged(ocShare, permissionFlag); @@ -157,5 +155,6 @@ protected void onStop() { public interface QuickPermissionSharingBottomSheetActions { void onQuickPermissionChanged(OCShare share, int permission); + void openShareDetails(OCShare share); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index ee3abddc9c6e..8b8aeb0445cc 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -57,4 +57,23 @@ class SharePermissionManager { fun hasPermission(permission: Int, permissionFlag: Int): Boolean { return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag } + + fun isCustomPermission(share: OCShare?): Boolean { + if (share == null) return false + val permissions = share.permissions + if (permissions == OCShare.NO_PERMISSION) return false + + val hasRead = hasPermission(permissions, OCShare.READ_PERMISSION_FLAG) + if (!hasRead) return false + + val hasCreate = hasPermission(permissions, OCShare.CREATE_PERMISSION_FLAG) + val hasUpdate = hasPermission(permissions, OCShare.UPDATE_PERMISSION_FLAG) + val hasDelete = hasPermission(permissions, OCShare.DELETE_PERMISSION_FLAG) + val hasShare = hasPermission(permissions, OCShare.SHARE_PERMISSION_FLAG) + + return when { + share.isFolder -> hasCreate || hasUpdate || hasDelete || hasShare + else -> hasUpdate || hasShare || hasDelete + } + } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 7390c3c16edb..cc60d9ff028b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -17,19 +17,19 @@ import com.owncloud.android.lib.resources.shares.OCShare; import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.DELETE_PERMISSION_FLAG; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; import static com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION; import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG; import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.UPDATE_PERMISSION_FLAG; /** * Helper calls for visibility logic of the sharing menu. */ public final class SharingMenuHelper { + private static final SharePermissionManager sharePermissionManager = new SharePermissionManager(); + private SharingMenuHelper() { // utility class -> private constructor } @@ -68,34 +68,12 @@ public static boolean isSecureFileDrop(OCShare share) { return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } - public static boolean isCreatePermission(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG; - } - - public static boolean isUpdatePermission(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == UPDATE_PERMISSION_FLAG; - } - - public static boolean isDeletePermission(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == DELETE_PERMISSION_FLAG; - } - public static String getPermissionName(Context context, OCShare share) { final var res = context.getResources(); - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + if (sharePermissionManager.isCustomPermission(share)) { + return res.getString(R.string.share_custom_permission); + } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { return res.getString(R.string.share_permission_can_edit); } else if (SharingMenuHelper.isReadOnly(share)) { return res.getString(R.string.share_permission_view_only); @@ -103,15 +81,8 @@ public static String getPermissionName(Context context, OCShare share) { return res.getString(R.string.share_permission_secure_file_drop); } else if (SharingMenuHelper.isFileDrop(share)) { return res.getString(R.string.share_permission_file_drop); - } else if (SharingMenuHelper.isCreatePermission(share)) { - return res.getString(R.string.share_create_permission); - } else if (SharingMenuHelper.isUpdatePermission(share)) { - return res.getString(R.string.share_edit_permission); - } else if (SharingMenuHelper.isDeletePermission(share)) { - return res.getString(R.string.share_delete_permission); - } else if (SharingMenuHelper.canReshare(share)) { - return res.getString(R.string.share_re_share_permission); } + return null; } @@ -122,20 +93,14 @@ public static String getPermissionName(Context context, OCShare share) { public static int getPermissionCheckedItem(Context context, OCShare share, String[] permissionArray) { int permissionName; - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + if (sharePermissionManager.isCustomPermission(share)) { + permissionName = R.string.share_custom_permission; + } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { permissionName = share.isFolder() ? R.string.link_share_allow_upload_and_editing : R.string.link_share_editing; } else if (SharingMenuHelper.isReadOnly(share)) { permissionName = R.string.link_share_view_only; } else if (SharingMenuHelper.isFileDrop(share)) { permissionName = R.string.link_share_file_drop; - } else if (SharingMenuHelper.isCreatePermission(share)) { - permissionName = R.string.share_create_permission; - } else if (SharingMenuHelper.isUpdatePermission(share)) { - permissionName = R.string.share_edit_permission; - } else if (SharingMenuHelper.isDeletePermission(share)) { - permissionName = R.string.share_delete_permission; - } else if (SharingMenuHelper.canReshare(share)) { - permissionName = R.string.share_re_share_permission; } else { return 0; } diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 446363239dcd..d86cd0664f7f 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -30,17 +30,13 @@ @string/link_share_view_only @string/link_share_allow_upload_and_editing @string/link_share_file_drop - @string/share_create_permission - @string/share_edit_permission - @string/share_delete_permission - @string/share_re_share_permission + @string/share_custom_permission @string/link_share_view_only @string/link_share_editing - @string/share_edit_permission - @string/share_re_share_permission + @string/share_custom_permission @string/sub_folder_rule_month From 76d575bcbcb7880cc74063da5389bc6aae9f29c6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 1 Apr 2025 14:23:25 +0200 Subject: [PATCH 022/110] add custom permissions to bottom sheet Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragment.java | 4 +-- .../FileDetailsSharingProcessFragment.kt | 30 ++++++++----------- ...ckSharingPermissionsBottomSheetDialog.java | 7 ++--- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index b3d58cfec44d..b8c5640998e6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -692,8 +692,8 @@ public void onQuickPermissionChanged(OCShare share, int permission) { } @Override - public void openShareDetails(OCShare share) { - modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_CUSTOM_PERMISSION); + public void openShareDetail(OCShare share) { + modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION); } //launcher for contact permission diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 6e1f804580a6..dbec7d8128b6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -71,8 +71,6 @@ class FileDetailsSharingProcessFragment : // types of screens to be displayed const val SCREEN_TYPE_PERMISSION = 1 // permissions screen const val SCREEN_TYPE_NOTE = 2 // note screen - const val SCREEN_TYPE_CUSTOM_PERMISSION = 3 // custom permissions screen - /** * fragment instance to be called while creating new share for internal and external share @@ -191,11 +189,7 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (shareProcessStep == SCREEN_TYPE_PERMISSION || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { - if (shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { - binding.customPermissionRadioButton.isChecked = true - } - + if (shareProcessStep == SCREEN_TYPE_PERMISSION) { showShareProcessFirst() } else { showShareProcessSecond() @@ -297,16 +291,18 @@ class FileDetailsSharingProcessFragment : if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() // custom permissions / read only / allow upload and editing / file drop - if (sharePermissionManager.isCustomPermission(share)) { - binding.customPermissionRadioButton.isChecked = true - binding.customPermissionLayout.setVisibilityWithAnimation(true) - } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - binding.editingRadioButton.isChecked = true - } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { - binding.fileDropRadioButton.isChecked = true - } else if (SharingMenuHelper.isReadOnly(share)) { - binding.viewOnlyRadioButton.isChecked = true - } // TODO: + binding.run { + if (sharePermissionManager.isCustomPermission(share)) { + customPermissionRadioButton.isChecked = true + customPermissionLayout.setVisibilityWithAnimation(true) + } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + editingRadioButton.isChecked = true + } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { + fileDropRadioButton.isChecked = true + } else if (SharingMenuHelper.isReadOnly(share)) { + viewOnlyRadioButton.isChecked = true + } + } shareType = share?.shareType ?: ShareType.NO_SHARED diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 88cf4ec06bce..ccab5d021363 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -32,12 +32,9 @@ import androidx.recyclerview.widget.LinearLayoutManager; import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.DELETE_PERMISSION_FLAG; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.UPDATE_PERMISSION_FLAG; /** * File Details Quick Sharing permissions options {@link Dialog} styled as a bottom sheet for main actions. @@ -119,7 +116,7 @@ private void handlePermissionChanged(List quickPermissionM permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_custom_permission))) { dismiss(); - actions.openShareDetails(ocShare); + actions.openShareDetail(ocShare); return; } @@ -155,6 +152,6 @@ protected void onStop() { public interface QuickPermissionSharingBottomSheetActions { void onQuickPermissionChanged(OCShare share, int permission); - void openShareDetails(OCShare share); + void openShareDetail(OCShare share); } } From 0483484cf4c9502b9ffbb8ffd20d3fb83d06d197 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 1 Apr 2025 15:01:15 +0200 Subject: [PATCH 023/110] add custom permissions to bottom sheet Signed-off-by: alperozturk --- .../owncloud/android/ui/fragment/util/SharePermissionManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index 8b8aeb0445cc..e8d7abdc1c07 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -73,7 +73,7 @@ class SharePermissionManager { return when { share.isFolder -> hasCreate || hasUpdate || hasDelete || hasShare - else -> hasUpdate || hasShare || hasDelete + else -> hasUpdate || hasShare } } } From c24a5b527944dbbb424e2fac2a178a05ed88dc57 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 1 Apr 2025 16:29:58 +0200 Subject: [PATCH 024/110] fix order Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 8 ++++---- .../android/ui/fragment/util/SharingMenuHelper.java | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index dbec7d8128b6..08476ec8af53 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -292,15 +292,15 @@ class FileDetailsSharingProcessFragment : // custom permissions / read only / allow upload and editing / file drop binding.run { - if (sharePermissionManager.isCustomPermission(share)) { - customPermissionRadioButton.isChecked = true - customPermissionLayout.setVisibilityWithAnimation(true) - } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { editingRadioButton.isChecked = true } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { fileDropRadioButton.isChecked = true } else if (SharingMenuHelper.isReadOnly(share)) { viewOnlyRadioButton.isChecked = true + } else if (sharePermissionManager.isCustomPermission(share)) { + customPermissionRadioButton.isChecked = true + customPermissionLayout.setVisibilityWithAnimation(true) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index cc60d9ff028b..09d3f9bd87a9 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -71,9 +71,7 @@ public static boolean isSecureFileDrop(OCShare share) { public static String getPermissionName(Context context, OCShare share) { final var res = context.getResources(); - if (sharePermissionManager.isCustomPermission(share)) { - return res.getString(R.string.share_custom_permission); - } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { return res.getString(R.string.share_permission_can_edit); } else if (SharingMenuHelper.isReadOnly(share)) { return res.getString(R.string.share_permission_view_only); @@ -81,6 +79,8 @@ public static String getPermissionName(Context context, OCShare share) { return res.getString(R.string.share_permission_secure_file_drop); } else if (SharingMenuHelper.isFileDrop(share)) { return res.getString(R.string.share_permission_file_drop); + } else if (sharePermissionManager.isCustomPermission(share)) { + return res.getString(R.string.share_custom_permission); } return null; @@ -93,14 +93,14 @@ public static String getPermissionName(Context context, OCShare share) { public static int getPermissionCheckedItem(Context context, OCShare share, String[] permissionArray) { int permissionName; - if (sharePermissionManager.isCustomPermission(share)) { - permissionName = R.string.share_custom_permission; - } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { permissionName = share.isFolder() ? R.string.link_share_allow_upload_and_editing : R.string.link_share_editing; } else if (SharingMenuHelper.isReadOnly(share)) { permissionName = R.string.link_share_view_only; } else if (SharingMenuHelper.isFileDrop(share)) { permissionName = R.string.link_share_file_drop; + } else if (sharePermissionManager.isCustomPermission(share)) { + permissionName = R.string.share_custom_permission; } else { return 0; } From 63d6ae3f24ca7b2242f0d6257aa8c522f07eecf5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 1 Apr 2025 17:01:56 +0200 Subject: [PATCH 025/110] fix order Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailSharingFragment.java | 2 +- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index b8c5640998e6..d5449ee2e445 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -693,7 +693,7 @@ public void onQuickPermissionChanged(OCShare share, int permission) { @Override public void openShareDetail(OCShare share) { - modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION); + modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_CUSTOM_PERMISSION); } //launcher for contact permission diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 08476ec8af53..d4e0bdbe8ff0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -71,6 +71,7 @@ class FileDetailsSharingProcessFragment : // types of screens to be displayed const val SCREEN_TYPE_PERMISSION = 1 // permissions screen const val SCREEN_TYPE_NOTE = 2 // note screen + const val SCREEN_TYPE_CUSTOM_PERMISSION = 3 // custom permissions screen /** * fragment instance to be called while creating new share for internal and external share @@ -189,11 +190,12 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (shareProcessStep == SCREEN_TYPE_PERMISSION) { + if (shareProcessStep == SCREEN_TYPE_PERMISSION || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { showShareProcessFirst() } else { showShareProcessSecond() } + implementClickEvents() setCheckboxStates() themeView() @@ -298,7 +300,11 @@ class FileDetailsSharingProcessFragment : fileDropRadioButton.isChecked = true } else if (SharingMenuHelper.isReadOnly(share)) { viewOnlyRadioButton.isChecked = true - } else if (sharePermissionManager.isCustomPermission(share)) { + } + + if (sharePermissionManager.isCustomPermission(share) || + shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) + { customPermissionRadioButton.isChecked = true customPermissionLayout.setVisibilityWithAnimation(true) } From 49fd4710585ce0676eb7cc093487ebefa84bce68 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 09:20:27 +0200 Subject: [PATCH 026/110] fix onCustomPermissionSelected Signed-off-by: alperozturk --- .../ui/adapter/QuickSharingPermissionsAdapter.kt | 12 ++++++++++-- .../QuickSharingPermissionsBottomSheetDialog.java | 10 ++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index 7fe50c0020cd..dea7938ca09f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -16,6 +16,7 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.utils.extensions.setVisibleIf +import com.owncloud.android.R import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding import com.owncloud.android.datamodel.QuickPermissionModel import com.owncloud.android.utils.theme.ViewThemeUtils @@ -57,9 +58,15 @@ class QuickSharingPermissionsAdapter( } } + val customPermissionName = itemView.context.getString(R.string.share_custom_permission) + val permissionName = quickPermissionModel.permissionName + val isCustomPermission = permissionName.equals(customPermissionName, ignoreCase = true) + itemView.setOnClickListener { - // if user select different options then only update the permission - if (!quickPermissionModel.isSelected) { + if (isCustomPermission) { + onPermissionChangeListener.onCustomPermissionSelected() + } else if (!quickPermissionModel.isSelected) { + // if user select different options then only update the permission onPermissionChangeListener.onPermissionChanged(absoluteAdapterPosition) } else { // dismiss sheet on selection of same permission @@ -70,6 +77,7 @@ class QuickSharingPermissionsAdapter( interface OnPermissionChangeListener { fun onPermissionChanged(position: Int) + fun onCustomPermissionSelected() fun onDismissSheet() } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index ccab5d021363..3d7bf169d790 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -81,6 +81,12 @@ private void setUpRecyclerView() { QuickSharingPermissionsAdapter adapter = new QuickSharingPermissionsAdapter( quickPermissionModelList, new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() { + @Override + public void onCustomPermissionSelected() { + dismiss(); + actions.openShareDetail(ocShare); + } + @Override public void onPermissionChanged(int position) { handlePermissionChanged(quickPermissionModelList, position); @@ -114,10 +120,6 @@ private void handlePermissionChanged(List quickPermissionM permissionFlag = READ_PERMISSION_FLAG; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_drop))) { permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_custom_permission))) { - dismiss(); - actions.openShareDetail(ocShare); - return; } actions.onQuickPermissionChanged(ocShare, permissionFlag); From a320b36da014c864d2336326c88a0dc864b4a727 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 09:25:54 +0200 Subject: [PATCH 027/110] fix radio button isChecked logic Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index d4e0bdbe8ff0..5943310e9fd1 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -294,19 +294,17 @@ class FileDetailsSharingProcessFragment : // custom permissions / read only / allow upload and editing / file drop binding.run { - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - editingRadioButton.isChecked = true - } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { - fileDropRadioButton.isChecked = true - } else if (SharingMenuHelper.isReadOnly(share)) { - viewOnlyRadioButton.isChecked = true - } - - if (sharePermissionManager.isCustomPermission(share) || - shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) - { - customPermissionRadioButton.isChecked = true - customPermissionLayout.setVisibilityWithAnimation(true) + when { + SharingMenuHelper.isUploadAndEditingAllowed(share) -> editingRadioButton.isChecked = true + SharingMenuHelper.isFileDrop(share) && share?.isFolder == true -> fileDropRadioButton.isChecked = true + SharingMenuHelper.isReadOnly(share) -> viewOnlyRadioButton.isChecked = true + else -> { + if (sharePermissionManager.isCustomPermission(share) || + shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { + customPermissionRadioButton.isChecked = true + customPermissionLayout.setVisibilityWithAnimation(true) + } + } } } From 5d59e1e63077db142a63c4ed29a8af9c885f1d19 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 09:26:21 +0200 Subject: [PATCH 028/110] remove unused character Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 5943310e9fd1..41a0e32bbbe5 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -148,7 +148,7 @@ class FileDetailsSharingProcessFragment : super.onAttach(context) try { onEditShareListener = context as FileDetailSharingFragment.OnEditShareListener - } catch (e: ClassCastException) { + } catch (_: ClassCastException) { throw IllegalStateException("Calling activity must implement the interface") } } From 799ed48e0d280e9e494003d45c60f3d364c67c77 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 10:42:25 +0200 Subject: [PATCH 029/110] fix radio button setOnCheckedChangeListener logic Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 41a0e32bbbe5..7bd7134d7be1 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -175,7 +175,7 @@ class FileDetailsSharingProcessFragment : fileActivity = activity as FileActivity? capabilities = CapabilityUtils.getCapability(context) - setInitialPermission() + permission = getMaximumPermission() requireNotNull(fileActivity) { "FileActivity may not be null" } @@ -203,14 +203,12 @@ class FileDetailsSharingProcessFragment : private fun isFolder(): Boolean = file?.isFolder == true || share?.isFolder == true - private fun setInitialPermission() { - val permissionFlag = if (isFolder()) { + private fun getMaximumPermission(): Int { + return if (isFolder()) { OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER } else { OCShare.MAXIMUM_PERMISSIONS_FOR_FILE } - - permission = permissionFlag } private fun themeView() { @@ -509,23 +507,16 @@ class FileDetailsSharingProcessFragment : when (optionId) { R.id.view_only_radio_button -> { customPermissionLayout.visibility = View.GONE - togglePermission(OCShare.READ_PERMISSION_FLAG) + permission = OCShare.READ_PERMISSION_FLAG } R.id.editing_radio_button -> { customPermissionLayout.visibility = View.GONE - - val permissionFlag = if (isFolder()) { - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER - } else { - OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - } - - togglePermission(permissionFlag) + permission = getMaximumPermission() } R.id.file_drop_radio_button -> { - togglePermission(OCShare.CREATE_PERMISSION_FLAG) + permission = OCShare.CREATE_PERMISSION_FLAG } R.id.custom_permission_radio_button -> { From 5f85f840e8f82b8186a9cf66b99192f6a39fea18 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 10:50:02 +0200 Subject: [PATCH 030/110] fix allow re-share logic Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 21 +++---------------- .../fragment/util/SharePermissionManager.kt | 15 +++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 7bd7134d7be1..484d0eb84319 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -27,7 +27,6 @@ import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.resources.shares.OCShare -import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.ui.activity.FileActivity @@ -175,7 +174,7 @@ class FileDetailsSharingProcessFragment : fileActivity = activity as FileActivity? capabilities = CapabilityUtils.getCapability(context) - permission = getMaximumPermission() + permission = sharePermissionManager.getMaximumPermission(isFolder()) requireNotNull(fileActivity) { "FileActivity may not be null" } @@ -203,14 +202,6 @@ class FileDetailsSharingProcessFragment : private fun isFolder(): Boolean = file?.isFolder == true || share?.isFolder == true - private fun getMaximumPermission(): Int { - return if (isFolder()) { - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER - } else { - OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - } - } - private fun themeView() { viewThemeUtils.platform.run { binding.run { @@ -512,7 +503,7 @@ class FileDetailsSharingProcessFragment : R.id.editing_radio_button -> { customPermissionLayout.visibility = View.GONE - permission = getMaximumPermission() + permission = sharePermissionManager.getMaximumPermission(isFolder()) } R.id.file_drop_radio_button -> { @@ -582,7 +573,7 @@ class FileDetailsSharingProcessFragment : } shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(getReSharePermission()) + permission = sharePermissionManager.getReSharePermission() } shareCheckbox.setOnCheckedChangeListener { _, isChecked -> @@ -665,12 +656,6 @@ class FileDetailsSharingProcessFragment : fileActivity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit() } - private fun getReSharePermission(): Int { - return SharePermissionsBuilder().apply { - setSharePermission(true) - }.build() - } - /** * method to validate the step 1 screen information */ diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index e8d7abdc1c07..f42265eaea28 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -9,6 +9,7 @@ package com.owncloud.android.ui.fragment.util import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Companion.TAG class SharePermissionManager { @@ -76,4 +77,18 @@ class SharePermissionManager { else -> hasUpdate || hasShare } } + + fun getReSharePermission(): Int { + return SharePermissionsBuilder().apply { + setSharePermission(true) + }.build() + } + + fun getMaximumPermission(isFolder: Boolean): Int { + return if (isFolder) { + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + } else { + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + } + } } From a18a7b9bd3737c7302d21e1b2db8974871c81049 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 11:19:17 +0200 Subject: [PATCH 031/110] reduce lint Signed-off-by: alperozturk --- app/src/main/res/values/strings.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 33a372111292..f31246f3c478 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -616,12 +616,10 @@ Sharing Share %1$s - Expires %1$s %1$s Set expiration date Share link Send link - Password-protected Set password Share with… Unset From 8460c90350b857577eb18b7a920a884a07c4fa0b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 11:55:53 +0200 Subject: [PATCH 032/110] create share with one click Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 484d0eb84319..f014da731f41 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -461,6 +461,7 @@ class FileDetailsSharingProcessFragment : binding.noteText.setText(R.string.empty) } shareProcessStep = SCREEN_TYPE_NOTE + binding.shareProcessBtnNext.performClick() } @Suppress("LongMethod") From 53dc81d9209ad302a53f15215b370b8866c712d0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 12:06:13 +0200 Subject: [PATCH 033/110] add setup view region Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 129 +++++++++--------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index f014da731f41..932e3a8fcc3e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -192,7 +192,7 @@ class FileDetailsSharingProcessFragment : if (shareProcessStep == SCREEN_TYPE_PERMISSION || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { showShareProcessFirst() } else { - showShareProcessSecond() + updateViewForNoteScreenType() } implementClickEvents() @@ -333,6 +333,7 @@ class FileDetailsSharingProcessFragment : showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) } + // region ViewUpdates private fun updateViewForShareType() { when (shareType) { ShareType.EMAIL -> { @@ -384,20 +385,19 @@ class FileDetailsSharingProcessFragment : } } - /** - * update views where share type external or link share - */ private fun updateViewForExternalAndLinkShare() { - binding.shareProcessHideDownloadCheckbox.visibility = View.VISIBLE - binding.shareProcessAllowResharingCheckbox.visibility = View.GONE - binding.shareProcessSetPasswordSwitch.visibility = View.VISIBLE + binding.run { + shareProcessHideDownloadCheckbox.visibility = View.VISIBLE + shareProcessAllowResharingCheckbox.visibility = View.GONE + shareProcessSetPasswordSwitch.visibility = View.VISIBLE - if (share != null) { - if (SharingMenuHelper.isFileDrop(share)) { - binding.shareProcessHideDownloadCheckbox.visibility = View.GONE - } else { - binding.shareProcessHideDownloadCheckbox.visibility = View.VISIBLE - binding.shareProcessHideDownloadCheckbox.isChecked = share?.isHideFileDownload == true + if (share != null) { + if (SharingMenuHelper.isFileDrop(share)) { + shareProcessHideDownloadCheckbox.visibility = View.GONE + } else { + shareProcessHideDownloadCheckbox.visibility = View.VISIBLE + shareProcessHideDownloadCheckbox.isChecked = share?.isHideFileDownload == true + } } } } @@ -432,37 +432,41 @@ class FileDetailsSharingProcessFragment : } private fun updateViewForFile() { - binding.editingRadioButton.text = getString(R.string.link_share_editing) - binding.fileDropRadioButton.visibility = View.GONE + binding.run { + editingRadioButton.text = getString(R.string.link_share_editing) + fileDropRadioButton.visibility = View.GONE + } } private fun updateViewForFolder() { - binding.editingRadioButton.text = getString(R.string.link_share_allow_upload_and_editing) - binding.fileDropRadioButton.visibility = View.VISIBLE - if (isSecureShare) { - binding.fileDropRadioButton.visibility = View.GONE - binding.shareProcessAllowResharingCheckbox.visibility = View.GONE - binding.shareProcessSetExpDateSwitch.visibility = View.GONE + binding.run { + editingRadioButton.text = getString(R.string.link_share_allow_upload_and_editing) + fileDropRadioButton.visibility = View.VISIBLE + if (isSecureShare) { + fileDropRadioButton.visibility = View.GONE + shareProcessAllowResharingCheckbox.visibility = View.GONE + shareProcessSetExpDateSwitch.visibility = View.GONE + } } } - /** - * update views for screen type Note - */ - private fun showShareProcessSecond() { - binding.shareProcessGroupOne.visibility = View.GONE - binding.shareProcessEditShareLink.visibility = View.GONE - binding.shareProcessGroupTwo.visibility = View.VISIBLE - if (share != null) { - binding.shareProcessBtnNext.text = getString(R.string.set_note) - binding.noteText.setText(share?.note) - } else { - binding.shareProcessBtnNext.text = getString(R.string.send_share) - binding.noteText.setText(R.string.empty) + private fun updateViewForNoteScreenType() { + binding.run { + shareProcessGroupOne.visibility = View.GONE + shareProcessEditShareLink.visibility = View.GONE + shareProcessGroupTwo.visibility = View.VISIBLE + if (share != null) { + shareProcessBtnNext.text = getString(R.string.set_note) + noteText.setText(share?.note) + } else { + shareProcessBtnNext.text = getString(R.string.send_share) + noteText.setText(R.string.empty) + } + shareProcessStep = SCREEN_TYPE_NOTE + shareProcessBtnNext.performClick() } - shareProcessStep = SCREEN_TYPE_NOTE - binding.shareProcessBtnNext.performClick() } + // endregion @Suppress("LongMethod") private fun implementClickEvents() { @@ -474,7 +478,7 @@ class FileDetailsSharingProcessFragment : if (shareProcessStep == SCREEN_TYPE_PERMISSION) { validateShareProcessFirst() } else { - validateShareProcessSecond() + createOrUpdateShare() } } shareProcessSetPasswordSwitch.setOnCheckedChangeListener { _, isChecked -> @@ -694,8 +698,19 @@ class FileDetailsSharingProcessFragment : removeCurrentFragment() } else { // else show step 2 (note screen) - showShareProcessSecond() + updateViewForNoteScreenType() + } + } + + private fun createOrUpdateShare() { + val noteText = binding.noteText.text.toString().trim() + // if modifying existing share then directly update the note and send email + if (share != null && share?.note != noteText) { + fileOperationsHelper?.updateNoteToShare(share, noteText) + } else { + createShare(noteText) } + removeCurrentFragment() } private fun updateShare() { @@ -726,31 +741,19 @@ class FileDetailsSharingProcessFragment : } } - /** - * method to validate step 2 (note screen) information - */ - private fun validateShareProcessSecond() { - val noteText = binding.noteText.text.toString().trim() - // if modifying existing share then directly update the note and send email - if (share != null && share?.note != noteText) { - fileOperationsHelper?.updateNoteToShare(share, noteText) - } else { - // else create new share - fileOperationsHelper?.shareFileWithSharee( - file, - shareeName, - shareType, - permission, - binding - .shareProcessHideDownloadCheckbox.isChecked, - binding.shareProcessEnterPassword.text.toString().trim(), - chosenExpDateInMills, - noteText, - binding.shareProcessChangeName.text.toString().trim(), - true - ) - } - removeCurrentFragment() + private fun createShare(noteText: String) { + fileOperationsHelper?.shareFileWithSharee( + file, + shareeName, + shareType, + permission, + binding.shareProcessHideDownloadCheckbox.isChecked, + binding.shareProcessEnterPassword.text.toString().trim(), + chosenExpDateInMills, + noteText, + binding.shareProcessChangeName.text.toString().trim(), + true + ) } /** From 19fe4f550cdd3da446e19d3b8a955c544bebf0e3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 12:07:08 +0200 Subject: [PATCH 034/110] clearer function name Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 932e3a8fcc3e..cbcd541f31a3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -478,7 +478,7 @@ class FileDetailsSharingProcessFragment : if (shareProcessStep == SCREEN_TYPE_PERMISSION) { validateShareProcessFirst() } else { - createOrUpdateShare() + createShareOrUpdateNoteShare() } } shareProcessSetPasswordSwitch.setOnCheckedChangeListener { _, isChecked -> @@ -702,7 +702,7 @@ class FileDetailsSharingProcessFragment : } } - private fun createOrUpdateShare() { + private fun createShareOrUpdateNoteShare() { val noteText = binding.noteText.text.toString().trim() // if modifying existing share then directly update the note and send email if (share != null && share?.note != noteText) { From b94504630f2131a319307395019b4891f69358c0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 12:52:58 +0200 Subject: [PATCH 035/110] remove unnecessary allow reshare checkbox Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 24 ++++--------------- .../fragment/util/SharePermissionManager.kt | 7 ------ .../file_details_sharing_process_fragment.xml | 18 -------------- app/src/main/res/values/strings.xml | 1 - 4 files changed, 5 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index cbcd541f31a3..da1d19fb0278 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -218,8 +218,6 @@ class FileDetailsSharingProcessFragment : themeCheckbox(shareEditCheckbox) themeCheckbox(shareCheckbox) themeCheckbox(shareDeleteCheckbox) - - themeCheckbox(shareProcessAllowResharingCheckbox) } } @@ -269,10 +267,6 @@ class FileDetailsSharingProcessFragment : setupUpdateUI() } - if (isSecureShare) { - binding.shareProcessAdvancePermissionTitle.visibility = View.GONE - } - // show or hide expiry date binding.shareProcessSetExpDateSwitch.setVisibleIf(isExpDateShown && !isSecureShare) shareProcessStep = SCREEN_TYPE_PERMISSION @@ -370,25 +364,21 @@ class FileDetailsSharingProcessFragment : binding.shareProcessChangeNameSwitch.visibility = View.GONE binding.shareProcessChangeNameContainer.visibility = View.GONE binding.shareProcessHideDownloadCheckbox.visibility = View.GONE - if (isSecureShare) { - binding.shareProcessAllowResharingCheckbox.visibility = View.GONE - } else { - binding.shareProcessAllowResharingCheckbox.visibility = View.VISIBLE - } + binding.shareCheckbox.setVisibleIf(!isSecureShare) binding.shareProcessSetPasswordSwitch.visibility = View.GONE if (share != null) { if (!isReShareShown) { - binding.shareProcessAllowResharingCheckbox.visibility = View.GONE + binding.shareCheckbox.visibility = View.GONE } - binding.shareProcessAllowResharingCheckbox.isChecked = SharingMenuHelper.canReshare(share) + binding.shareCheckbox.isChecked = SharingMenuHelper.canReshare(share) } } private fun updateViewForExternalAndLinkShare() { binding.run { shareProcessHideDownloadCheckbox.visibility = View.VISIBLE - shareProcessAllowResharingCheckbox.visibility = View.GONE + shareCheckbox.visibility = View.GONE shareProcessSetPasswordSwitch.visibility = View.VISIBLE if (share != null) { @@ -444,7 +434,7 @@ class FileDetailsSharingProcessFragment : fileDropRadioButton.visibility = View.VISIBLE if (isSecureShare) { fileDropRadioButton.visibility = View.GONE - shareProcessAllowResharingCheckbox.visibility = View.GONE + shareCheckbox.visibility = View.GONE shareProcessSetExpDateSwitch.visibility = View.GONE } } @@ -577,10 +567,6 @@ class FileDetailsSharingProcessFragment : togglePermission(OCShare.UPDATE_PERMISSION_FLAG) } - shareProcessAllowResharingCheckbox.setOnCheckedChangeListener { _, isChecked -> - permission = sharePermissionManager.getReSharePermission() - } - shareCheckbox.setOnCheckedChangeListener { _, isChecked -> togglePermission(OCShare.SHARE_PERMISSION_FLAG) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index f42265eaea28..a6fd4858e8ac 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -9,7 +9,6 @@ package com.owncloud.android.ui.fragment.util import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.shares.OCShare -import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Companion.TAG class SharePermissionManager { @@ -78,12 +77,6 @@ class SharePermissionManager { } } - fun getReSharePermission(): Int { - return SharePermissionsBuilder().apply { - setSharePermission(true) - }.build() - } - fun getMaximumPermission(isFolder: Boolean): Int { return if (isFolder) { OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index d1ae3ed98f16..77a387fc7332 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -74,24 +74,6 @@ - - - - File drop Secure file drop Share permissions - Advanced settings Next Send share Please select at least one permission to share. From 85f8d2763f701305bbdab589199a18bb44a48ab8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 13:32:34 +0200 Subject: [PATCH 036/110] fix togglePermission Signed-off-by: alperozturk --- .../fragment/FileDetailsSharingProcessFragment.kt | 14 +++++++------- .../ui/fragment/util/SharePermissionManager.kt | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index da1d19fb0278..f0e359d2d9ea 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -516,8 +516,8 @@ class FileDetailsSharingProcessFragment : } } - private fun togglePermission(permissionFlag: Int) { - permission = sharePermissionManager.togglePermission(permission, permissionFlag) + private fun togglePermission(isChecked: Boolean, permissionFlag: Int) { + permission = sharePermissionManager.togglePermission(isChecked, permission, permissionFlag) } private fun setCheckboxStates() { @@ -556,23 +556,23 @@ class FileDetailsSharingProcessFragment : private fun setCheckboxesListeners() { binding.run { shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(OCShare.READ_PERMISSION_FLAG) + togglePermission(isChecked, OCShare.READ_PERMISSION_FLAG) } shareCreateCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(OCShare.CREATE_PERMISSION_FLAG) + togglePermission(isChecked, OCShare.CREATE_PERMISSION_FLAG) } shareEditCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(OCShare.UPDATE_PERMISSION_FLAG) + togglePermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) } shareCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(OCShare.SHARE_PERMISSION_FLAG) + togglePermission(isChecked, OCShare.SHARE_PERMISSION_FLAG) } shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(OCShare.DELETE_PERMISSION_FLAG) + togglePermission(isChecked, OCShare.DELETE_PERMISSION_FLAG) } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index a6fd4858e8ac..ae10030097dc 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -13,7 +13,7 @@ import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Compan class SharePermissionManager { - fun togglePermission(permission: Int, permissionFlag: Int): Int { + fun togglePermission(isChecked: Boolean, permission: Int, permissionFlag: Int): Int { Log_OC.d(TAG, "togglePermission before: $permission") if (!isPermissionValid(permission)) { @@ -21,10 +21,10 @@ class SharePermissionManager { return permission } - val result = if (hasPermission(permission, permissionFlag)) { - permission and permissionFlag.inv() - } else { + val result = if (isChecked) { permission or permissionFlag + } else { + permission and permissionFlag.inv() } Log_OC.d(TAG, "togglePermission after: $result") From f6268377340568f33274920e43677632e2de47f3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 13:38:56 +0200 Subject: [PATCH 037/110] fix initial permission Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index f0e359d2d9ea..afb8feedd322 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -174,7 +174,7 @@ class FileDetailsSharingProcessFragment : fileActivity = activity as FileActivity? capabilities = CapabilityUtils.getCapability(context) - permission = sharePermissionManager.getMaximumPermission(isFolder()) + permission = share?.permissions ?: sharePermissionManager.getMaximumPermission(isFolder()) requireNotNull(fileActivity) { "FileActivity may not be null" } From c0e5b2ca70c8714ef1ee40d4d247ec748c29eaf1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 2 Apr 2025 16:11:41 +0200 Subject: [PATCH 038/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 3 ++- .../android/ui/fragment/util/SharePermissionManager.kt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index afb8feedd322..302de5d028d0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -283,7 +283,8 @@ class FileDetailsSharingProcessFragment : SharingMenuHelper.isReadOnly(share) -> viewOnlyRadioButton.isChecked = true else -> { if (sharePermissionManager.isCustomPermission(share) || - shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { + shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION + ) { customPermissionRadioButton.isChecked = true customPermissionLayout.setVisibilityWithAnimation(true) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index ae10030097dc..4ae1f628a4af 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -58,6 +58,7 @@ class SharePermissionManager { return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag } + @Suppress("ReturnCount") fun isCustomPermission(share: OCShare?): Boolean { if (share == null) return false val permissions = share.permissions From 16bb4ecc2f0dec3d77cdd552dcbe5d04802590db Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 3 Apr 2025 09:09:18 +0200 Subject: [PATCH 039/110] use default permission Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 46 ------------------- .../FileDetailsSharingProcessFragment.kt | 25 +++++----- app/src/main/res/values/strings.xml | 1 - 3 files changed, 14 insertions(+), 58 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 99cac6c885a8..6170d7835f2e 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -343,13 +343,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check( - matches( - not( - isDisplayed() - ) - ) - ) // read-only onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) @@ -497,13 +490,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check( - matches( - not( - isDisplayed() - ) - ) - ) // read-only publicShare.permissions = 17 // from server @@ -640,9 +626,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView( ViewMatchers.withId(R.id.share_process_change_name_switch) ).check(matches(not(isDisplayed()))) - onView( - ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) - ).check(matches(isDisplayed())) // read-only userShare.permissions = 17 // from server @@ -657,19 +640,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) goBack() - // allow reshare - userShare.permissions = 1 // from server - openAdvancedPermissions(sut, userShare) - onView( - ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) - ).check(matches(isNotChecked())) - goBack() - - userShare.permissions = 17 // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) - goBack() - // set expiration date userShare.expirationDate = 1582019340000 openAdvancedPermissions(sut, userShare) @@ -787,9 +757,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView( ViewMatchers.withId(R.id.share_process_change_name_switch) ).check(matches(not(isDisplayed()))) - onView( - ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) - ).check(matches(isDisplayed())) // read-only userShare.permissions = 17 // from server @@ -814,19 +781,6 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) goBack() - // allow reshare - userShare.permissions = 1 // from server - openAdvancedPermissions(sut, userShare) - onView( - ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox) - ).check(matches(isNotChecked())) - goBack() - - userShare.permissions = 17 // from server - openAdvancedPermissions(sut, userShare) - onView(ViewMatchers.withId(R.id.share_process_allow_resharing_checkbox)).check(matches(isChecked())) - goBack() - // set expiration date userShare.expirationDate = 1582019340000 openAdvancedPermissions(sut, userShare) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 302de5d028d0..176a52e3bb7d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -174,11 +174,12 @@ class FileDetailsSharingProcessFragment : fileActivity = activity as FileActivity? capabilities = CapabilityUtils.getCapability(context) - permission = share?.permissions ?: sharePermissionManager.getMaximumPermission(isFolder()) requireNotNull(fileActivity) { "FileActivity may not be null" } - permission = capabilities.defaultPermissions ?: OCShare.NO_PERMISSION + permission = share?.permissions ?: + capabilities.defaultPermissions ?: + sharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -362,17 +363,19 @@ class FileDetailsSharingProcessFragment : } private fun updateViewForInternalShare() { - binding.shareProcessChangeNameSwitch.visibility = View.GONE - binding.shareProcessChangeNameContainer.visibility = View.GONE - binding.shareProcessHideDownloadCheckbox.visibility = View.GONE - binding.shareCheckbox.setVisibleIf(!isSecureShare) - binding.shareProcessSetPasswordSwitch.visibility = View.GONE + binding.run { + shareProcessChangeNameSwitch.visibility = View.GONE + shareProcessChangeNameContainer.visibility = View.GONE + shareProcessHideDownloadCheckbox.visibility = View.GONE + shareCheckbox.setVisibleIf(!isSecureShare) + shareProcessSetPasswordSwitch.visibility = View.GONE - if (share != null) { - if (!isReShareShown) { - binding.shareCheckbox.visibility = View.GONE + if (share != null) { + if (!isReShareShown) { + shareCheckbox.visibility = View.GONE + } + shareCheckbox.isChecked = SharingMenuHelper.canReshare(share) } - binding.shareCheckbox.isChecked = SharingMenuHelper.canReshare(share) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2bb765a7b10c..b3cddd22498d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1090,7 +1090,6 @@ New name Share link (%1$s) Share link - Allow resharing Custom permissions Read Create From a883e646a010c4d0f36ffdfb52901703afcfb3e7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 3 Apr 2025 10:23:23 +0200 Subject: [PATCH 040/110] fix check order Signed-off-by: alperozturk --- .../owncloud/android/ui/fragment/util/SharingMenuHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 09d3f9bd87a9..4feab42f61bf 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -75,12 +75,12 @@ public static String getPermissionName(Context context, OCShare share) { return res.getString(R.string.share_permission_can_edit); } else if (SharingMenuHelper.isReadOnly(share)) { return res.getString(R.string.share_permission_view_only); + } else if (sharePermissionManager.isCustomPermission(share)) { + return res.getString(R.string.share_custom_permission); } else if (SharingMenuHelper.isSecureFileDrop(share)) { return res.getString(R.string.share_permission_secure_file_drop); } else if (SharingMenuHelper.isFileDrop(share)) { return res.getString(R.string.share_permission_file_drop); - } else if (sharePermissionManager.isCustomPermission(share)) { - return res.getString(R.string.share_custom_permission); } return null; From ba46f566825da595a8485302cefcb2808112e566 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 3 Apr 2025 10:26:15 +0200 Subject: [PATCH 041/110] fix license Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 176a52e3bb7d..430fd8dec31e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -1,11 +1,8 @@ /* - * Nextcloud Android client application + * Nextcloud - Android Client * - * @author TSI-mc - * Copyright (C) 2021 TSI-mc - * Copyright (C) 2021 Nextcloud GmbH - * - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ package com.owncloud.android.ui.fragment From 55f718fc5b96df4c9cf1a65f1b6580c7437397b4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 3 Apr 2025 10:36:59 +0200 Subject: [PATCH 042/110] simplify functions Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 112 ++++++++---------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 430fd8dec31e..100f6e9ceb27 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -174,9 +174,9 @@ class FileDetailsSharingProcessFragment : requireNotNull(fileActivity) { "FileActivity may not be null" } - permission = share?.permissions ?: - capabilities.defaultPermissions ?: - sharePermissionManager.getMaximumPermission(isFolder()) + permission = share?.permissions + ?: capabilities.defaultPermissions + ?: sharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -490,26 +490,24 @@ class FileDetailsSharingProcessFragment : // region RadioButtons shareProcessPermissionRadioGroup.setOnCheckedChangeListener { radioGroup, optionId -> - run { - when (optionId) { - R.id.view_only_radio_button -> { - customPermissionLayout.visibility = View.GONE - permission = OCShare.READ_PERMISSION_FLAG - } - - R.id.editing_radio_button -> { - customPermissionLayout.visibility = View.GONE - permission = sharePermissionManager.getMaximumPermission(isFolder()) - } - - R.id.file_drop_radio_button -> { - permission = OCShare.CREATE_PERMISSION_FLAG - } - - R.id.custom_permission_radio_button -> { - val isChecked = customPermissionRadioButton.isChecked - customPermissionLayout.setVisibilityWithAnimation(isChecked) - } + when (optionId) { + R.id.view_only_radio_button -> { + customPermissionLayout.visibility = View.GONE + permission = OCShare.READ_PERMISSION_FLAG + } + + R.id.editing_radio_button -> { + customPermissionLayout.visibility = View.GONE + permission = sharePermissionManager.getMaximumPermission(isFolder()) + } + + R.id.file_drop_radio_button -> { + permission = OCShare.CREATE_PERMISSION_FLAG + } + + R.id.custom_permission_radio_button -> { + val isChecked = customPermissionRadioButton.isChecked + customPermissionLayout.setVisibilityWithAnimation(isChecked) } } } @@ -525,56 +523,40 @@ class FileDetailsSharingProcessFragment : val currentPermissions = share?.permissions ?: permission binding.run { - if (isFolder()) { - // Only for the folder makes sense to have create permission - // so that user can create files in the shared folder - shareCreateCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.CREATE_PERMISSION_FLAG) - } else { - shareCreateCheckbox.visibility = View.GONE - } - - shareReadCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) - shareEditCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.UPDATE_PERMISSION_FLAG) - - if (isFolder()) { - shareDeleteCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.DELETE_PERMISSION_FLAG) - } else { - shareDeleteCheckbox.isChecked = false - shareDeleteCheckbox.isEnabled = false + sharePermissionManager.run { + shareReadCheckbox.isChecked = hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) + shareEditCheckbox.isChecked = hasPermission(currentPermissions, OCShare.UPDATE_PERMISSION_FLAG) + shareCheckbox.isChecked = hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG) + + if (isFolder()) { + // Only for the folder makes sense to have create permission + // so that user can create files in the shared folder + shareCreateCheckbox.isChecked = hasPermission(currentPermissions, OCShare.CREATE_PERMISSION_FLAG) + shareDeleteCheckbox.isChecked = hasPermission(currentPermissions, OCShare.DELETE_PERMISSION_FLAG) + } else { + shareCreateCheckbox.visibility = View.GONE + shareDeleteCheckbox.apply { + isChecked = false + isEnabled = false + } + } } - - shareCheckbox.isChecked = - sharePermissionManager.hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG) } setCheckboxesListeners() } private fun setCheckboxesListeners() { - binding.run { - shareReadCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(isChecked, OCShare.READ_PERMISSION_FLAG) - } - - shareCreateCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(isChecked, OCShare.CREATE_PERMISSION_FLAG) - } - - shareEditCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(isChecked, OCShare.UPDATE_PERMISSION_FLAG) - } - - shareCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(isChecked, OCShare.SHARE_PERMISSION_FLAG) - } + val checkboxes = mapOf( + binding.shareReadCheckbox to OCShare.READ_PERMISSION_FLAG, + binding.shareCreateCheckbox to OCShare.CREATE_PERMISSION_FLAG, + binding.shareEditCheckbox to OCShare.UPDATE_PERMISSION_FLAG, + binding.shareCheckbox to OCShare.SHARE_PERMISSION_FLAG, + binding.shareDeleteCheckbox to OCShare.DELETE_PERMISSION_FLAG + ) - shareDeleteCheckbox.setOnCheckedChangeListener { _, isChecked -> - togglePermission(isChecked, OCShare.DELETE_PERMISSION_FLAG) - } + checkboxes.forEach { (checkbox, flag) -> + checkbox.setOnCheckedChangeListener { _, isChecked -> togglePermission(isChecked, flag) } } } From 8d87a8e0ef6296ee20810e2a6533e7c051ce9740 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 9 Apr 2025 16:46:48 +0200 Subject: [PATCH 043/110] add shareAllowDownloadAndSyncCheckbox Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 6 ++++++ .../res/layout/file_details_sharing_process_fragment.xml | 9 +++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 16 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 100f6e9ceb27..e26c4749ceff 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -211,6 +211,8 @@ class FileDetailsSharingProcessFragment : themeRadioButton(fileDropRadioButton) themeRadioButton(customPermissionRadioButton) + themeCheckbox(shareAllowDownloadAndSyncCheckbox) + themeCheckbox(shareReadCheckbox) themeCheckbox(shareCreateCheckbox) themeCheckbox(shareEditCheckbox) @@ -488,6 +490,10 @@ class FileDetailsSharingProcessFragment : showExpirationDateDialog() } + shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> + share + } + // region RadioButtons shareProcessPermissionRadioGroup.setOnCheckedChangeListener { radioGroup, optionId -> when (optionId) { diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 77a387fc7332..b8830a81115d 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -74,6 +74,15 @@ + + Share link Custom permissions Read + Allow download and sync Create Edit Share From 0c577d2df1f0a2710f118f4ee836cba3f695c6de Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 11:03:19 +0200 Subject: [PATCH 044/110] add share attribute field Signed-off-by: alperozturk --- .../client/database/entity/ShareEntity.kt | 4 ++- .../datamodel/FileDataStorageManager.java | 4 +++ .../com/owncloud/android/db/ProviderMeta.java | 1 + .../CreateShareWithShareeOperation.java | 6 +++- .../operations/UpdateShareInfoOperation.java | 6 ++++ .../android/services/OperationsService.java | 7 +++++ .../FileDetailsSharingProcessFragment.kt | 11 ++++--- .../fragment/util/SharePermissionManager.kt | 31 +++++++++++++++++++ .../ui/helpers/FileOperationsHelper.java | 3 ++ 9 files changed, 67 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/entity/ShareEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/ShareEntity.kt index 1c397ced030d..ad5005efef20 100644 --- a/app/src/main/java/com/nextcloud/client/database/entity/ShareEntity.kt +++ b/app/src/main/java/com/nextcloud/client/database/entity/ShareEntity.kt @@ -58,5 +58,7 @@ data class ShareEntity( @ColumnInfo(name = ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_LIMIT) val downloadLimitLimit: Int?, @ColumnInfo(name = ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT) - val downloadLimitCount: Int? + val downloadLimitCount: Int?, + @ColumnInfo(name = ProviderTableMeta.OCSHARES_ATTRIBUTES) + val attributes: String? ) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 2f84154ede97..79f3d977f45a 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -1569,6 +1569,8 @@ private ContentValues createContentValueForShare(OCShare share) { contentValues.putNull(ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT); } + contentValues.put(ProviderTableMeta.OCSHARES_ATTRIBUTES, share.getAttributes()); + return contentValues; } @@ -1599,6 +1601,8 @@ private OCShare createShareInstance(Cursor cursor) { getInt(cursor, ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT)); share.setFileDownloadLimit(downloadLimit); + share.setAttributes(getString(cursor,ProviderTableMeta.OCSHARES_ATTRIBUTES)); + return share; } diff --git a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java index 955aeb1d9044..cda0cc1b80dc 100644 --- a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -203,6 +203,7 @@ static public class ProviderTableMeta implements BaseColumns { public static final String OCSHARES_SHARE_LABEL = "share_label"; public static final String OCSHARES_DOWNLOADLIMIT_LIMIT = "download_limit_limit"; public static final String OCSHARES_DOWNLOADLIMIT_COUNT = "download_limit_count"; + public static final String OCSHARES_ATTRIBUTES = "attributes"; public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE + " collate nocase asc"; diff --git a/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java index 469829bbaae5..68a5751938cb 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java @@ -56,6 +56,7 @@ public class CreateShareWithShareeOperation extends SyncOperation { private String label; private final Context context; private final User user; + private String attributes; private ArbitraryDataProvider arbitraryDataProvider; @@ -85,6 +86,7 @@ public CreateShareWithShareeOperation(String path, String sharePassword, long expirationDateInMillis, boolean hideFileDownload, + String attributes, FileDataStorageManager storageManager, Context context, User user, @@ -105,6 +107,7 @@ public CreateShareWithShareeOperation(String path, this.context = context; this.user = user; this.arbitraryDataProvider = arbitraryDataProvider; + this.attributes = attributes; } @Override @@ -156,7 +159,8 @@ protected RemoteOperationResult run(OwnCloudClient client) { false, sharePassword, permissions, - noteMessage + noteMessage, + attributes ); operation.setGetShareDetails(true); RemoteOperationResult shareResult = operation.execute(client); diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java index 918e5577a0cc..538194c39d58 100644 --- a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java @@ -35,6 +35,7 @@ public class UpdateShareInfoOperation extends SyncOperation { private int permissions = -1; private String password; private String label; + private String attributes; /** * Constructor @@ -93,6 +94,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } updateOp.setPassword(password); updateOp.setLabel(label); + updateOp.setAttributes(attributes); RemoteOperationResult result = updateOp.execute(client); @@ -125,6 +127,10 @@ public void setHideFileDownload(boolean hideFileDownload) { this.hideFileDownload = hideFileDownload; } + public void setAttributes(String attributes) { + this.attributes = attributes; + } + public void setPermissions(int permissions) { this.permissions = permissions; } diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 4ccadf9d6b0a..48b0373b34d9 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -101,6 +101,7 @@ public class OperationsService extends Service { public static final String EXTRA_SHARE_NOTE = "SHARE_NOTE"; public static final String EXTRA_IN_BACKGROUND = "IN_BACKGROUND"; public static final String EXTRA_FILES_DOWNLOAD_LIMIT = "FILES_DOWNLOAD_LIMIT"; + public static final String EXTRA_SHARE_ATTRIBUTES = "SHARE_ATTRIBUTES"; public static final String ACTION_CREATE_SHARE_VIA_LINK = "CREATE_SHARE_VIA_LINK"; public static final String ACTION_CREATE_SECURE_FILE_DROP = "CREATE_SECURE_FILE_DROP"; @@ -593,6 +594,8 @@ private Pair newOperation(Intent operationIntent) { .getLongExtra(EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, 0L); boolean hideFileDownload = operationIntent.getBooleanExtra(EXTRA_SHARE_HIDE_FILE_DOWNLOAD, false); + String attributes = operationIntent.getStringExtra(EXTRA_SHARE_ATTRIBUTES); + if (!TextUtils.isEmpty(remotePath)) { CreateShareWithShareeOperation createShareWithShareeOperation = new CreateShareWithShareeOperation(remotePath, @@ -603,6 +606,7 @@ private Pair newOperation(Intent operationIntent) { sharePassword, expirationDateInMillis, hideFileDownload, + attributes, fileDataStorageManager, getApplicationContext(), user, @@ -641,6 +645,9 @@ private Pair newOperation(Intent operationIntent) { updateShare.setLabel(operationIntent.getStringExtra(EXTRA_SHARE_PUBLIC_LABEL)); } + String shareAttributes = operationIntent.getStringExtra(EXTRA_SHARE_ATTRIBUTES); + updateShare.setAttributes(shareAttributes); + operation = updateShare; } break; diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index e26c4749ceff..d0f64d858d86 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -490,10 +490,6 @@ class FileDetailsSharingProcessFragment : showExpirationDateDialog() } - shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> - share - } - // region RadioButtons shareProcessPermissionRadioGroup.setOnCheckedChangeListener { radioGroup, optionId -> when (optionId) { @@ -546,6 +542,8 @@ class FileDetailsSharingProcessFragment : isEnabled = false } } + + shareAllowDownloadAndSyncCheckbox.isChecked = isAllowDownloadAndSyncEnabled(share) } } @@ -564,6 +562,10 @@ class FileDetailsSharingProcessFragment : checkboxes.forEach { (checkbox, flag) -> checkbox.setOnCheckedChangeListener { _, isChecked -> togglePermission(isChecked, flag) } } + + binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> + share?.attributes = sharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) + } } private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) { @@ -726,6 +728,7 @@ class FileDetailsSharingProcessFragment : binding.shareProcessEnterPassword.text.toString().trim(), chosenExpDateInMills, noteText, + share?.attributes, binding.shareProcessChangeName.text.toString().trim(), true ) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index 4ae1f628a4af..a5bc891d0ce6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -9,6 +9,9 @@ package com.owncloud.android.ui.fragment.util import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.attributes.ShareAttributes +import com.owncloud.android.lib.resources.shares.attributes.ShareAttributesJsonHandler +import com.owncloud.android.lib.resources.shares.attributes.getDownloadAttribute import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Companion.TAG class SharePermissionManager { @@ -85,4 +88,32 @@ class SharePermissionManager { OCShare.MAXIMUM_PERMISSIONS_FOR_FILE } } + + fun toggleAllowDownloadAndSync(isChecked: Boolean, share: OCShare?): String? { + val shareAttributes = getShareAttributes(share)?.toMutableList() + val downloadAttributeIndex = shareAttributes?.indexOf(shareAttributes.getDownloadAttribute()) + if (downloadAttributeIndex != null && downloadAttributeIndex >= 0) { + val updatedAttribute = shareAttributes[downloadAttributeIndex].copy(isEnabled = isChecked) + shareAttributes[downloadAttributeIndex] = updatedAttribute + } + + if (shareAttributes == null) { + return null + } + + return ShareAttributesJsonHandler.toJson(shareAttributes) + } + + fun isAllowDownloadAndSyncEnabled(share: OCShare?): Boolean { + val shareAttributes = getShareAttributes(share)?.toMutableList() + return shareAttributes.getDownloadAttribute()?.isEnabled == true + } + + private fun getShareAttributes(share: OCShare?): List? { + if (share == null || share.attributes == null) { + return null + } + + return ShareAttributesJsonHandler.parseJson(share.attributes!!) + } } diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 9d4de1321383..3357e98bc5ce 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -534,6 +534,7 @@ public void shareFileWithSharee(OCFile file, String password, long expirationTimeInMillis, String note, + String attributes, String label, boolean showLoadingDialog) { if (file != null) { @@ -555,6 +556,7 @@ public void shareFileWithSharee(OCFile file, service.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis); service.putExtra(OperationsService.EXTRA_SHARE_NOTE, (note == null) ? "" : note); service.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label); + service.putExtra(OperationsService.EXTRA_SHARE_ATTRIBUTES, attributes); mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service); @@ -763,6 +765,7 @@ public void updateShareInformation(OCShare share, int permissions, updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label); + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ATTRIBUTES, share.getAttributes()); queueShareIntent(updateShareIntent); } From 926fcc09a7a2aaf79d9fa06d982070c70a1026eb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 12:37:33 +0200 Subject: [PATCH 045/110] add share attribute field Signed-off-by: alperozturk --- .../com/owncloud/android/datamodel/FileDataStorageManager.java | 2 +- .../owncloud/android/ui/fragment/util/SharePermissionManager.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 79f3d977f45a..de005a984eba 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -1601,7 +1601,7 @@ private OCShare createShareInstance(Cursor cursor) { getInt(cursor, ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT)); share.setFileDownloadLimit(downloadLimit); - share.setAttributes(getString(cursor,ProviderTableMeta.OCSHARES_ATTRIBUTES)); + share.setAttributes(getString(cursor, ProviderTableMeta.OCSHARES_ATTRIBUTES)); return share; } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index a5bc891d0ce6..c72457560d63 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -114,6 +114,6 @@ class SharePermissionManager { return null } - return ShareAttributesJsonHandler.parseJson(share.attributes!!) + return ShareAttributesJsonHandler.toList(share.attributes!!) } } From a9fcb1e4090f6ee8e178594f24443089af2d0fc5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 12:45:00 +0200 Subject: [PATCH 046/110] simplify Signed-off-by: alperozturk --- .../android/ui/fragment/util/SharePermissionManager.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index c72457560d63..5b22f241b5f3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -105,15 +105,10 @@ class SharePermissionManager { } fun isAllowDownloadAndSyncEnabled(share: OCShare?): Boolean { - val shareAttributes = getShareAttributes(share)?.toMutableList() - return shareAttributes.getDownloadAttribute()?.isEnabled == true + return getShareAttributes(share).getDownloadAttribute()?.isEnabled == true } private fun getShareAttributes(share: OCShare?): List? { - if (share == null || share.attributes == null) { - return null - } - - return ShareAttributesJsonHandler.toList(share.attributes!!) + return share?.attributes?.let { ShareAttributesJsonHandler.toList(it) } } } From a2b2133acf8f780428296d77f09bbf3d46637794 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 10 Apr 2025 14:24:59 +0200 Subject: [PATCH 047/110] fix logic Signed-off-by: alperozturk --- .../ui/fragment/util/SharePermissionManager.kt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index 5b22f241b5f3..c3735a0cbcdb 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -91,21 +91,23 @@ class SharePermissionManager { fun toggleAllowDownloadAndSync(isChecked: Boolean, share: OCShare?): String? { val shareAttributes = getShareAttributes(share)?.toMutableList() - val downloadAttributeIndex = shareAttributes?.indexOf(shareAttributes.getDownloadAttribute()) - if (downloadAttributeIndex != null && downloadAttributeIndex >= 0) { - val updatedAttribute = shareAttributes[downloadAttributeIndex].copy(isEnabled = isChecked) - shareAttributes[downloadAttributeIndex] = updatedAttribute + if (shareAttributes == null) { + val downloadAttribute = ShareAttributes.createDownloadAttributes(isChecked) + val updatedShareAttributes = listOf(downloadAttribute) + return ShareAttributesJsonHandler.toJson(updatedShareAttributes) } - if (shareAttributes == null) { - return null + val downloadAttributeIndex = shareAttributes.indexOf(shareAttributes.getDownloadAttribute()) + if (downloadAttributeIndex >= 0) { + val updatedAttribute = shareAttributes[downloadAttributeIndex].copy(value = isChecked) + shareAttributes[downloadAttributeIndex] = updatedAttribute } return ShareAttributesJsonHandler.toJson(shareAttributes) } fun isAllowDownloadAndSyncEnabled(share: OCShare?): Boolean { - return getShareAttributes(share).getDownloadAttribute()?.isEnabled == true + return getShareAttributes(share).getDownloadAttribute()?.value == true } private fun getShareAttributes(share: OCShare?): List? { From 241dfbcd02146c7df89a07e3e5f3685046e6e282 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 14 Apr 2025 13:00:56 +0200 Subject: [PATCH 048/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index d0f64d858d86..84ce6babee2a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -521,6 +521,7 @@ class FileDetailsSharingProcessFragment : permission = sharePermissionManager.togglePermission(isChecked, permission, permissionFlag) } + @Suppress("NestedBlockDepth") private fun setCheckboxStates() { val currentPermissions = share?.permissions ?: permission From 5d7e848d8574cc048a474d4f4de2d9e3b82bd852 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 14 Apr 2025 16:18:52 +0200 Subject: [PATCH 049/110] do not show allow download and sync for public share Signed-off-by: alperozturk --- .../fragment/FileDetailsSharingProcessFragment.kt | 15 +++++++++++---- .../file_details_sharing_process_fragment.xml | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 84ce6babee2a..3e12da3f7341 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -211,7 +211,10 @@ class FileDetailsSharingProcessFragment : themeRadioButton(fileDropRadioButton) themeRadioButton(customPermissionRadioButton) - themeCheckbox(shareAllowDownloadAndSyncCheckbox) + if (shareType != ShareType.PUBLIC_LINK) { + shareAllowDownloadAndSyncCheckbox.visibility = View.VISIBLE + themeCheckbox(shareAllowDownloadAndSyncCheckbox) + } themeCheckbox(shareReadCheckbox) themeCheckbox(shareCreateCheckbox) @@ -544,7 +547,9 @@ class FileDetailsSharingProcessFragment : } } - shareAllowDownloadAndSyncCheckbox.isChecked = isAllowDownloadAndSyncEnabled(share) + if (shareType != ShareType.PUBLIC_LINK) { + shareAllowDownloadAndSyncCheckbox.isChecked = isAllowDownloadAndSyncEnabled(share) + } } } @@ -564,8 +569,10 @@ class FileDetailsSharingProcessFragment : checkbox.setOnCheckedChangeListener { _, isChecked -> togglePermission(isChecked, flag) } } - binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> - share?.attributes = sharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) + if (shareType != ShareType.PUBLIC_LINK) { + binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> + share?.attributes = sharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) + } } } diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index b8830a81115d..6bce6d7570ea 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -80,6 +80,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/standard_margin" android:minHeight="@dimen/minimum_size_for_touchable_area" + android:visibility="gone" android:text="@string/share_allow_download_and_sync_permission" tools:visibility="visible" /> From 13260791e8f9175bd98191815bffdd8d11a5450a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 10:53:20 +0200 Subject: [PATCH 050/110] enable read checkbox for updateViewForLinkShare and folder Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 3e12da3f7341..28021486619b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -349,19 +349,24 @@ class FileDetailsSharingProcessFragment : } private fun updateViewForExternalShare() { - binding.shareProcessChangeNameSwitch.visibility = View.GONE - binding.shareProcessChangeNameContainer.visibility = View.GONE - updateViewForExternalAndLinkShare() + binding.run { + shareProcessChangeNameSwitch.visibility = View.GONE + shareProcessChangeNameContainer.visibility = View.GONE + updateViewForExternalAndLinkShare() + } } private fun updateViewForLinkShare() { updateViewForExternalAndLinkShare() - binding.shareProcessChangeNameSwitch.visibility = View.VISIBLE - if (share != null) { - binding.shareProcessChangeName.setText(share?.label) - binding.shareProcessChangeNameSwitch.isChecked = !TextUtils.isEmpty(share?.label) + binding.run { + shareProcessChangeNameSwitch.visibility = View.VISIBLE + if (share != null) { + shareProcessChangeName.setText(share?.label) + shareProcessChangeNameSwitch.isChecked = !TextUtils.isEmpty(share?.label) + } + shareReadCheckbox.isEnabled = isFolder() + showChangeNameInput(shareProcessChangeNameSwitch.isChecked) } - showChangeNameInput(binding.shareProcessChangeNameSwitch.isChecked) } private fun updateViewForInternalShare() { From 056316a6f3766edf3924004b2d1aec35a0d1eeb2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 10:59:57 +0200 Subject: [PATCH 051/110] align translations with web and iOS client Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- .../ui/fragment/QuickSharingPermissionsBottomSheetDialog.java | 4 ++-- .../owncloud/android/ui/fragment/util/SharingMenuHelper.java | 4 ++-- .../main/res/layout/file_details_sharing_process_fragment.xml | 4 ++-- app/src/main/res/values/attrs.xml | 4 ++-- app/src/main/res/values/strings.xml | 3 +-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 28021486619b..b209a04eb08c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -441,7 +441,7 @@ class FileDetailsSharingProcessFragment : private fun updateViewForFolder() { binding.run { - editingRadioButton.text = getString(R.string.link_share_allow_upload_and_editing) + editingRadioButton.text = getString(R.string.share_permission_can_edit) fileDropRadioButton.visibility = View.VISIBLE if (isSecureShare) { fileDropRadioButton.visibility = View.GONE diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 3d7bf169d790..1672c8248262 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -114,11 +114,11 @@ private void handlePermissionChanged(List quickPermissionM final var res = fileActivity.getResources(); int permissionFlag = 0; - if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_allow_upload_and_editing)) || permissionName.equalsIgnoreCase(res.getString(R.string.link_share_editing))) { + if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_can_edit)) || permissionName.equalsIgnoreCase(res.getString(R.string.link_share_editing))) { permissionFlag = ocShare.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : MAXIMUM_PERMISSIONS_FOR_FILE; } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_view_only))) { permissionFlag = READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_drop))) { + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_request))) { permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 4feab42f61bf..72fd468953da 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -94,11 +94,11 @@ public static int getPermissionCheckedItem(Context context, OCShare share, Strin int permissionName; if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - permissionName = share.isFolder() ? R.string.link_share_allow_upload_and_editing : R.string.link_share_editing; + permissionName = share.isFolder() ? R.string.share_permission_can_edit : R.string.link_share_editing; } else if (SharingMenuHelper.isReadOnly(share)) { permissionName = R.string.link_share_view_only; } else if (SharingMenuHelper.isFileDrop(share)) { - permissionName = R.string.link_share_file_drop; + permissionName = R.string.link_share_file_request; } else if (sharePermissionManager.isCustomPermission(share)) { permissionName = R.string.share_custom_permission; } else { diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 6bce6d7570ea..30f4e7f03a65 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -56,7 +56,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/minimum_size_for_touchable_area" - android:text="@string/link_share_allow_upload_and_editing" /> + android:text="@string/share_permission_can_edit" /> + android:text="@string/link_share_file_request" /> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index d86cd0664f7f..dd334efcd898 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -28,8 +28,8 @@ @string/link_share_view_only - @string/link_share_allow_upload_and_editing - @string/link_share_file_drop + @string/share_permission_can_edit + @string/link_share_file_request @string/share_custom_permission diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c87245990d98..50cc49e5c331 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1099,8 +1099,7 @@ Delete View only Editing - Allow upload and editing - File drop (upload only) + File request Could not retrieve shares Failed to update UI Failed to pick email address. From 61450a3a738308a3adfc25a28610982d5020a74a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 12:00:59 +0200 Subject: [PATCH 052/110] align icons with web and iOS client Signed-off-by: alperozturk --- .../android/datamodel/QuickPermissionModel.kt | 50 ++++++++++++++--- .../adapter/QuickSharingPermissionsAdapter.kt | 22 ++++---- ...ckSharingPermissionsBottomSheetDialog.java | 23 ++++---- .../res/drawable/ic_custom_permissions.xml | 16 ++++++ app/src/main/res/drawable/ic_eye.xml | 18 +++++++ app/src/main/res/drawable/ic_file_request.xml | 16 ++++++ .../layout/item_quick_share_permissions.xml | 54 +++++++------------ app/src/main/res/values/attrs.xml | 12 ----- 8 files changed, 134 insertions(+), 77 deletions(-) create mode 100644 app/src/main/res/drawable/ic_custom_permissions.xml create mode 100644 app/src/main/res/drawable/ic_eye.xml create mode 100644 app/src/main/res/drawable/ic_file_request.xml diff --git a/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt b/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt index b24bfcd88abf..8b57c511cedd 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt @@ -1,13 +1,49 @@ /* - * Nextcloud Android client application + * Nextcloud - Android Client * - * @author TSI-mc - * Copyright (C) 2021 TSI-mc - * Copyright (C) 2021 Nextcloud GmbH - * - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ package com.owncloud.android.datamodel -data class QuickPermissionModel(val permissionName: String, val isSelected: Boolean) +import android.content.Context +import com.owncloud.android.R + +data class QuickPermissionModel(val iconId: Int, val textId: Int, var isSelected: Boolean) { + companion object { + fun getPermissionModel(isFolder: Boolean): List = + if (isFolder) folderSharePermissions else fileSharePermissions + + fun getPermissionArray(permissions: List, context: Context): Array = + permissions.map { context.getString(it.textId) }.toTypedArray() + + private val folderSharePermissions = listOf( + QuickPermissionModel( + iconId = R.drawable.ic_eye, + textId = R.string.link_share_view_only, + isSelected = false + ), + QuickPermissionModel( + iconId = R.drawable.ic_edit, + textId = R.string.share_permission_can_edit, + isSelected = false + ), + QuickPermissionModel( + iconId = R.drawable.ic_file_request, + textId = R.string.link_share_file_request, + isSelected = false + ), + QuickPermissionModel( + iconId = R.drawable.ic_custom_permissions, + textId = R.string.share_custom_permission, + isSelected = false + ) + ) + + private const val FILE_REQUEST_INDEX = 2 + + private val fileSharePermissions = + folderSharePermissions.filterIndexed { index, _ -> index != FILE_REQUEST_INDEX } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index dea7938ca09f..fd15d6d4fd3a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -13,9 +13,9 @@ package com.owncloud.android.ui.adapter import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import com.nextcloud.android.common.ui.theme.utils.ColorRole -import com.nextcloud.utils.extensions.setVisibleIf +import com.google.android.material.button.MaterialButton import com.owncloud.android.R import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding import com.owncloud.android.datamodel.QuickPermissionModel @@ -43,23 +43,27 @@ class QuickSharingPermissionsAdapter( } class QuickSharingPermissionViewHolder( - val binding: ItemQuickSharePermissionsBinding, + private val binding: ItemQuickSharePermissionsBinding, itemView: View, - val onPermissionChangeListener: OnPermissionChangeListener, + private val onPermissionChangeListener: OnPermissionChangeListener, private val viewThemeUtils: ViewThemeUtils ) : RecyclerView.ViewHolder(itemView) { fun bindData(quickPermissionModel: QuickPermissionModel) { + val context = itemView.context + val permissionName = context.getString(quickPermissionModel.textId) + binding.run { - tvQuickShareName.text = quickPermissionModel.permissionName - tvQuickShareCheckIcon.setVisibleIf(quickPermissionModel.isSelected) + quickPermissionButton.text = permissionName + quickPermissionButton.iconGravity = MaterialButton.ICON_GRAVITY_START + quickPermissionButton.icon = ContextCompat.getDrawable(context, quickPermissionModel.iconId) + if (quickPermissionModel.isSelected) { - viewThemeUtils.platform.colorImageView(tvQuickShareCheckIcon, ColorRole.PRIMARY) + viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(quickPermissionButton) } } - val customPermissionName = itemView.context.getString(R.string.share_custom_permission) - val permissionName = quickPermissionModel.permissionName + val customPermissionName = context.getString(R.string.share_custom_permission) val isCustomPermission = permissionName.equals(customPermissionName, ignoreCase = true) itemView.setOnClickListener { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 1672c8248262..a2e4fb73d0ca 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -26,7 +26,6 @@ import com.owncloud.android.ui.fragment.util.SharingMenuHelper; import com.owncloud.android.utils.theme.ViewThemeUtils; -import java.util.ArrayList; import java.util.List; import androidx.recyclerview.widget.LinearLayoutManager; @@ -106,11 +105,13 @@ public void onDismissSheet() { /** * handle permission changed on click of selected permission + * * @param quickPermissionModelList * @param position */ private void handlePermissionChanged(List quickPermissionModelList, int position) { - final var permissionName = quickPermissionModelList.get(position).getPermissionName(); + final var permissionTextId = quickPermissionModelList.get(position).getTextId(); + final var permissionName = getContext().getString(permissionTextId); final var res = fileActivity.getResources(); int permissionFlag = 0; @@ -129,21 +130,16 @@ private void handlePermissionChanged(List quickPermissionM /** * prepare the list of permissions needs to be displayed on recyclerview - * @return */ private List getQuickPermissionList() { - int permissionArrayId = ocShare.isFolder() ? R.array.folder_share_permission_dialog_values : R.array.file_share_permission_dialog_values; - String[] permissionArray = fileActivity.getResources().getStringArray(permissionArrayId); - - // get the checked item position + final var result = QuickPermissionModel.Companion.getPermissionModel(ocShare.isFolder()); + String[] permissionArray = QuickPermissionModel.Companion.getPermissionArray(result, getContext()); int checkedItem = SharingMenuHelper.getPermissionCheckedItem(fileActivity, ocShare, permissionArray); - - final List quickPermissionModelList = new ArrayList<>(permissionArray.length); - for (int i = 0; i < permissionArray.length; i++) { - QuickPermissionModel quickPermissionModel = new QuickPermissionModel(permissionArray[i], checkedItem == i); - quickPermissionModelList.add(quickPermissionModel); + for (int i = 0; i < result.size(); i++) { + result.get(i).setSelected(checkedItem == i); } - return quickPermissionModelList; + + return result; } @Override @@ -154,6 +150,7 @@ protected void onStop() { public interface QuickPermissionSharingBottomSheetActions { void onQuickPermissionChanged(OCShare share, int permission); + void openShareDetail(OCShare share); } } diff --git a/app/src/main/res/drawable/ic_custom_permissions.xml b/app/src/main/res/drawable/ic_custom_permissions.xml new file mode 100644 index 000000000000..b02f8b939490 --- /dev/null +++ b/app/src/main/res/drawable/ic_custom_permissions.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/drawable/ic_eye.xml b/app/src/main/res/drawable/ic_eye.xml new file mode 100644 index 000000000000..9ea4987e52ac --- /dev/null +++ b/app/src/main/res/drawable/ic_eye.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_file_request.xml b/app/src/main/res/drawable/ic_file_request.xml new file mode 100644 index 000000000000..470d7d30b469 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_request.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/layout/item_quick_share_permissions.xml b/app/src/main/res/layout/item_quick_share_permissions.xml index efa183210751..d40064e490be 100644 --- a/app/src/main/res/layout/item_quick_share_permissions.xml +++ b/app/src/main/res/layout/item_quick_share_permissions.xml @@ -2,41 +2,23 @@ - + ~ SPDX-License-Identifier: AGPL-3.0-or-later + --> + - - - - - - + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:insetTop="0dp" + android:insetBottom="0dp" + android:minHeight="56dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + app:iconGravity="textStart" + app:iconPadding="12dp" /> \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index dd334efcd898..8641f4e9de73 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -26,18 +26,6 @@ @string/pref_instant_name_collision_policy_entries_cancel - - @string/link_share_view_only - @string/share_permission_can_edit - @string/link_share_file_request - @string/share_custom_permission - - - - @string/link_share_view_only - @string/link_share_editing - @string/share_custom_permission - @string/sub_folder_rule_month @string/sub_folder_rule_year From 5ff8996fc7fe46ae27bf11bfa1a0322d716ef91c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 12:06:11 +0200 Subject: [PATCH 053/110] set download limit for "Share link" Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index b209a04eb08c..73091a8db1d8 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -420,7 +420,7 @@ class FileDetailsSharingProcessFragment : } private fun updateFileDownloadLimitView() { - if (capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) { + if (shareType == ShareType.PUBLIC_LINK && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) { binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE val currentDownloadLimit = share?.fileDownloadLimit?.limit ?: capabilities.filesDownloadLimitDefault From 26c0902bb5f0f98dc0d5ac9a0144ffb61331fd8f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 12:54:14 +0200 Subject: [PATCH 054/110] use quick permission type Signed-off-by: alperozturk --- .../android/datamodel/QuickPermissionModel.kt | 49 ------------- .../quickPermission/QuickPermission.kt | 25 +++++++ .../quickPermission/QuickPermissionType.kt | 68 +++++++++++++++++++ .../adapter/QuickSharingPermissionsAdapter.kt | 14 ++-- .../android/ui/adapter/ShareeListAdapter.java | 20 +++++- .../fragment/FileDetailSharingFragment.java | 4 ++ ...ckSharingPermissionsBottomSheetDialog.java | 30 +++----- .../ui/fragment/util/SharingMenuHelper.java | 35 +++------- 8 files changed, 144 insertions(+), 101 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt create mode 100644 app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt create mode 100644 app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt diff --git a/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt b/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt deleted file mode 100644 index 8b57c511cedd..000000000000 --- a/app/src/main/java/com/owncloud/android/datamodel/QuickPermissionModel.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.owncloud.android.datamodel - -import android.content.Context -import com.owncloud.android.R - -data class QuickPermissionModel(val iconId: Int, val textId: Int, var isSelected: Boolean) { - companion object { - fun getPermissionModel(isFolder: Boolean): List = - if (isFolder) folderSharePermissions else fileSharePermissions - - fun getPermissionArray(permissions: List, context: Context): Array = - permissions.map { context.getString(it.textId) }.toTypedArray() - - private val folderSharePermissions = listOf( - QuickPermissionModel( - iconId = R.drawable.ic_eye, - textId = R.string.link_share_view_only, - isSelected = false - ), - QuickPermissionModel( - iconId = R.drawable.ic_edit, - textId = R.string.share_permission_can_edit, - isSelected = false - ), - QuickPermissionModel( - iconId = R.drawable.ic_file_request, - textId = R.string.link_share_file_request, - isSelected = false - ), - QuickPermissionModel( - iconId = R.drawable.ic_custom_permissions, - textId = R.string.share_custom_permission, - isSelected = false - ) - ) - - private const val FILE_REQUEST_INDEX = 2 - - private val fileSharePermissions = - folderSharePermissions.filterIndexed { index, _ -> index != FILE_REQUEST_INDEX } - } -} diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt new file mode 100644 index 000000000000..adf07d35fc51 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt @@ -0,0 +1,25 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.datamodel.quickPermission + +data class QuickPermission(val type: QuickPermissionType, val iconId: Int, val textId: Int, var isSelected: Boolean) { + companion object { + fun getPermissionModel(isFolder: Boolean, selectedType: QuickPermissionType): List { + val result = getFolderSharePermissions().toMutableList() + if (!isFolder) { + result.removeAt(FILE_REQUEST_INDEX) + } + result.find { it.type == selectedType }?.isSelected = true + return result + } + + private fun getFolderSharePermissions() = QuickPermissionType.getPermissions() + + private const val FILE_REQUEST_INDEX = 2 + } +} diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt new file mode 100644 index 000000000000..00cad7a33965 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt @@ -0,0 +1,68 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.datamodel.quickPermission + +import com.owncloud.android.R + +enum class QuickPermissionType { + NONE, VIEW_ONLY, CAN_EDIT, FILE_REQUEST, CUSTOM_PERMISSIONS; + + companion object { + fun getPermissions() = listOf( + VIEW_ONLY.getPermission(), + CAN_EDIT.getPermission(), + FILE_REQUEST.getPermission(), + CUSTOM_PERMISSIONS.getPermission() + ) + } + + fun getPermission(): QuickPermission { + return when(this) { + VIEW_ONLY -> { + QuickPermission( + type = this, + iconId = R.drawable.ic_eye, + textId = R.string.link_share_view_only, + isSelected = false + ) + } + CAN_EDIT -> { + QuickPermission( + type = this, + iconId = R.drawable.ic_edit, + textId = R.string.share_permission_can_edit, + isSelected = false + ) + } + FILE_REQUEST -> { + QuickPermission( + type = this, + iconId = R.drawable.ic_file_request, + textId = R.string.link_share_file_request, + isSelected = false + ) + } + CUSTOM_PERMISSIONS -> { + QuickPermission( + type = this, + iconId = R.drawable.ic_custom_permissions, + textId = R.string.share_custom_permission, + isSelected = false + ) + } + else -> { + QuickPermission( + type = this, + iconId = R.drawable.ic_unknown, + textId = R.string.unknown, + isSelected = false + ) + } + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index fd15d6d4fd3a..7da807904768 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -18,11 +18,11 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton import com.owncloud.android.R import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding -import com.owncloud.android.datamodel.QuickPermissionModel +import com.owncloud.android.datamodel.quickPermission.QuickPermission import com.owncloud.android.utils.theme.ViewThemeUtils class QuickSharingPermissionsAdapter( - private val quickPermissionList: MutableList, + private val quickPermissionList: MutableList, private val onPermissionChangeListener: QuickSharingPermissionViewHolder.OnPermissionChangeListener, private val viewThemeUtils: ViewThemeUtils ) : @@ -49,16 +49,16 @@ class QuickSharingPermissionsAdapter( private val viewThemeUtils: ViewThemeUtils ) : RecyclerView.ViewHolder(itemView) { - fun bindData(quickPermissionModel: QuickPermissionModel) { + fun bindData(quickPermission: QuickPermission) { val context = itemView.context - val permissionName = context.getString(quickPermissionModel.textId) + val permissionName = context.getString(quickPermission.textId) binding.run { quickPermissionButton.text = permissionName quickPermissionButton.iconGravity = MaterialButton.ICON_GRAVITY_START - quickPermissionButton.icon = ContextCompat.getDrawable(context, quickPermissionModel.iconId) + quickPermissionButton.icon = ContextCompat.getDrawable(context, quickPermission.iconId) - if (quickPermissionModel.isSelected) { + if (quickPermission.isSelected) { viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(quickPermissionButton) } } @@ -69,7 +69,7 @@ class QuickSharingPermissionsAdapter( itemView.setOnClickListener { if (isCustomPermission) { onPermissionChangeListener.onCustomPermissionSelected() - } else if (!quickPermissionModel.isSelected) { + } else if (!quickPermission.isSelected) { // if user select different options then only update the permission onPermissionChangeListener.onPermissionChanged(absoluteAdapterPosition) } else { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index 2b22b72050b9..8a3bb181afbb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -79,7 +79,25 @@ public ShareeListAdapter(FileActivity fileActivity, @Override public int getItemViewType(int position) { - return shares.get(position).getShareType().getValue(); + if (shares == null) { + return 0; + } + + if (position < 0 || position >= shares.size()) { + return 0; + } + + final var share = shares.get(position); + if (share == null) { + return 0; + } + + final var shareType = share.getShareType(); + if (shareType == null) { + return 0; + } + + return shareType.getValue(); } @NonNull diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index d5449ee2e445..c3599b79de3f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -178,6 +178,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, file.isEncrypted(), SharesType.INTERNAL); + internalShareeListAdapter.setHasStableIds(true); + binding.sharesListInternal.setAdapter(internalShareeListAdapter); binding.sharesListInternal.setLayoutManager(new LinearLayoutManager(requireContext())); @@ -190,6 +192,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, viewThemeUtils, file.isEncrypted(), SharesType.EXTERNAL); + + externalShareeListAdapter.setHasStableIds(true); binding.sharesListExternal.setAdapter(externalShareeListAdapter); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index a2e4fb73d0ca..22ae956f8e7b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -19,7 +19,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog; import com.owncloud.android.R; import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; -import com.owncloud.android.datamodel.QuickPermissionModel; +import com.owncloud.android.datamodel.quickPermission.QuickPermission; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter; @@ -76,9 +76,9 @@ protected void onCreate(Bundle savedInstanceState) { } private void setUpRecyclerView() { - List quickPermissionModelList = getQuickPermissionList(); + List quickPermissionList = getQuickPermissionList(); QuickSharingPermissionsAdapter adapter = new QuickSharingPermissionsAdapter( - quickPermissionModelList, + quickPermissionList, new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() { @Override public void onCustomPermissionSelected() { @@ -88,7 +88,7 @@ public void onCustomPermissionSelected() { @Override public void onPermissionChanged(int position) { - handlePermissionChanged(quickPermissionModelList, position); + handlePermissionChanged(quickPermissionList, position); } @Override @@ -104,13 +104,11 @@ public void onDismissSheet() { } /** - * handle permission changed on click of selected permission + * Handle permission changed on click of selected permission * - * @param quickPermissionModelList - * @param position */ - private void handlePermissionChanged(List quickPermissionModelList, int position) { - final var permissionTextId = quickPermissionModelList.get(position).getTextId(); + private void handlePermissionChanged(List quickPermissionList, int position) { + final var permissionTextId = quickPermissionList.get(position).getTextId(); final var permissionName = getContext().getString(permissionTextId); final var res = fileActivity.getResources(); @@ -129,17 +127,11 @@ private void handlePermissionChanged(List quickPermissionM } /** - * prepare the list of permissions needs to be displayed on recyclerview + * Prepare the list of permissions needs to be displayed on recyclerview */ - private List getQuickPermissionList() { - final var result = QuickPermissionModel.Companion.getPermissionModel(ocShare.isFolder()); - String[] permissionArray = QuickPermissionModel.Companion.getPermissionArray(result, getContext()); - int checkedItem = SharingMenuHelper.getPermissionCheckedItem(fileActivity, ocShare, permissionArray); - for (int i = 0; i < result.size(); i++) { - result.get(i).setSelected(checkedItem == i); - } - - return result; + private List getQuickPermissionList() { + final var selectedType = SharingMenuHelper.getSelectedType(ocShare); + return QuickPermission.Companion.getPermissionModel(ocShare.isFolder(), selectedType); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 72fd468953da..ada972103ef6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -14,6 +14,8 @@ import android.content.Context; import com.owncloud.android.R; +import com.owncloud.android.datamodel.quickPermission.QuickPermission; +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; @@ -86,35 +88,18 @@ public static String getPermissionName(Context context, OCShare share) { return null; } - /** - * method to get the current checked index from the list of permissions - * - */ - public static int getPermissionCheckedItem(Context context, OCShare share, String[] permissionArray) { - int permissionName; - - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - permissionName = share.isFolder() ? R.string.share_permission_can_edit : R.string.link_share_editing; - } else if (SharingMenuHelper.isReadOnly(share)) { - permissionName = R.string.link_share_view_only; + public static QuickPermissionType getSelectedType(OCShare share) { + if (SharingMenuHelper.isReadOnly(share)) { + return QuickPermissionType.VIEW_ONLY; + } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + return QuickPermissionType.CAN_EDIT; } else if (SharingMenuHelper.isFileDrop(share)) { - permissionName = R.string.link_share_file_request; + return QuickPermissionType.FILE_REQUEST; } else if (sharePermissionManager.isCustomPermission(share)) { - permissionName = R.string.share_custom_permission; - } else { - return 0; + return QuickPermissionType.CUSTOM_PERMISSIONS; } - return getPermissionIndexFromArray(context, permissionArray, permissionName); - } - - private static int getPermissionIndexFromArray(Context context, String[] permissionArray, int permissionName) { - for (int i = 0; i < permissionArray.length; i++) { - if (permissionArray[i].equalsIgnoreCase(context.getResources().getString(permissionName))) { - return i; - } - } - return 0; + return QuickPermissionType.NONE; } public static boolean canReshare(OCShare share) { From e9b5c6a764244dc9c58c1ccd3c45f57b93621d8e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 12:54:54 +0200 Subject: [PATCH 055/110] use quick permission type Signed-off-by: alperozturk --- .../datamodel/quickPermission/QuickPermissionType.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt index 00cad7a33965..3a8dd1083f08 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt @@ -10,7 +10,11 @@ package com.owncloud.android.datamodel.quickPermission import com.owncloud.android.R enum class QuickPermissionType { - NONE, VIEW_ONLY, CAN_EDIT, FILE_REQUEST, CUSTOM_PERMISSIONS; + NONE, + VIEW_ONLY, + CAN_EDIT, + FILE_REQUEST, + CUSTOM_PERMISSIONS; companion object { fun getPermissions() = listOf( @@ -22,7 +26,7 @@ enum class QuickPermissionType { } fun getPermission(): QuickPermission { - return when(this) { + return when (this) { VIEW_ONLY -> { QuickPermission( type = this, From 48a893b52ec15034ec12c1186847957eef436fa2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 13:05:00 +0200 Subject: [PATCH 056/110] remove redundant code Signed-off-by: alperozturk --- .../quickPermission/QuickPermission.kt | 18 ++--- .../quickPermission/QuickPermissionType.kt | 68 ++++--------------- .../adapter/QuickSharingPermissionsAdapter.kt | 4 +- ...ckSharingPermissionsBottomSheetDialog.java | 4 +- .../ui/fragment/util/SharingMenuHelper.java | 1 - 5 files changed, 23 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt index adf07d35fc51..d4489c921ec5 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt @@ -7,19 +7,15 @@ package com.owncloud.android.datamodel.quickPermission -data class QuickPermission(val type: QuickPermissionType, val iconId: Int, val textId: Int, var isSelected: Boolean) { +data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) { companion object { - fun getPermissionModel(isFolder: Boolean, selectedType: QuickPermissionType): List { - val result = getFolderSharePermissions().toMutableList() - if (!isFolder) { - result.removeAt(FILE_REQUEST_INDEX) + fun getPermissions(isFolder: Boolean, selectedType: QuickPermissionType): List { + return QuickPermissionType.getAvailablePermissions(isFolder).map { type -> + QuickPermission( + type = type, + isSelected = type == selectedType + ) } - result.find { it.type == selectedType }?.isSelected = true - return result } - - private fun getFolderSharePermissions() = QuickPermissionType.getPermissions() - - private const val FILE_REQUEST_INDEX = 2 } } diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt index 3a8dd1083f08..3214758ea507 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt @@ -9,64 +9,20 @@ package com.owncloud.android.datamodel.quickPermission import com.owncloud.android.R -enum class QuickPermissionType { - NONE, - VIEW_ONLY, - CAN_EDIT, - FILE_REQUEST, - CUSTOM_PERMISSIONS; +enum class QuickPermissionType( + val iconId: Int, + val textId: Int +) { + NONE(R.drawable.ic_unknown, R.string.unknown), + VIEW_ONLY(R.drawable.ic_eye, R.string.link_share_view_only), + CAN_EDIT(R.drawable.ic_edit, R.string.share_permission_can_edit), + FILE_REQUEST(R.drawable.ic_file_request, R.string.link_share_file_request), + CUSTOM_PERMISSIONS(R.drawable.ic_custom_permissions, R.string.share_custom_permission); companion object { - fun getPermissions() = listOf( - VIEW_ONLY.getPermission(), - CAN_EDIT.getPermission(), - FILE_REQUEST.getPermission(), - CUSTOM_PERMISSIONS.getPermission() - ) - } - - fun getPermission(): QuickPermission { - return when (this) { - VIEW_ONLY -> { - QuickPermission( - type = this, - iconId = R.drawable.ic_eye, - textId = R.string.link_share_view_only, - isSelected = false - ) - } - CAN_EDIT -> { - QuickPermission( - type = this, - iconId = R.drawable.ic_edit, - textId = R.string.share_permission_can_edit, - isSelected = false - ) - } - FILE_REQUEST -> { - QuickPermission( - type = this, - iconId = R.drawable.ic_file_request, - textId = R.string.link_share_file_request, - isSelected = false - ) - } - CUSTOM_PERMISSIONS -> { - QuickPermission( - type = this, - iconId = R.drawable.ic_custom_permissions, - textId = R.string.share_custom_permission, - isSelected = false - ) - } - else -> { - QuickPermission( - type = this, - iconId = R.drawable.ic_unknown, - textId = R.string.unknown, - isSelected = false - ) - } + fun getAvailablePermissions(isFolder: Boolean): List { + val permissions = listOf(VIEW_ONLY, CAN_EDIT, FILE_REQUEST, CUSTOM_PERMISSIONS) + return if (isFolder) permissions else permissions.filter { it != FILE_REQUEST } } } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index 7da807904768..2d27bea8ce5f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -51,12 +51,12 @@ class QuickSharingPermissionsAdapter( fun bindData(quickPermission: QuickPermission) { val context = itemView.context - val permissionName = context.getString(quickPermission.textId) + val permissionName = context.getString(quickPermission.type.textId) binding.run { quickPermissionButton.text = permissionName quickPermissionButton.iconGravity = MaterialButton.ICON_GRAVITY_START - quickPermissionButton.icon = ContextCompat.getDrawable(context, quickPermission.iconId) + quickPermissionButton.icon = ContextCompat.getDrawable(context, quickPermission.type.iconId) if (quickPermission.isSelected) { viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(quickPermissionButton) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 22ae956f8e7b..96d0c2ee85b9 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -108,7 +108,7 @@ public void onDismissSheet() { * */ private void handlePermissionChanged(List quickPermissionList, int position) { - final var permissionTextId = quickPermissionList.get(position).getTextId(); + final var permissionTextId = quickPermissionList.get(position).getType().getTextId(); final var permissionName = getContext().getString(permissionTextId); final var res = fileActivity.getResources(); @@ -131,7 +131,7 @@ private void handlePermissionChanged(List quickPermissionList, */ private List getQuickPermissionList() { final var selectedType = SharingMenuHelper.getSelectedType(ocShare); - return QuickPermission.Companion.getPermissionModel(ocShare.isFolder(), selectedType); + return QuickPermission.Companion.getPermissions(ocShare.isFolder(), selectedType); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index ada972103ef6..af1a695b3407 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -14,7 +14,6 @@ import android.content.Context; import com.owncloud.android.R; -import com.owncloud.android.datamodel.quickPermission.QuickPermission; import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; From 434a8adbbb67547634bf3f390e5f7f99ccc81d88 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 13:10:51 +0200 Subject: [PATCH 057/110] remove redundant code Signed-off-by: alperozturk --- .../android/datamodel/quickPermission/QuickPermission.kt | 9 ++++++++- .../android/ui/adapter/QuickSharingPermissionsAdapter.kt | 5 ++--- .../QuickSharingPermissionsBottomSheetDialog.java | 3 +-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt index d4489c921ec5..04d3bf08e5fa 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt @@ -7,15 +7,22 @@ package com.owncloud.android.datamodel.quickPermission +import android.content.Context +import android.graphics.drawable.Drawable +import androidx.core.content.ContextCompat + data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) { companion object { fun getPermissions(isFolder: Boolean, selectedType: QuickPermissionType): List { return QuickPermissionType.getAvailablePermissions(isFolder).map { type -> QuickPermission( type = type, - isSelected = type == selectedType + isSelected = (type == selectedType) ) } } } + + fun getText(context: Context): String = context.getString(type.textId) + fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, type.iconId) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index 2d27bea8ce5f..59328288ba00 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -13,7 +13,6 @@ package com.owncloud.android.ui.adapter import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton import com.owncloud.android.R @@ -51,12 +50,12 @@ class QuickSharingPermissionsAdapter( fun bindData(quickPermission: QuickPermission) { val context = itemView.context - val permissionName = context.getString(quickPermission.type.textId) + val permissionName = quickPermission.getText(context) binding.run { quickPermissionButton.text = permissionName quickPermissionButton.iconGravity = MaterialButton.ICON_GRAVITY_START - quickPermissionButton.icon = ContextCompat.getDrawable(context, quickPermission.type.iconId) + quickPermissionButton.icon = quickPermission.getIcon(context) if (quickPermission.isSelected) { viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(quickPermissionButton) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 96d0c2ee85b9..62d2debd90b1 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -108,8 +108,7 @@ public void onDismissSheet() { * */ private void handlePermissionChanged(List quickPermissionList, int position) { - final var permissionTextId = quickPermissionList.get(position).getType().getTextId(); - final var permissionName = getContext().getString(permissionTextId); + final var permissionName = quickPermissionList.get(position).getText(getContext()); final var res = fileActivity.getResources(); int permissionFlag = 0; From d9a4f06c23e94ba22acc96bcd200b40ca201a3f1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 17 Apr 2025 15:17:18 +0200 Subject: [PATCH 058/110] fix update Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 73091a8db1d8..e0f25f98be1a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -704,6 +704,11 @@ class FileDetailsSharingProcessFragment : } private fun updateShare() { + // empty string causing fails + if (share?.attributes?.isEmpty() == true) { + share?.attributes = null + } + fileOperationsHelper?.updateShareInformation( share, permission, From cf59bc865c98e13550bd895c5b29264944055115 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 5 May 2025 12:53:40 +0200 Subject: [PATCH 059/110] solve git conflicts Signed-off-by: alperozturk --- gradle/verification-metadata.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index d7da67a84957..bb78b5c57ea9 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -11503,6 +11503,14 @@ + + + + + + + + From 0e060d89a3c776b6010534c4b4bb8244d264b526 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 5 May 2025 14:07:09 +0200 Subject: [PATCH 060/110] update library Signed-off-by: alperozturk --- gradle/verification-metadata.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index bb78b5c57ea9..c217a0c43d54 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -11447,6 +11447,14 @@ + + + + + + + + From f284465b5601c37623ae7b2c884de0af17f77fae Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 6 May 2025 14:42:29 +0200 Subject: [PATCH 061/110] add hasFileRequestPermission Signed-off-by: alperozturk --- .../android/datamodel/quickPermission/QuickPermission.kt | 7 +++++-- .../datamodel/quickPermission/QuickPermissionType.kt | 4 ++-- .../android/ui/fragment/FileDetailSharingFragment.java | 8 +++++++- .../QuickSharingPermissionsBottomSheetDialog.java | 8 +++++--- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt index 04d3bf08e5fa..545b87b3c692 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt @@ -13,8 +13,11 @@ import androidx.core.content.ContextCompat data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) { companion object { - fun getPermissions(isFolder: Boolean, selectedType: QuickPermissionType): List { - return QuickPermissionType.getAvailablePermissions(isFolder).map { type -> + fun getPermissions( + hasFileRequestPermission: Boolean, + selectedType: QuickPermissionType + ): List { + return QuickPermissionType.getAvailablePermissions(hasFileRequestPermission).map { type -> QuickPermission( type = type, isSelected = (type == selectedType) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt index 3214758ea507..0b57984f39ed 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt @@ -20,9 +20,9 @@ enum class QuickPermissionType( CUSTOM_PERMISSIONS(R.drawable.ic_custom_permissions, R.string.share_custom_permission); companion object { - fun getAvailablePermissions(isFolder: Boolean): List { + fun getAvailablePermissions(hasFileRequestPermission: Boolean): List { val permissions = listOf(VIEW_ONLY, CAN_EDIT, FILE_REQUEST, CUSTOM_PERMISSIONS) - return if (isFolder) permissions else permissions.filter { it != FILE_REQUEST } + return if (hasFileRequestPermission) permissions else permissions.filter { it != FILE_REQUEST } } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index c3599b79de3f..6f573ce33bcc 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -60,6 +60,7 @@ import com.owncloud.android.ui.asynctasks.RetrieveHoverCardAsyncTask; import com.owncloud.android.ui.dialog.SharePasswordDialogFragment; import com.owncloud.android.ui.fragment.util.FileDetailSharingFragmentHelper; +import com.owncloud.android.ui.fragment.util.SharePermissionManager; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.utils.ClipboardUtil; import com.owncloud.android.utils.DisplayUtils; @@ -104,6 +105,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda private ShareeListAdapter internalShareeListAdapter; private ShareeListAdapter externalShareeListAdapter; + private final SharePermissionManager sharePermissionManager = new SharePermissionManager(); @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @@ -424,7 +426,11 @@ public void showSharingMenuActionSheet(OCShare share) { */ @Override public void showPermissionsDialog(OCShare share) { - new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show(); + boolean hasFileRequestPermission = false; + if (share.isFolder()) { + hasFileRequestPermission = sharePermissionManager.hasPermission(share.getPermissions(), OCShare.CREATE_PERMISSION_FLAG); + } + new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils, hasFileRequestPermission).show(); } /** diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 62d2debd90b1..b3099d132a12 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -44,16 +44,19 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog private final FileActivity fileActivity; private final OCShare ocShare; private final ViewThemeUtils viewThemeUtils; + private final boolean hasFileRequestPermission; public QuickSharingPermissionsBottomSheetDialog(FileActivity fileActivity, QuickPermissionSharingBottomSheetActions actions, OCShare ocShare, - ViewThemeUtils viewThemeUtils) { + ViewThemeUtils viewThemeUtils, + boolean hasFileRequestPermission) { super(fileActivity); this.actions = actions; this.ocShare = ocShare; this.fileActivity = fileActivity; this.viewThemeUtils = viewThemeUtils; + this.hasFileRequestPermission = hasFileRequestPermission; } @Override @@ -105,7 +108,6 @@ public void onDismissSheet() { /** * Handle permission changed on click of selected permission - * */ private void handlePermissionChanged(List quickPermissionList, int position) { final var permissionName = quickPermissionList.get(position).getText(getContext()); @@ -130,7 +132,7 @@ private void handlePermissionChanged(List quickPermissionList, */ private List getQuickPermissionList() { final var selectedType = SharingMenuHelper.getSelectedType(ocShare); - return QuickPermission.Companion.getPermissions(ocShare.isFolder(), selectedType); + return QuickPermission.Companion.getPermissions(hasFileRequestPermission, selectedType); } @Override From 7a75b75d4c294596ee849afff1642203298f0d65 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 6 May 2025 16:29:46 +0200 Subject: [PATCH 062/110] check hasFileRequestPermission Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 40 +++++++++--------- .../com/nextcloud/utils/OCShareExtensions.kt | 15 +++++++ .../ui/adapter/LinkShareViewHolder.java | 4 +- .../fragment/FileDetailSharingFragment.java | 6 +-- .../FileDetailsSharingProcessFragment.kt | 42 ++++++++++++------- ...ckSharingPermissionsBottomSheetDialog.java | 8 ++-- .../ui/fragment/util/SharingMenuHelper.java | 8 ++-- .../file_details_sharing_process_fragment.xml | 3 +- app/src/main/res/values/strings.xml | 1 - 9 files changed, 76 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 6170d7835f2e..ac8c211e6b78 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -339,7 +339,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) @@ -347,7 +347,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) goBack() // upload and editing @@ -355,15 +355,15 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) goBack() - // file drop + // file request publicShare.permissions = 4 openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isChecked())) goBack() // password protection @@ -486,7 +486,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) @@ -616,7 +616,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(not(isDisplayed()))) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(not(isDisplayed()))) onView( ViewMatchers.withId(R.id.share_process_hide_download_checkbox) ).check(matches(not(isDisplayed()))) @@ -747,7 +747,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isDisplayed())) onView( ViewMatchers.withId(R.id.share_process_hide_download_checkbox) ).check(matches(not(isDisplayed()))) @@ -762,7 +762,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) goBack() // allow upload & editing @@ -770,15 +770,15 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) goBack() - // file drop + // file request userShare.permissions = 4 openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.file_drop_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isChecked())) goBack() // set expiration date @@ -940,27 +940,27 @@ class FileDetailSharingFragmentIT : AbstractIT() { val share = OCShare().apply { permissions = 4 } - assertTrue(SharingMenuHelper.isFileDrop(share)) + assertTrue(SharingMenuHelper.isFileRequest(share)) share.permissions = NO_PERMISSION - assertFalse(SharingMenuHelper.isFileDrop(share)) + assertFalse(SharingMenuHelper.isFileRequest(share)) share.permissions = READ_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isFileDrop(share)) + assertFalse(SharingMenuHelper.isFileRequest(share)) share.permissions = CREATE_PERMISSION_FLAG - assertTrue(SharingMenuHelper.isFileDrop(share)) + assertTrue(SharingMenuHelper.isFileRequest(share)) share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isFileDrop(share)) + assertFalse(SharingMenuHelper.isFileRequest(share)) share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isFileDrop(share)) + assertFalse(SharingMenuHelper.isFileRequest(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - assertFalse(SharingMenuHelper.isFileDrop(share)) + assertFalse(SharingMenuHelper.isFileRequest(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE - assertFalse(SharingMenuHelper.isFileDrop(share)) + assertFalse(SharingMenuHelper.isFileRequest(share)) } } diff --git a/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt b/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt new file mode 100644 index 000000000000..bfa654f13725 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt @@ -0,0 +1,15 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils + +import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.ShareType + +fun OCShare.hasFileRequestPermission(): Boolean { + return (isFolder && (shareType == ShareType.PUBLIC_LINK || shareType == ShareType.EMAIL)) +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index b2e70da44dd8..e628251c1e94 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -67,7 +67,9 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { String text = String.format(context.getString(R.string.share_link_with_label), publicShare.getLabel()); binding.name.setText(text); } else { - if (SharingMenuHelper.isSecureFileDrop(publicShare)) { + if (SharingMenuHelper.isFileRequest(publicShare)) { + binding.name.setText(context.getResources().getString(R.string.link_share_file_request)); + } else if (SharingMenuHelper.isSecureFileDrop(publicShare)) { binding.name.setText(context.getResources().getString(R.string.share_permission_secure_file_drop)); } else { binding.name.setText(R.string.share_link); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 6f573ce33bcc..234897b0d0ba 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -426,11 +426,7 @@ public void showSharingMenuActionSheet(OCShare share) { */ @Override public void showPermissionsDialog(OCShare share) { - boolean hasFileRequestPermission = false; - if (share.isFolder()) { - hasFileRequestPermission = sharePermissionManager.hasPermission(share.getPermissions(), OCShare.CREATE_PERMISSION_FLAG); - } - new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils, hasFileRequestPermission).show(); + new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show(); } /** diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index e0f25f98be1a..9a4abd956d2c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -196,9 +196,15 @@ class FileDetailsSharingProcessFragment : implementClickEvents() setCheckboxStates() themeView() + setVisibilitiesOfShareOption() } - private fun isFolder(): Boolean = file?.isFolder == true || share?.isFolder == true + private fun setVisibilitiesOfShareOption() { + binding.run { + shareAllowDownloadAndSyncCheckbox.setVisibleIf(!isPublicShare()) + fileRequestRadioButton.setVisibleIf(isPublicShare() && isFolder()) + } + } private fun themeView() { viewThemeUtils.platform.run { @@ -208,14 +214,16 @@ class FileDetailsSharingProcessFragment : themeRadioButton(viewOnlyRadioButton) themeRadioButton(editingRadioButton) - themeRadioButton(fileDropRadioButton) themeRadioButton(customPermissionRadioButton) - if (shareType != ShareType.PUBLIC_LINK) { - shareAllowDownloadAndSyncCheckbox.visibility = View.VISIBLE + if (!isPublicShare()) { themeCheckbox(shareAllowDownloadAndSyncCheckbox) } + if (isPublicShare() && isFolder()) { + themeRadioButton(fileRequestRadioButton) + } + themeCheckbox(shareReadCheckbox) themeCheckbox(shareCreateCheckbox) themeCheckbox(shareEditCheckbox) @@ -278,11 +286,11 @@ class FileDetailsSharingProcessFragment : private fun setupModificationUI() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() - // custom permissions / read only / allow upload and editing / file drop + // custom permissions / read only / allow upload and editing / file request binding.run { when { SharingMenuHelper.isUploadAndEditingAllowed(share) -> editingRadioButton.isChecked = true - SharingMenuHelper.isFileDrop(share) && share?.isFolder == true -> fileDropRadioButton.isChecked = true + SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = true SharingMenuHelper.isReadOnly(share) -> viewOnlyRadioButton.isChecked = true else -> { if (sharePermissionManager.isCustomPermission(share) || @@ -300,7 +308,7 @@ class FileDetailsSharingProcessFragment : // show different text for link share and other shares // because we have link to share in Public Link binding.shareProcessBtnNext.text = getString( - if (shareType == ShareType.PUBLIC_LINK) { + if (isPublicShare()) { R.string.share_copy_link } else { R.string.common_confirm @@ -393,7 +401,7 @@ class FileDetailsSharingProcessFragment : shareProcessSetPasswordSwitch.visibility = View.VISIBLE if (share != null) { - if (SharingMenuHelper.isFileDrop(share)) { + if (SharingMenuHelper.isFileRequest(share)) { shareProcessHideDownloadCheckbox.visibility = View.GONE } else { shareProcessHideDownloadCheckbox.visibility = View.VISIBLE @@ -420,7 +428,7 @@ class FileDetailsSharingProcessFragment : } private fun updateFileDownloadLimitView() { - if (shareType == ShareType.PUBLIC_LINK && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) { + if (isPublicShare() && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) { binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE val currentDownloadLimit = share?.fileDownloadLimit?.limit ?: capabilities.filesDownloadLimitDefault @@ -435,16 +443,14 @@ class FileDetailsSharingProcessFragment : private fun updateViewForFile() { binding.run { editingRadioButton.text = getString(R.string.link_share_editing) - fileDropRadioButton.visibility = View.GONE } } private fun updateViewForFolder() { binding.run { editingRadioButton.text = getString(R.string.share_permission_can_edit) - fileDropRadioButton.visibility = View.VISIBLE + if (isSecureShare) { - fileDropRadioButton.visibility = View.GONE shareCheckbox.visibility = View.GONE shareProcessSetExpDateSwitch.visibility = View.GONE } @@ -511,7 +517,7 @@ class FileDetailsSharingProcessFragment : permission = sharePermissionManager.getMaximumPermission(isFolder()) } - R.id.file_drop_radio_button -> { + R.id.file_request_radio_button -> { permission = OCShare.CREATE_PERMISSION_FLAG } @@ -552,7 +558,7 @@ class FileDetailsSharingProcessFragment : } } - if (shareType != ShareType.PUBLIC_LINK) { + if (!isPublicShare()) { shareAllowDownloadAndSyncCheckbox.isChecked = isAllowDownloadAndSyncEnabled(share) } } @@ -574,7 +580,7 @@ class FileDetailsSharingProcessFragment : checkbox.setOnCheckedChangeListener { _, isChecked -> togglePermission(isChecked, flag) } } - if (shareType != ShareType.PUBLIC_LINK) { + if (!isPublicShare()) { binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> share?.attributes = sharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) } @@ -770,4 +776,10 @@ class FileDetailsSharingProcessFragment : override fun onDateUnSet() { binding.shareProcessSetExpDateSwitch.isChecked = false } + + // region Helpers + private fun isFolder(): Boolean = file?.isFolder == true || share?.isFolder == true + + private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK) + // endregion } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index b3099d132a12..f1689aff1d29 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -17,10 +17,12 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.nextcloud.utils.OCShareExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; import com.owncloud.android.datamodel.quickPermission.QuickPermission; import com.owncloud.android.lib.resources.shares.OCShare; +import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter; import com.owncloud.android.ui.fragment.util.SharingMenuHelper; @@ -44,19 +46,16 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog private final FileActivity fileActivity; private final OCShare ocShare; private final ViewThemeUtils viewThemeUtils; - private final boolean hasFileRequestPermission; public QuickSharingPermissionsBottomSheetDialog(FileActivity fileActivity, QuickPermissionSharingBottomSheetActions actions, OCShare ocShare, - ViewThemeUtils viewThemeUtils, - boolean hasFileRequestPermission) { + ViewThemeUtils viewThemeUtils) { super(fileActivity); this.actions = actions; this.ocShare = ocShare; this.fileActivity = fileActivity; this.viewThemeUtils = viewThemeUtils; - this.hasFileRequestPermission = hasFileRequestPermission; } @Override @@ -132,6 +131,7 @@ private void handlePermissionChanged(List quickPermissionList, */ private List getQuickPermissionList() { final var selectedType = SharingMenuHelper.getSelectedType(ocShare); + final var hasFileRequestPermission = OCShareExtensionsKt.hasFileRequestPermission(ocShare); return QuickPermission.Companion.getPermissions(hasFileRequestPermission, selectedType); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index af1a695b3407..229133b3e009 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -53,7 +53,7 @@ public static boolean isReadOnly(OCShare share) { return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == READ_PERMISSION_FLAG; } - public static boolean isFileDrop(OCShare share) { + public static boolean isFileRequest(OCShare share) { if (share.getPermissions() == NO_PERMISSION) { return false; } @@ -80,8 +80,8 @@ public static String getPermissionName(Context context, OCShare share) { return res.getString(R.string.share_custom_permission); } else if (SharingMenuHelper.isSecureFileDrop(share)) { return res.getString(R.string.share_permission_secure_file_drop); - } else if (SharingMenuHelper.isFileDrop(share)) { - return res.getString(R.string.share_permission_file_drop); + } else if (SharingMenuHelper.isFileRequest(share)) { + return res.getString(R.string.link_share_file_request); } return null; @@ -92,7 +92,7 @@ public static QuickPermissionType getSelectedType(OCShare share) { return QuickPermissionType.VIEW_ONLY; } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { return QuickPermissionType.CAN_EDIT; - } else if (SharingMenuHelper.isFileDrop(share)) { + } else if (SharingMenuHelper.isFileRequest(share)) { return QuickPermissionType.FILE_REQUEST; } else if (sharePermissionManager.isCustomPermission(share)) { return QuickPermissionType.CUSTOM_PERMISSIONS; diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 30f4e7f03a65..90062427a9e8 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -66,8 +66,9 @@ android:text="@string/share_custom_permission" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 50cc49e5c331..a69a2e214f60 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1167,7 +1167,6 @@ Please choose a template and enter a file name. View only Can edit - File drop Secure file drop Share permissions Next From 17b3293bba976390db4681a867a4f45b5320dfb0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 13:34:43 +0200 Subject: [PATCH 063/110] fix unshare Signed-off-by: alperozturk --- .../android/operations/UnshareOperation.java | 10 ++-- .../android/ui/adapter/ShareeListAdapter.java | 20 ++++---- .../fragment/FileDetailSharingFragment.java | 47 ++++++++++--------- .../FileDetailsSharingProcessFragment.kt | 2 +- 4 files changed, 42 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UnshareOperation.java b/app/src/main/java/com/owncloud/android/operations/UnshareOperation.java index bdfc32923a97..8168c0dd1197 100644 --- a/app/src/main/java/com/owncloud/android/operations/UnshareOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UnshareOperation.java @@ -113,6 +113,8 @@ protected RemoteOperationResult run(OwnCloudClient client) { RemoveShareRemoteOperation operation = new RemoveShareRemoteOperation(share.getRemoteId()); result = operation.execute(client); + boolean isFileExists = existsFile(client, file.getRemotePath()); + boolean isShareExists = getStorageManager().getShareById(shareId) != null; if (result.isSuccess()) { // E2E: unlock folder @@ -140,10 +142,12 @@ protected RemoteOperationResult run(OwnCloudClient client) { getStorageManager().saveFile(file); getStorageManager().removeShare(share); - - } else if (result.getCode() != ResultCode.MAINTENANCE_MODE && !existsFile(client, file.getRemotePath())) { - // unshare failed because file was deleted before + } else if (result.getCode() != ResultCode.MAINTENANCE_MODE && !isFileExists) { + // UnShare failed because file was deleted before getStorageManager().removeFile(file, true, true); + } else if (isShareExists && result.getCode() == ResultCode.FILE_NOT_FOUND) { + // UnShare failed because share was deleted before + getStorageManager().removeShare(share); } } else { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index 8a3bb181afbb..f94df8393473 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -33,7 +33,9 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -169,6 +171,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi return; } + if (holder instanceof LinkShareViewHolder publicShareViewHolder) { publicShareViewHolder.bind(share, listener); } else if (holder instanceof InternalShareViewHolder internalShareViewHolder) { @@ -204,7 +207,7 @@ public int getItemCount() { @SuppressLint("NotifyDataSetChanged") public void toggleShowAll() { - this.showAll = !this.showAll; + showAll = !showAll; notifyDataSetChanged(); } @@ -219,6 +222,12 @@ public void addShares(List sharesToAdd) { notifyDataSetChanged(); } + @SuppressLint("NotifyDataSetChanged") + public void removeAll() { + shares.clear(); + notifyDataSetChanged(); + } + @Override public void avatarGenerated(Drawable avatarDrawable, Object callContext) { if (callContext instanceof ImageView iv) { @@ -273,13 +282,4 @@ protected final void sortShares() { public List getShares() { return shares; } - - public void removeNewPublicShare() { - for (OCShare share : shares) { - if (share.getShareType() == ShareType.NEW_PUBLIC_LINK) { - shares.remove(share); - break; - } - } - } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 234897b0d0ba..a48df64bbc3c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -23,6 +23,7 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.provider.ContactsContract; import android.text.InputType; @@ -60,7 +61,6 @@ import com.owncloud.android.ui.asynctasks.RetrieveHoverCardAsyncTask; import com.owncloud.android.ui.dialog.SharePasswordDialogFragment; import com.owncloud.android.ui.fragment.util.FileDetailSharingFragmentHelper; -import com.owncloud.android.ui.fragment.util.SharePermissionManager; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.utils.ClipboardUtil; import com.owncloud.android.utils.DisplayUtils; @@ -69,6 +69,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.inject.Inject; @@ -105,7 +107,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda private ShareeListAdapter internalShareeListAdapter; private ShareeListAdapter externalShareeListAdapter; - private final SharePermissionManager sharePermissionManager = new SharePermissionManager(); @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @@ -220,10 +221,11 @@ public void onAttach(@NonNull Context context) { if (!(getActivity() instanceof FileActivity)) { throw new IllegalArgumentException("Calling activity must be of type FileActivity"); } + try { onEditShareListener = (OnEditShareListener) context; - } catch (Exception ignored) { - throw new IllegalArgumentException("Calling activity must implement the interface", ignored); + } catch (Exception e) { + throw new IllegalArgumentException("Calling activity must implement the interface" + e); } } @@ -523,7 +525,8 @@ public void refreshSharesFromDB() { DisplayUtils.showSnackMessage(getView(), getString(R.string.could_not_retrieve_shares)); return; } - internalShareeListAdapter.getShares().clear(); + + internalShareeListAdapter.removeAll(); // to show share with users/groups info List shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(), @@ -550,25 +553,24 @@ public void refreshSharesFromDB() { } internalShareeListAdapter.addShares(internalShares); + ViewExtensionsKt.setVisibleIf(binding.sharesListInternalShowAll, internalShareeListAdapter.getShares().size() > 3); + addExternalAndInternalShares(externalShares); + ViewExtensionsKt.setVisibleIf(binding.sharesListExternalShowAll, externalShareeListAdapter.getShares().size() > 3); + } - ViewExtensionsKt.setVisibleIf(binding.sharesListInternalShowAll, - internalShareeListAdapter.getShares().size() > 3 - ); - - externalShareeListAdapter.getShares().clear(); - - // Get public share - List publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), - ShareType.PUBLIC_LINK, - ""); - - externalShareeListAdapter.addShares(externalShares); - - externalShareeListAdapter.addShares(publicShares); + private void addExternalAndInternalShares(List externalShares) { + List publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), ShareType.PUBLIC_LINK, ""); - ViewExtensionsKt.setVisibleIf(binding.sharesListExternalShowAll, - externalShareeListAdapter.getShares().size() > 3 - ); + externalShareeListAdapter.removeAll(); + Stream combinedStream = Stream.concat(externalShares.stream(), publicShares.stream()) + .distinct(); + List combinedShares; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + combinedShares = combinedStream.toList(); + } else { + combinedShares = combinedStream.collect(Collectors.toList()); + } + externalShareeListAdapter.addShares(combinedShares); } private void checkContactPermission() { @@ -656,7 +658,6 @@ public void advancedPermissions(OCShare share) { modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION); } - @Override public void sendNewEmail(OCShare share) { modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_NOTE); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 9a4abd956d2c..3a0d75ab7e0a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -778,7 +778,7 @@ class FileDetailsSharingProcessFragment : } // region Helpers - private fun isFolder(): Boolean = file?.isFolder == true || share?.isFolder == true + private fun isFolder(): Boolean = (file?.isFolder == true || share?.isFolder == true) private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK) // endregion From 474512f395e7989ab8743f2de85e03748d0bc02c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 13:53:11 +0200 Subject: [PATCH 064/110] add missing ShareeListAdapter for unShare Signed-off-by: alperozturk --- .../android/ui/adapter/ShareeListAdapter.java | 8 +++++--- .../ui/fragment/FileDetailSharingFragment.java | 16 +++++++++------- .../ui/helpers/FileOperationsHelper.java | 17 +++++++---------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index f94df8393473..3b066d803bc3 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -244,10 +244,12 @@ public boolean shouldCallGeneratedCallback(String tag, Object callContext) { return false; } - @SuppressLint("NotifyDataSetChanged") public void remove(OCShare share) { - shares.remove(share); - notifyDataSetChanged(); + int position = shares.indexOf(share); + if (position != -1) { + shares.remove(position); + notifyItemRemoved(position); + } } /** diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index a48df64bbc3c..b885c1aefe6f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -468,8 +468,8 @@ private void refreshUiFromDB() { setupView(); } - private void unshareWith(OCShare share) { - fileOperationsHelper.unshareShare(file, share); + private void unShareWith(OCShare share) { + fileOperationsHelper.unShareShare(file, share); } /** @@ -665,13 +665,15 @@ public void sendNewEmail(OCShare share) { @Override public void unShare(OCShare share) { - unshareWith(share); - ShareeListAdapter adapter = (ShareeListAdapter) binding.sharesListInternal.getAdapter(); - if (adapter == null) { + unShareWith(share); + + if (binding.sharesListInternal.getAdapter() instanceof ShareeListAdapter adapter) { + adapter.remove(share); + } else if (binding.sharesListExternal.getAdapter() instanceof ShareeListAdapter adapter) { + adapter.remove(share); + } else { DisplayUtils.showSnackMessage(getView(), getString(R.string.failed_update_ui)); - return; } - adapter.remove(share); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 3357e98bc5ce..211dcfaec3bc 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -590,16 +590,13 @@ public void restoreFileVersion(FileVersion fileVersion) { * * @param file The file to unshare. */ - public void unshareShare(OCFile file, OCShare share) { - - // Unshare the file: Create the intent - Intent unshareService = new Intent(fileActivity, OperationsService.class); - unshareService.setAction(OperationsService.ACTION_UNSHARE); - unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); - unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath()); - unshareService.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId()); - - queueShareIntent(unshareService); + public void unShareShare(OCFile file, OCShare share) { + Intent intent = new Intent(fileActivity, OperationsService.class); + intent.setAction(OperationsService.ACTION_UNSHARE); + intent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); + intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath()); + intent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId()); + queueShareIntent(intent); } private void queueShareIntent(Intent shareIntent) { From 3aba7bd4529c3075a84e1d174b977f7d6869390f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 14:11:38 +0200 Subject: [PATCH 065/110] show fail message only for download limit and check canSetDownloadLimit before updating Signed-off-by: alperozturk --- .../operations/UpdateShareInfoOperation.java | 6 +++--- .../owncloud/android/ui/activity/FileActivity.java | 4 +++- .../fragment/FileDetailsSharingProcessFragment.kt | 13 +++++++++---- app/src/main/res/values/strings.xml | 1 + 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java index 538194c39d58..1c078c20045b 100644 --- a/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UpdateShareInfoOperation.java @@ -79,7 +79,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (share == null) { // TODO try to get remote share before failing? - return new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND); + return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND); } // Update remote share @@ -96,10 +96,10 @@ protected RemoteOperationResult run(OwnCloudClient client) { updateOp.setLabel(label); updateOp.setAttributes(attributes); - RemoteOperationResult result = updateOp.execute(client); + var result = updateOp.execute(client); if (result.isSuccess()) { - RemoteOperation getShareOp = new GetShareRemoteOperation(share.getRemoteId()); + final var getShareOp = new GetShareRemoteOperation(share.getRemoteId()); result = getShareOp.execute(client); //only update the share in storage if shareId is available diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index d78a98bddf46..b6c93efd0df4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -426,8 +426,10 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe onCreateShareViaLinkOperationFinish((CreateShareViaLinkOperation) operation, result); } else if (operation instanceof CreateShareWithShareeOperation) { onUpdateShareInformation(result, R.string.sharee_add_failed); - } else if (operation instanceof UpdateShareViaLinkOperation || operation instanceof UpdateShareInfoOperation || operation instanceof SetFilesDownloadLimitOperation) { + } else if (operation instanceof UpdateShareViaLinkOperation || operation instanceof UpdateShareInfoOperation) { onUpdateShareInformation(result, R.string.updating_share_failed); + } else if (operation instanceof SetFilesDownloadLimitOperation) { + onUpdateShareInformation(result, R.string.set_download_limit_failed); } else if (operation instanceof UpdateSharePermissionsOperation) { onUpdateShareInformation(result, R.string.updating_share_failed); } else if (operation instanceof UnshareOperation) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 3a0d75ab7e0a..a0d702df5f63 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -176,7 +176,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: sharePermissionManager.getMaximumPermission(isFolder()) + ?: sharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -290,7 +290,9 @@ class FileDetailsSharingProcessFragment : binding.run { when { SharingMenuHelper.isUploadAndEditingAllowed(share) -> editingRadioButton.isChecked = true - SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = true + SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = + true + SharingMenuHelper.isReadOnly(share) -> viewOnlyRadioButton.isChecked = true else -> { if (sharePermissionManager.isCustomPermission(share) || @@ -428,7 +430,7 @@ class FileDetailsSharingProcessFragment : } private fun updateFileDownloadLimitView() { - if (isPublicShare() && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) { + if (canSetDownloadLimit()) { binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE val currentDownloadLimit = share?.fileDownloadLimit?.limit ?: capabilities.filesDownloadLimitDefault @@ -724,7 +726,7 @@ class FileDetailsSharingProcessFragment : binding.shareProcessChangeName.text.toString().trim() ) - if (capabilities.filesDownloadLimit.isTrue) { + if (canSetDownloadLimit()) { val downloadLimitInput = binding.shareProcessSetDownloadLimitInput.text.toString().trim() val downloadLimit = if (binding.shareProcessSetDownloadLimitSwitch.isChecked && downloadLimitInput.isNotEmpty()) { @@ -780,6 +782,9 @@ class FileDetailsSharingProcessFragment : // region Helpers private fun isFolder(): Boolean = (file?.isFolder == true || share?.isFolder == true) + private fun canSetDownloadLimit(): Boolean = + (isPublicShare() && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) + private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK) // endregion } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a69a2e214f60..a68c808ee70c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1331,6 +1331,7 @@ Due to new restrictions imposed by Google, we have been forced to remove an important permission. We are currently working with Google to resolve this issue and restore full functionality.\n\nTo re-enable auto upload for new photos and videos:\nSelect \"Allow all\" in the following dialogue or the system settings.\nAllow media location when prompted, as this allows Nextcloud to store location data when uploading images.\n\nThe permissions dialogue is only displayed when necessary. If in doubt, check the system settings.\n\nAuto upload will only be able to upload image and video files when using the Google Play version of the Nextcloud app.\n\nPlease check for any files that may not have been uploaded since December 2024. Manual intervention required to re-enable auto-upload Set download limit + Unable to set download limit. Please check capabilities. Download limit %1$d download remaining From ef50fcaba8e7a9c5244c7964fff740625b5bcaae Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 14:17:55 +0200 Subject: [PATCH 066/110] mergeDistinctByToken Signed-off-by: alperozturk --- .../com/nextcloud/utils/OCShareExtensions.kt | 4 ++++ .../ui/fragment/FileDetailSharingFragment.java | 18 ++++-------------- ...ickSharingPermissionsBottomSheetDialog.java | 1 - 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt b/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt index bfa654f13725..5952383a870e 100644 --- a/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt @@ -13,3 +13,7 @@ import com.owncloud.android.lib.resources.shares.ShareType fun OCShare.hasFileRequestPermission(): Boolean { return (isFolder && (shareType == ShareType.PUBLIC_LINK || shareType == ShareType.EMAIL)) } + +fun List.mergeDistinctByToken(other: List): List { + return (this + other).distinctBy { it.token } +} diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index b885c1aefe6f..133bcec97a69 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -23,7 +23,6 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.ContactsContract; import android.text.InputType; @@ -36,6 +35,7 @@ import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.network.ClientFactory; +import com.nextcloud.utils.OCShareExtensionsKt; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; @@ -69,8 +69,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.inject.Inject; @@ -559,18 +557,10 @@ public void refreshSharesFromDB() { } private void addExternalAndInternalShares(List externalShares) { - List publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), ShareType.PUBLIC_LINK, ""); - + final var publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), ShareType.PUBLIC_LINK, ""); externalShareeListAdapter.removeAll(); - Stream combinedStream = Stream.concat(externalShares.stream(), publicShares.stream()) - .distinct(); - List combinedShares; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - combinedShares = combinedStream.toList(); - } else { - combinedShares = combinedStream.collect(Collectors.toList()); - } - externalShareeListAdapter.addShares(combinedShares); + final var shares = OCShareExtensionsKt.mergeDistinctByToken(externalShares, publicShares); + externalShareeListAdapter.addShares(shares); } private void checkContactPermission() { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index f1689aff1d29..ec40603c2fa6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -22,7 +22,6 @@ import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; import com.owncloud.android.datamodel.quickPermission.QuickPermission; import com.owncloud.android.lib.resources.shares.OCShare; -import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter; import com.owncloud.android.ui.fragment.util.SharingMenuHelper; From 268ca8d458e13aabdba594dc665d3794fee760cd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 14:19:31 +0200 Subject: [PATCH 067/110] better function naming Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailSharingFragment.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 133bcec97a69..8cde8a65b0ac 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -552,11 +552,12 @@ public void refreshSharesFromDB() { internalShareeListAdapter.addShares(internalShares); ViewExtensionsKt.setVisibleIf(binding.sharesListInternalShowAll, internalShareeListAdapter.getShares().size() > 3); - addExternalAndInternalShares(externalShares); + + addExternalAndPublicShares(externalShares); ViewExtensionsKt.setVisibleIf(binding.sharesListExternalShowAll, externalShareeListAdapter.getShares().size() > 3); } - private void addExternalAndInternalShares(List externalShares) { + private void addExternalAndPublicShares(List externalShares) { final var publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), ShareType.PUBLIC_LINK, ""); externalShareeListAdapter.removeAll(); final var shares = OCShareExtensionsKt.mergeDistinctByToken(externalShares, publicShares); From 12acf3b4b8d2aa1b3929a74c0e623dae70043d9d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 15:03:58 +0200 Subject: [PATCH 068/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailSharingFragmentIT.kt | 8 ++++++-- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 7 ++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index ac8c211e6b78..0b52076af8bd 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -486,7 +486,9 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.`@+id/file_request_radio_button`) + ).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) @@ -616,7 +618,9 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(not(isDisplayed()))) + onView( + ViewMatchers.withId(R.id.`@+id/file_request_radio_button`) + ).check(matches(not(isDisplayed()))) onView( ViewMatchers.withId(R.id.share_process_hide_download_checkbox) ).check(matches(not(isDisplayed()))) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index a0d702df5f63..0d4baf3695a5 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -176,7 +176,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: sharePermissionManager.getMaximumPermission(isFolder()) + ?: sharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -290,8 +290,9 @@ class FileDetailsSharingProcessFragment : binding.run { when { SharingMenuHelper.isUploadAndEditingAllowed(share) -> editingRadioButton.isChecked = true - SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = - true + SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> + fileRequestRadioButton.isChecked = + true SharingMenuHelper.isReadOnly(share) -> viewOnlyRadioButton.isChecked = true else -> { From a7aa84e15253c3cb8d4dbc61c71ed5fdaa9d1703 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 15:04:34 +0200 Subject: [PATCH 069/110] fix tests Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 0b52076af8bd..00582e366090 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -339,7 +339,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_change_name_switch)).check(matches(isDisplayed())) @@ -347,7 +347,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() // upload and editing @@ -355,7 +355,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() // file request @@ -363,7 +363,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isChecked())) goBack() // password protection @@ -487,7 +487,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) onView( - ViewMatchers.withId(R.id.`@+id/file_request_radio_button`) + ViewMatchers.withId(R.id.file_request_radio_button) ).check(matches(not(isDisplayed()))) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) @@ -619,7 +619,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) onView( - ViewMatchers.withId(R.id.`@+id/file_request_radio_button`) + ViewMatchers.withId(R.id.file_request_radio_button) ).check(matches(not(isDisplayed()))) onView( ViewMatchers.withId(R.id.share_process_hide_download_checkbox) @@ -751,7 +751,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isDisplayed())) onView( ViewMatchers.withId(R.id.share_process_hide_download_checkbox) ).check(matches(not(isDisplayed()))) @@ -766,7 +766,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() // allow upload & editing @@ -774,7 +774,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() // file request @@ -782,7 +782,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.`@+id/file_request_radio_button`)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isChecked())) goBack() // set expiration date From 088fa83d794d3be4675537471d6b9eb10f8292ff Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 15:47:09 +0200 Subject: [PATCH 070/110] better function naming Signed-off-by: alperozturk --- .../ui/fragment/FileDetailSharingFragmentIT.kt | 16 ++++++++-------- .../FileDetailsSharingProcessFragment.kt | 2 +- .../ui/fragment/util/SharingMenuHelper.java | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 00582e366090..775298b067c1 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -914,28 +914,28 @@ class FileDetailSharingFragmentIT : AbstractIT() { val share = OCShare().apply { permissions = 17 } - assertTrue(SharingMenuHelper.isReadOnly(share)) + assertTrue(SharingMenuHelper.isViewOnly(share)) share.permissions = NO_PERMISSION - assertFalse(SharingMenuHelper.isReadOnly(share)) + assertFalse(SharingMenuHelper.isViewOnly(share)) share.permissions = READ_PERMISSION_FLAG - assertTrue(SharingMenuHelper.isReadOnly(share)) + assertTrue(SharingMenuHelper.isViewOnly(share)) share.permissions = CREATE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isReadOnly(share)) + assertFalse(SharingMenuHelper.isViewOnly(share)) share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isReadOnly(share)) + assertFalse(SharingMenuHelper.isViewOnly(share)) share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isReadOnly(share)) + assertFalse(SharingMenuHelper.isViewOnly(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - assertFalse(SharingMenuHelper.isReadOnly(share)) + assertFalse(SharingMenuHelper.isViewOnly(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE - assertFalse(SharingMenuHelper.isReadOnly(share)) + assertFalse(SharingMenuHelper.isViewOnly(share)) } @Test diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 0d4baf3695a5..2b17a2c76073 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -294,7 +294,7 @@ class FileDetailsSharingProcessFragment : fileRequestRadioButton.isChecked = true - SharingMenuHelper.isReadOnly(share) -> viewOnlyRadioButton.isChecked = true + SharingMenuHelper.isViewOnly(share) -> viewOnlyRadioButton.isChecked = true else -> { if (sharePermissionManager.isCustomPermission(share) || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 229133b3e009..8c1dcf5bb302 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -45,7 +45,7 @@ public static boolean isUploadAndEditingAllowed(OCShare share) { MAXIMUM_PERMISSIONS_FOR_FILE); } - public static boolean isReadOnly(OCShare share) { + public static boolean isViewOnly(OCShare share) { if (share.getPermissions() == NO_PERMISSION) { return false; } @@ -74,7 +74,7 @@ public static String getPermissionName(Context context, OCShare share) { if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { return res.getString(R.string.share_permission_can_edit); - } else if (SharingMenuHelper.isReadOnly(share)) { + } else if (SharingMenuHelper.isViewOnly(share)) { return res.getString(R.string.share_permission_view_only); } else if (sharePermissionManager.isCustomPermission(share)) { return res.getString(R.string.share_custom_permission); @@ -88,7 +88,7 @@ public static String getPermissionName(Context context, OCShare share) { } public static QuickPermissionType getSelectedType(OCShare share) { - if (SharingMenuHelper.isReadOnly(share)) { + if (SharingMenuHelper.isViewOnly(share)) { return QuickPermissionType.VIEW_ONLY; } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { return QuickPermissionType.CAN_EDIT; From 90a46e631dc5acef34734807169aa14c399e8460 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 15:57:38 +0200 Subject: [PATCH 071/110] better function naming Signed-off-by: alperozturk --- .../ui/fragment/FileDetailSharingFragmentIT.kt | 12 ++++++------ .../ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- .../android/ui/fragment/util/SharingMenuHelper.java | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 775298b067c1..57bb548e6f13 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -890,22 +890,22 @@ class FileDetailSharingFragmentIT : AbstractIT() { val share = OCShare().apply { permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER } - assertTrue(SharingMenuHelper.isUploadAndEditingAllowed(share)) + assertTrue(SharingMenuHelper.canEdit(share)) share.permissions = NO_PERMISSION - assertFalse(SharingMenuHelper.isUploadAndEditingAllowed(share)) + assertFalse(SharingMenuHelper.canEdit(share)) share.permissions = READ_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isUploadAndEditingAllowed(share)) + assertFalse(SharingMenuHelper.canEdit(share)) share.permissions = CREATE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isUploadAndEditingAllowed(share)) + assertFalse(SharingMenuHelper.canEdit(share)) share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isUploadAndEditingAllowed(share)) + assertFalse(SharingMenuHelper.canEdit(share)) share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isUploadAndEditingAllowed(share)) + assertFalse(SharingMenuHelper.canEdit(share)) } @Test diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 2b17a2c76073..3f2cee08464b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -289,7 +289,7 @@ class FileDetailsSharingProcessFragment : // custom permissions / read only / allow upload and editing / file request binding.run { when { - SharingMenuHelper.isUploadAndEditingAllowed(share) -> editingRadioButton.isChecked = true + SharingMenuHelper.canEdit(share) -> editingRadioButton.isChecked = true SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = true diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 8c1dcf5bb302..a7578dbcc78f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -35,7 +35,7 @@ private SharingMenuHelper() { // utility class -> private constructor } - public static boolean isUploadAndEditingAllowed(OCShare share) { + public static boolean canEdit(OCShare share) { if (share.getPermissions() == NO_PERMISSION) { return false; } @@ -72,7 +72,7 @@ public static boolean isSecureFileDrop(OCShare share) { public static String getPermissionName(Context context, OCShare share) { final var res = context.getResources(); - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + if (SharingMenuHelper.canEdit(share)) { return res.getString(R.string.share_permission_can_edit); } else if (SharingMenuHelper.isViewOnly(share)) { return res.getString(R.string.share_permission_view_only); @@ -90,7 +90,7 @@ public static String getPermissionName(Context context, OCShare share) { public static QuickPermissionType getSelectedType(OCShare share) { if (SharingMenuHelper.isViewOnly(share)) { return QuickPermissionType.VIEW_ONLY; - } else if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { + } else if (SharingMenuHelper.canEdit(share)) { return QuickPermissionType.CAN_EDIT; } else if (SharingMenuHelper.isFileRequest(share)) { return QuickPermissionType.FILE_REQUEST; From 340e613fbbd662be90cc13bb79edf4f40c8733b5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 7 May 2025 16:18:46 +0200 Subject: [PATCH 072/110] check next button availability Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 3f2cee08464b..87a8563c3929 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -197,6 +197,7 @@ class FileDetailsSharingProcessFragment : setCheckboxStates() themeView() setVisibilitiesOfShareOption() + checkNextButtonAvailability() } private fun setVisibilitiesOfShareOption() { @@ -529,6 +530,8 @@ class FileDetailsSharingProcessFragment : customPermissionLayout.setVisibilityWithAnimation(isChecked) } } + + toggleNextButtonAvailability(true) } // endregion } @@ -536,6 +539,22 @@ class FileDetailsSharingProcessFragment : private fun togglePermission(isChecked: Boolean, permissionFlag: Int) { permission = sharePermissionManager.togglePermission(isChecked, permission, permissionFlag) + toggleNextButtonAvailability(true) + } + + private fun checkNextButtonAvailability() { + var hasAnyPermission = false + if (share != null) { + hasAnyPermission = SharingMenuHelper.getPermissionName(requireContext(), share) != null + } + toggleNextButtonAvailability(hasAnyPermission) + } + + private fun toggleNextButtonAvailability(value: Boolean) { + binding.run { + shareProcessBtnNext.isEnabled = value + shareProcessBtnNext.isClickable = value + } } @Suppress("NestedBlockDepth") From 06eee02dc0b2c1bed3f8ff8e0b5ee5e5efd63db4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 09:03:17 +0200 Subject: [PATCH 073/110] show isSecureFileDrop text if encrypted Signed-off-by: alperozturk --- .../ui/adapter/LinkShareViewHolder.java | 7 +- .../android/ui/adapter/ShareViewHolder.java | 7 +- .../android/ui/adapter/ShareeListAdapter.java | 69 +++++++------------ .../FileDetailsSharingProcessFragment.kt | 4 +- .../ui/fragment/util/SharingMenuHelper.java | 10 +-- 5 files changed, 43 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index e628251c1e94..dfdf73f56e97 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -36,6 +36,7 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder { private FileDetailsShareLinkShareItemBinding binding; private Context context; private ViewThemeUtils viewThemeUtils; + private boolean encrypted; public LinkShareViewHolder(@NonNull View itemView) { super(itemView); @@ -43,11 +44,13 @@ public LinkShareViewHolder(@NonNull View itemView) { public LinkShareViewHolder(FileDetailsShareLinkShareItemBinding binding, Context context, - final ViewThemeUtils viewThemeUtils) { + final ViewThemeUtils viewThemeUtils, + boolean encrypted) { this(binding.getRoot()); this.binding = binding; this.context = context; this.viewThemeUtils = viewThemeUtils; + this.encrypted = encrypted; } public void bind(OCShare publicShare, ShareeListAdapterListener listener) { @@ -90,7 +93,7 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { binding.subline.setVisibility(View.GONE); } - String permissionName = SharingMenuHelper.getPermissionName(context, publicShare); + String permissionName = SharingMenuHelper.getPermissionName(context, publicShare, encrypted); setPermissionName(publicShare, permissionName); binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare)); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index 4c9b95471f29..447217e54ebb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -37,6 +37,7 @@ class ShareViewHolder extends RecyclerView.ViewHolder { private User user; private Context context; private ViewThemeUtils viewThemeUtils; + private boolean encrypted; public ShareViewHolder(@NonNull View itemView) { super(itemView); @@ -45,12 +46,14 @@ public ShareViewHolder(@NonNull View itemView) { public ShareViewHolder(FileDetailsShareShareItemBinding binding, User user, Context context, - final ViewThemeUtils viewThemeUtils) { + final ViewThemeUtils viewThemeUtils, + boolean encrypted) { this(binding.getRoot()); this.binding = binding; this.user = user; this.context = context; this.viewThemeUtils = viewThemeUtils; + this.encrypted = encrypted; } public void bind(OCShare share, @@ -106,7 +109,7 @@ public void bind(OCShare share, if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) { binding.overflowMenu.setVisibility(View.VISIBLE); - String permissionName = SharingMenuHelper.getPermissionName(context, share); + String permissionName = SharingMenuHelper.getPermissionName(context, share, encrypted); setPermissionName(permissionName); // bind listener to edit privileges diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index 3b066d803bc3..bd2b9c29d1c2 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -33,9 +33,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -106,50 +104,35 @@ public int getItemViewType(int position) { @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { boolean shareViaLink = MDMConfig.INSTANCE.shareViaLink(fileActivity); + final var parentViewGroup = LayoutInflater.from(fileActivity); - if (shareViaLink) { - switch (ShareType.fromValue(viewType)) { - case PUBLIC_LINK, EMAIL -> { - return new LinkShareViewHolder( - FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(fileActivity), - parent, - false), - fileActivity, - viewThemeUtils); - } - case NEW_PUBLIC_LINK -> { - if (encrypted) { - return new NewSecureFileDropViewHolder( - FileDetailsShareSecureFileDropAddNewItemBinding.inflate(LayoutInflater.from(fileActivity), - parent, - false) - ); - } else { - return new NewLinkShareViewHolder( - FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(fileActivity), - parent, - false) - ); - } - } - case INTERNAL -> { - return new InternalShareViewHolder( - FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false), - fileActivity); - } - default -> { - return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(fileActivity), - parent, - false), - user, - fileActivity, - viewThemeUtils); + if (!shareViaLink) { + final var binding = FileDetailsShareInternalShareLinkBinding.inflate(parentViewGroup, parent, false); + return new InternalShareViewHolder(binding, fileActivity); + } + + switch (ShareType.fromValue(viewType)) { + case PUBLIC_LINK, EMAIL -> { + final var binding = FileDetailsShareLinkShareItemBinding.inflate(parentViewGroup, parent, false); + return new LinkShareViewHolder(binding, fileActivity, viewThemeUtils, encrypted); + } + case NEW_PUBLIC_LINK -> { + if (encrypted) { + final var binding = FileDetailsShareSecureFileDropAddNewItemBinding.inflate(parentViewGroup, parent, false); + return new NewSecureFileDropViewHolder(binding); + } else { + final var binding = FileDetailsSharePublicLinkAddNewItemBinding.inflate(parentViewGroup, parent, false); + return new NewLinkShareViewHolder(binding); } } - } else { - return new InternalShareViewHolder( - FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false), - fileActivity); + case INTERNAL -> { + final var binding = FileDetailsShareInternalShareLinkBinding.inflate(parentViewGroup, parent, false); + return new InternalShareViewHolder(binding, fileActivity); + } + default -> { + final var binding = FileDetailsShareShareItemBinding.inflate(parentViewGroup, parent, false); + return new ShareViewHolder(binding, user, fileActivity, viewThemeUtils, encrypted); + } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 87a8563c3929..851a499c8a2d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -176,7 +176,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: sharePermissionManager.getMaximumPermission(isFolder()) + ?: sharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -545,7 +545,7 @@ class FileDetailsSharingProcessFragment : private fun checkNextButtonAvailability() { var hasAnyPermission = false if (share != null) { - hasAnyPermission = SharingMenuHelper.getPermissionName(requireContext(), share) != null + hasAnyPermission = SharingMenuHelper.getPermissionName(requireContext(), share, isSecureShare) != null } toggleNextButtonAvailability(hasAnyPermission) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index a7578dbcc78f..37965b7af254 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -69,19 +69,19 @@ public static boolean isSecureFileDrop(OCShare share) { return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } - public static String getPermissionName(Context context, OCShare share) { + public static String getPermissionName(Context context, OCShare share, boolean encrypted) { final var res = context.getResources(); if (SharingMenuHelper.canEdit(share)) { return res.getString(R.string.share_permission_can_edit); + } else if (encrypted && SharingMenuHelper.isSecureFileDrop(share)) { + return res.getString(R.string.share_permission_secure_file_drop); + } else if (SharingMenuHelper.isFileRequest(share)) { + return res.getString(R.string.link_share_file_request); } else if (SharingMenuHelper.isViewOnly(share)) { return res.getString(R.string.share_permission_view_only); } else if (sharePermissionManager.isCustomPermission(share)) { return res.getString(R.string.share_custom_permission); - } else if (SharingMenuHelper.isSecureFileDrop(share)) { - return res.getString(R.string.share_permission_secure_file_drop); - } else if (SharingMenuHelper.isFileRequest(share)) { - return res.getString(R.string.link_share_file_request); } return null; From a86f3446858e9b60b0ebd415b6653b90c12cb8c0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 09:15:13 +0200 Subject: [PATCH 074/110] correct view order Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 28 +++++++++---------- .../FileDetailsSharingProcessFragment.kt | 21 ++++++-------- .../file_details_sharing_process_fragment.xml | 12 ++++---- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 57bb548e6f13..79d147a6038b 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -338,7 +338,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_hide_download_checkbox)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.share_process_set_password_switch)).check(matches(isDisplayed())) @@ -346,7 +346,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() @@ -354,7 +354,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() @@ -362,7 +362,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { publicShare.permissions = 4 openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isChecked())) goBack() @@ -485,7 +485,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isDisplayed())) onView( ViewMatchers.withId(R.id.file_request_radio_button) ).check(matches(not(isDisplayed()))) @@ -496,14 +496,14 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only publicShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isNotChecked())) goBack() // editing publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server openAdvancedPermissions(sut, publicShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isChecked())) goBack() // hide download @@ -617,7 +617,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isDisplayed())) onView( ViewMatchers.withId(R.id.file_request_radio_button) ).check(matches(not(isDisplayed()))) @@ -634,14 +634,14 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isNotChecked())) goBack() // editing userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FILE // from server openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isChecked())) goBack() // set expiration date @@ -750,7 +750,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // validate view shown on screen onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isDisplayed())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isDisplayed())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isDisplayed())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isDisplayed())) onView( ViewMatchers.withId(R.id.share_process_hide_download_checkbox) @@ -765,7 +765,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { // read-only userShare.permissions = 17 // from server onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() @@ -773,7 +773,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER // from server openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isChecked())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isNotChecked())) goBack() @@ -781,7 +781,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { userShare.permissions = 4 openAdvancedPermissions(sut, userShare) onView(ViewMatchers.withId(R.id.view_only_radio_button)).check(matches(isNotChecked())) - onView(ViewMatchers.withId(R.id.editing_radio_button)).check(matches(isNotChecked())) + onView(ViewMatchers.withId(R.id.can_edit_radio_button)).check(matches(isNotChecked())) onView(ViewMatchers.withId(R.id.file_request_radio_button)).check(matches(isChecked())) goBack() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 851a499c8a2d..2517d32884b0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -214,7 +214,7 @@ class FileDetailsSharingProcessFragment : colorTextView(shareCustomPermissionsText) themeRadioButton(viewOnlyRadioButton) - themeRadioButton(editingRadioButton) + themeRadioButton(canEditRadioButton) themeRadioButton(customPermissionRadioButton) if (!isPublicShare()) { @@ -290,7 +290,7 @@ class FileDetailsSharingProcessFragment : // custom permissions / read only / allow upload and editing / file request binding.run { when { - SharingMenuHelper.canEdit(share) -> editingRadioButton.isChecked = true + SharingMenuHelper.canEdit(share) -> canEditRadioButton.isChecked = true SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = true @@ -446,13 +446,13 @@ class FileDetailsSharingProcessFragment : private fun updateViewForFile() { binding.run { - editingRadioButton.text = getString(R.string.link_share_editing) + canEditRadioButton.text = getString(R.string.link_share_editing) } } private fun updateViewForFolder() { binding.run { - editingRadioButton.text = getString(R.string.share_permission_can_edit) + canEditRadioButton.text = getString(R.string.share_permission_can_edit) if (isSecureShare) { shareCheckbox.visibility = View.GONE @@ -509,28 +509,23 @@ class FileDetailsSharingProcessFragment : } // region RadioButtons - shareProcessPermissionRadioGroup.setOnCheckedChangeListener { radioGroup, optionId -> + shareProcessPermissionRadioGroup.setOnCheckedChangeListener { _, optionId -> when (optionId) { R.id.view_only_radio_button -> { - customPermissionLayout.visibility = View.GONE permission = OCShare.READ_PERMISSION_FLAG } - R.id.editing_radio_button -> { - customPermissionLayout.visibility = View.GONE + R.id.can_edit_radio_button -> { permission = sharePermissionManager.getMaximumPermission(isFolder()) } R.id.file_request_radio_button -> { permission = OCShare.CREATE_PERMISSION_FLAG } - - R.id.custom_permission_radio_button -> { - val isChecked = customPermissionRadioButton.isChecked - customPermissionLayout.setVisibilityWithAnimation(isChecked) - } } + val isCustomPermissionSelected = (optionId == R.id.custom_permission_radio_button) + customPermissionLayout.setVisibilityWithAnimation(isCustomPermissionSelected) toggleNextButtonAvailability(true) } // endregion diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 90062427a9e8..f43d3482a5ae 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -52,26 +52,26 @@ android:text="@string/link_share_view_only" /> + android:text="@string/link_share_file_request" /> + android:text="@string/share_custom_permission" /> From 0c59872a9c4ae6777377b7e2d1779cb296f48995 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 09:31:52 +0200 Subject: [PATCH 075/110] share common logic for canSetFileRequest Signed-off-by: alperozturk --- .../utils/{ => extensions}/OCShareExtensions.kt | 7 +++---- .../utils/extensions/ShareTypeExtensions.kt | 12 ++++++++++++ .../ui/fragment/FileDetailSharingFragment.java | 2 +- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 7 +++++-- .../QuickSharingPermissionsBottomSheetDialog.java | 2 +- 5 files changed, 22 insertions(+), 8 deletions(-) rename app/src/main/java/com/nextcloud/utils/{ => extensions}/OCShareExtensions.kt (56%) create mode 100644 app/src/main/java/com/nextcloud/utils/extensions/ShareTypeExtensions.kt diff --git a/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt similarity index 56% rename from app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt rename to app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt index 5952383a870e..45cfa46dfd63 100644 --- a/app/src/main/java/com/nextcloud/utils/OCShareExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/OCShareExtensions.kt @@ -1,17 +1,16 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-FileCopyrightText: 2025 Your Name * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.nextcloud.utils +package com.nextcloud.utils.extensions import com.owncloud.android.lib.resources.shares.OCShare -import com.owncloud.android.lib.resources.shares.ShareType fun OCShare.hasFileRequestPermission(): Boolean { - return (isFolder && (shareType == ShareType.PUBLIC_LINK || shareType == ShareType.EMAIL)) + return (isFolder && shareType?.isPublicOrMail() == true) } fun List.mergeDistinctByToken(other: List): List { diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ShareTypeExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ShareTypeExtensions.kt new file mode 100644 index 000000000000..4200fae86634 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/extensions/ShareTypeExtensions.kt @@ -0,0 +1,12 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils.extensions + +import com.owncloud.android.lib.resources.shares.ShareType + +fun ShareType.isPublicOrMail(): Boolean = (this == ShareType.PUBLIC_LINK || this == ShareType.EMAIL) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 8cde8a65b0ac..335dabab5f03 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -35,9 +35,9 @@ import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.network.ClientFactory; -import com.nextcloud.utils.OCShareExtensionsKt; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.FileExtensionsKt; +import com.nextcloud.utils.extensions.OCShareExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.R; diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 2517d32884b0..436405660ffc 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -18,6 +18,7 @@ import androidx.fragment.app.Fragment import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument +import com.nextcloud.utils.extensions.isPublicOrMail import com.nextcloud.utils.extensions.setVisibilityWithAnimation import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R @@ -203,7 +204,7 @@ class FileDetailsSharingProcessFragment : private fun setVisibilitiesOfShareOption() { binding.run { shareAllowDownloadAndSyncCheckbox.setVisibleIf(!isPublicShare()) - fileRequestRadioButton.setVisibleIf(isPublicShare() && isFolder()) + fileRequestRadioButton.setVisibleIf(canSetFileRequest()) } } @@ -221,7 +222,7 @@ class FileDetailsSharingProcessFragment : themeCheckbox(shareAllowDownloadAndSyncCheckbox) } - if (isPublicShare() && isFolder()) { + if (canSetFileRequest()) { themeRadioButton(fileRequestRadioButton) } @@ -797,6 +798,8 @@ class FileDetailsSharingProcessFragment : // region Helpers private fun isFolder(): Boolean = (file?.isFolder == true || share?.isFolder == true) + private fun canSetFileRequest(): Boolean = isFolder() && shareType.isPublicOrMail() + private fun canSetDownloadLimit(): Boolean = (isPublicShare() && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index ec40603c2fa6..f36b23b68fe5 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -17,7 +17,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; -import com.nextcloud.utils.OCShareExtensionsKt; +import com.nextcloud.utils.extensions.OCShareExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; import com.owncloud.android.datamodel.quickPermission.QuickPermission; From 1e670830eaeb332208399ef2cac3cbf46b7ac8a3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 14:17:22 +0200 Subject: [PATCH 076/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 436405660ffc..347eb08ec7ee 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -177,7 +177,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: sharePermissionManager.getMaximumPermission(isFolder()) + ?: sharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { From e4a2fe56c410eb1f44bf658ace197cc2c9ce3a80 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 14:37:18 +0200 Subject: [PATCH 077/110] fix isSecureFileDrop condition Signed-off-by: alperozturk --- .../android/ui/adapter/LinkShareViewHolder.java | 15 ++++++++------- .../ui/fragment/FileDetailSharingFragment.java | 2 +- .../FileDetailSharingMenuBottomSheetDialog.java | 17 +++++++++++------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index dfdf73f56e97..e5e9b8bf8dc9 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -72,7 +72,7 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { } else { if (SharingMenuHelper.isFileRequest(publicShare)) { binding.name.setText(context.getResources().getString(R.string.link_share_file_request)); - } else if (SharingMenuHelper.isSecureFileDrop(publicShare)) { + } else if (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted) { binding.name.setText(context.getResources().getString(R.string.share_permission_secure_file_drop)); } else { binding.name.setText(R.string.share_link); @@ -97,7 +97,7 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { setPermissionName(publicShare, permissionName); binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare)); - if (!SharingMenuHelper.isSecureFileDrop(publicShare)) { + if (!SharingMenuHelper.isSecureFileDrop(publicShare) && !encrypted) { binding.shareByLinkContainer.setOnClickListener(v -> listener.showPermissionsDialog(publicShare)); } @@ -109,12 +109,13 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { } private void setPermissionName(OCShare publicShare, String permissionName) { - if (!TextUtils.isEmpty(permissionName) && !SharingMenuHelper.isSecureFileDrop(publicShare)) { - binding.permissionName.setText(permissionName); - binding.permissionName.setVisibility(View.VISIBLE); - viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName); - } else { + if (TextUtils.isEmpty(permissionName) || (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted)) { binding.permissionName.setVisibility(View.GONE); + return; } + + binding.permissionName.setText(permissionName); + binding.permissionName.setVisibility(View.VISIBLE); + viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 335dabab5f03..9602db804cc0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -415,7 +415,7 @@ public void copyLink(OCShare share) { @VisibleForTesting public void showSharingMenuActionSheet(OCShare share) { if (fileActivity != null && !fileActivity.isFinishing()) { - new FileDetailSharingMenuBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show(); + new FileDetailSharingMenuBottomSheetDialog(fileActivity, this, share, viewThemeUtils, file.isEncrypted()).show(); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java index be6779b9573a..46d67917b7ef 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java @@ -16,6 +16,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.databinding.FileDetailsSharingMenuBottomSheetFragmentBinding; import com.owncloud.android.lib.resources.shares.OCShare; @@ -32,14 +33,18 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog { private final FileDetailsSharingMenuBottomSheetActions actions; private final OCShare ocShare; private final ViewThemeUtils viewThemeUtils; + private final boolean encrypted; + public FileDetailSharingMenuBottomSheetDialog(FileActivity fileActivity, FileDetailsSharingMenuBottomSheetActions actions, OCShare ocShare, - ViewThemeUtils viewThemeUtils) { + ViewThemeUtils viewThemeUtils, + boolean encrypted) { super(fileActivity); this.actions = actions; this.ocShare = ocShare; this.viewThemeUtils = viewThemeUtils; + this.encrypted = encrypted; } @Override @@ -54,10 +59,10 @@ protected void onCreate(Bundle savedInstanceState) { viewThemeUtils.platform.themeDialog(binding.getRoot()); - viewThemeUtils.platform.colorImageView(binding.menuIconAdvancedPermissions); - viewThemeUtils.platform.colorImageView(binding.menuIconSendLink); - viewThemeUtils.platform.colorImageView(binding.menuIconUnshare); - viewThemeUtils.platform.colorImageView(binding.menuIconSendNewEmail); + viewThemeUtils.platform.colorImageView(binding.menuIconAdvancedPermissions, ColorRole.PRIMARY); + viewThemeUtils.platform.colorImageView(binding.menuIconSendLink, ColorRole.PRIMARY); + viewThemeUtils.platform.colorImageView(binding.menuIconUnshare, ColorRole.PRIMARY); + viewThemeUtils.platform.colorImageView(binding.menuIconSendNewEmail, ColorRole.PRIMARY); updateUI(); @@ -78,7 +83,7 @@ private void updateUI() { binding.menuShareSendLink.setVisibility(View.GONE); } - if (SharingMenuHelper.isSecureFileDrop(ocShare)) { + if (SharingMenuHelper.isSecureFileDrop(ocShare) && encrypted) { binding.menuShareAdvancedPermissions.setVisibility(View.GONE); } } From 667168334e93c3606edd3a05260b7f925033226a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 15:09:04 +0200 Subject: [PATCH 078/110] use single source of truth for sub-title of the external and internal share and quick permissions Signed-off-by: alperozturk --- .../quickPermission/QuickPermission.kt | 23 +--------------- .../quickPermission/QuickPermissionType.kt | 26 +++++++++++++++--- .../ui/adapter/LinkShareViewHolder.java | 7 ++--- .../adapter/QuickSharingPermissionsAdapter.kt | 4 +-- .../android/ui/adapter/ShareViewHolder.java | 5 ++-- .../fragment/FileDetailSharingFragment.java | 2 +- .../FileDetailsSharingProcessFragment.kt | 3 ++- ...ckSharingPermissionsBottomSheetDialog.java | 16 ++++++----- .../ui/fragment/util/SharingMenuHelper.java | 27 +++---------------- .../file_details_sharing_process_fragment.xml | 4 +-- app/src/main/res/values/strings.xml | 10 +++---- 11 files changed, 56 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt index 545b87b3c692..b6be8070156c 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt @@ -7,25 +7,4 @@ package com.owncloud.android.datamodel.quickPermission -import android.content.Context -import android.graphics.drawable.Drawable -import androidx.core.content.ContextCompat - -data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) { - companion object { - fun getPermissions( - hasFileRequestPermission: Boolean, - selectedType: QuickPermissionType - ): List { - return QuickPermissionType.getAvailablePermissions(hasFileRequestPermission).map { type -> - QuickPermission( - type = type, - isSelected = (type == selectedType) - ) - } - } - } - - fun getText(context: Context): String = context.getString(type.textId) - fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, type.iconId) -} +data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt index 0b57984f39ed..51dfbb5bf23c 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermissionType.kt @@ -7,6 +7,9 @@ package com.owncloud.android.datamodel.quickPermission +import android.content.Context +import android.graphics.drawable.Drawable +import androidx.core.content.ContextCompat import com.owncloud.android.R enum class QuickPermissionType( @@ -14,15 +17,30 @@ enum class QuickPermissionType( val textId: Int ) { NONE(R.drawable.ic_unknown, R.string.unknown), - VIEW_ONLY(R.drawable.ic_eye, R.string.link_share_view_only), + VIEW_ONLY(R.drawable.ic_eye, R.string.share_permission_view_only), CAN_EDIT(R.drawable.ic_edit, R.string.share_permission_can_edit), - FILE_REQUEST(R.drawable.ic_file_request, R.string.link_share_file_request), + FILE_REQUEST(R.drawable.ic_file_request, R.string.share_permission_file_request), + SECURE_FILE_DROP(R.drawable.ic_file_request, R.string.share_permission_secure_file_drop), CUSTOM_PERMISSIONS(R.drawable.ic_custom_permissions, R.string.share_custom_permission); + fun getText(context: Context): String = context.getString(textId) + + fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, iconId) + companion object { - fun getAvailablePermissions(hasFileRequestPermission: Boolean): List { + fun getAvailablePermissions( + hasFileRequestPermission: Boolean, + selectedType: QuickPermissionType + ): List { val permissions = listOf(VIEW_ONLY, CAN_EDIT, FILE_REQUEST, CUSTOM_PERMISSIONS) - return if (hasFileRequestPermission) permissions else permissions.filter { it != FILE_REQUEST } + val result = if (hasFileRequestPermission) permissions else permissions.filter { it != FILE_REQUEST } + + return result.map { type -> + QuickPermission( + type = type, + isSelected = (type == selectedType) + ) + } } } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index e5e9b8bf8dc9..4f545df52ad9 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -23,6 +23,7 @@ import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding; +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.ui.fragment.util.SharingMenuHelper; @@ -71,7 +72,7 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { binding.name.setText(text); } else { if (SharingMenuHelper.isFileRequest(publicShare)) { - binding.name.setText(context.getResources().getString(R.string.link_share_file_request)); + binding.name.setText(context.getResources().getString(R.string.share_permission_file_request)); } else if (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted) { binding.name.setText(context.getResources().getString(R.string.share_permission_secure_file_drop)); } else { @@ -93,8 +94,8 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { binding.subline.setVisibility(View.GONE); } - String permissionName = SharingMenuHelper.getPermissionName(context, publicShare, encrypted); - setPermissionName(publicShare, permissionName); + QuickPermissionType quickPermissionType = SharingMenuHelper.getSelectedType(publicShare, encrypted); + setPermissionName(publicShare, quickPermissionType.getText(context)); binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare)); if (!SharingMenuHelper.isSecureFileDrop(publicShare) && !encrypted) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index 59328288ba00..06a444fb01c5 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -50,12 +50,12 @@ class QuickSharingPermissionsAdapter( fun bindData(quickPermission: QuickPermission) { val context = itemView.context - val permissionName = quickPermission.getText(context) + val permissionName = quickPermission.type.getText(context) binding.run { quickPermissionButton.text = permissionName quickPermissionButton.iconGravity = MaterialButton.ICON_GRAVITY_START - quickPermissionButton.icon = quickPermission.getIcon(context) + quickPermissionButton.icon = quickPermission.type.getIcon(context) if (quickPermission.isSelected) { viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(quickPermissionButton) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index 447217e54ebb..bfe4e527c5fc 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -21,6 +21,7 @@ import com.nextcloud.client.account.User; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsShareShareItemBinding; +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.TextDrawable; import com.owncloud.android.ui.fragment.util.SharingMenuHelper; @@ -109,8 +110,8 @@ public void bind(OCShare share, if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) { binding.overflowMenu.setVisibility(View.VISIBLE); - String permissionName = SharingMenuHelper.getPermissionName(context, share, encrypted); - setPermissionName(permissionName); + QuickPermissionType quickPermissionType = SharingMenuHelper.getSelectedType(share, encrypted); + setPermissionName(quickPermissionType.getText(context)); // bind listener to edit privileges binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(share)); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 9602db804cc0..03bcaa459694 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -426,7 +426,7 @@ public void showSharingMenuActionSheet(OCShare share) { */ @Override public void showPermissionsDialog(OCShare share) { - new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show(); + new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils, file.isEncrypted()).show(); } /** diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 347eb08ec7ee..4d2ed20ce03e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -24,6 +24,7 @@ import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.status.OCCapability @@ -541,7 +542,7 @@ class FileDetailsSharingProcessFragment : private fun checkNextButtonAvailability() { var hasAnyPermission = false if (share != null) { - hasAnyPermission = SharingMenuHelper.getPermissionName(requireContext(), share, isSecureShare) != null + hasAnyPermission = SharingMenuHelper.getSelectedType(share, isSecureShare) != QuickPermissionType.NONE } toggleNextButtonAvailability(hasAnyPermission) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index f36b23b68fe5..331cb2fe203b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -21,6 +21,7 @@ import com.owncloud.android.R; import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; import com.owncloud.android.datamodel.quickPermission.QuickPermission; +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter; @@ -45,16 +46,19 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog private final FileActivity fileActivity; private final OCShare ocShare; private final ViewThemeUtils viewThemeUtils; + private final boolean encrypted; public QuickSharingPermissionsBottomSheetDialog(FileActivity fileActivity, QuickPermissionSharingBottomSheetActions actions, OCShare ocShare, - ViewThemeUtils viewThemeUtils) { + ViewThemeUtils viewThemeUtils, + boolean encrypted) { super(fileActivity); this.actions = actions; this.ocShare = ocShare; this.fileActivity = fileActivity; this.viewThemeUtils = viewThemeUtils; + this.encrypted = encrypted; } @Override @@ -108,15 +112,15 @@ public void onDismissSheet() { * Handle permission changed on click of selected permission */ private void handlePermissionChanged(List quickPermissionList, int position) { - final var permissionName = quickPermissionList.get(position).getText(getContext()); + final var permissionName = quickPermissionList.get(position).getType().getText(getContext()); final var res = fileActivity.getResources(); int permissionFlag = 0; if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_can_edit)) || permissionName.equalsIgnoreCase(res.getString(R.string.link_share_editing))) { permissionFlag = ocShare.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : MAXIMUM_PERMISSIONS_FOR_FILE; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_view_only))) { + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_view_only))) { permissionFlag = READ_PERMISSION_FLAG; - } else if (permissionName.equalsIgnoreCase(res.getString(R.string.link_share_file_request))) { + } else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_file_request))) { permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } @@ -129,9 +133,9 @@ private void handlePermissionChanged(List quickPermissionList, * Prepare the list of permissions needs to be displayed on recyclerview */ private List getQuickPermissionList() { - final var selectedType = SharingMenuHelper.getSelectedType(ocShare); + final var selectedType = SharingMenuHelper.getSelectedType(ocShare, encrypted); final var hasFileRequestPermission = OCShareExtensionsKt.hasFileRequestPermission(ocShare); - return QuickPermission.Companion.getPermissions(hasFileRequestPermission, selectedType); + return QuickPermissionType.Companion.getAvailablePermissions(hasFileRequestPermission, selectedType); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java index 37965b7af254..c7d3d8830c3b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java @@ -11,9 +11,6 @@ package com.owncloud.android.ui.fragment.util; -import android.content.Context; - -import com.owncloud.android.R; import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; @@ -69,31 +66,15 @@ public static boolean isSecureFileDrop(OCShare share) { return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; } - public static String getPermissionName(Context context, OCShare share, boolean encrypted) { - final var res = context.getResources(); - + public static QuickPermissionType getSelectedType(OCShare share, boolean encrypted) { if (SharingMenuHelper.canEdit(share)) { - return res.getString(R.string.share_permission_can_edit); + return QuickPermissionType.CAN_EDIT; } else if (encrypted && SharingMenuHelper.isSecureFileDrop(share)) { - return res.getString(R.string.share_permission_secure_file_drop); + return QuickPermissionType.SECURE_FILE_DROP; } else if (SharingMenuHelper.isFileRequest(share)) { - return res.getString(R.string.link_share_file_request); + return QuickPermissionType.FILE_REQUEST; } else if (SharingMenuHelper.isViewOnly(share)) { - return res.getString(R.string.share_permission_view_only); - } else if (sharePermissionManager.isCustomPermission(share)) { - return res.getString(R.string.share_custom_permission); - } - - return null; - } - - public static QuickPermissionType getSelectedType(OCShare share) { - if (SharingMenuHelper.isViewOnly(share)) { return QuickPermissionType.VIEW_ONLY; - } else if (SharingMenuHelper.canEdit(share)) { - return QuickPermissionType.CAN_EDIT; - } else if (SharingMenuHelper.isFileRequest(share)) { - return QuickPermissionType.FILE_REQUEST; } else if (sharePermissionManager.isCustomPermission(share)) { return QuickPermissionType.CUSTOM_PERMISSIONS; } diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index f43d3482a5ae..6a39600b5dc1 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -49,7 +49,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/minimum_size_for_touchable_area" - android:text="@string/link_share_view_only" /> + android:text="@string/share_permission_view_only" /> + android:text="@string/share_permission_file_request" /> New %1$s %2$s + File request + View only + Can edit + Secure file drop + Choose what to sync Free up space %1$s is %2$s, but there is only %3$s available on device. @@ -1097,9 +1102,7 @@ Edit Share Delete - View only Editing - File request Could not retrieve shares Failed to update UI Failed to pick email address. @@ -1165,9 +1168,6 @@ Create Please select one template Please choose a template and enter a file name. - View only - Can edit - Secure file drop Share permissions Next Send share From a5839a224920e55fd9b9f24f1e6e17058df94838 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 15:45:11 +0200 Subject: [PATCH 079/110] add error checks Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 49 ++++++++++++++----- app/src/main/res/values/strings.xml | 3 ++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 4d2ed20ce03e..bbcb2ccbd39a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -24,7 +24,6 @@ import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.quickPermission.QuickPermissionType import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.status.OCCapability @@ -199,7 +198,7 @@ class FileDetailsSharingProcessFragment : setCheckboxStates() themeView() setVisibilitiesOfShareOption() - checkNextButtonAvailability() + toggleNextButtonAvailability(isAnyShareOptionChecked()) } private fun setVisibilitiesOfShareOption() { @@ -539,12 +538,20 @@ class FileDetailsSharingProcessFragment : toggleNextButtonAvailability(true) } - private fun checkNextButtonAvailability() { - var hasAnyPermission = false - if (share != null) { - hasAnyPermission = SharingMenuHelper.getSelectedType(share, isSecureShare) != QuickPermissionType.NONE + private fun isAnyShareOptionChecked(): Boolean { + return binding.run { + val isCustomPermissionChecked = customPermissionRadioButton.isChecked && + (shareReadCheckbox.isChecked || + shareCreateCheckbox.isChecked || + shareEditCheckbox.isChecked || + shareCheckbox.isChecked || + shareDeleteCheckbox.isChecked) + + viewOnlyRadioButton.isChecked || + canEditRadioButton.isChecked || + fileRequestRadioButton.isChecked || + isCustomPermissionChecked } - toggleNextButtonAvailability(hasAnyPermission) } private fun toggleNextButtonAvailability(value: Boolean) { @@ -718,13 +725,31 @@ class FileDetailsSharingProcessFragment : } private fun createShareOrUpdateNoteShare() { + if (!isAnyShareOptionChecked()) { + DisplayUtils.showSnackMessage(requireActivity(), R.string.share_option_required) + return + } + val noteText = binding.noteText.text.toString().trim() - // if modifying existing share then directly update the note and send email - if (share != null && share?.note != noteText) { - fileOperationsHelper?.updateNoteToShare(share, noteText) - } else { - createShare(noteText) + if (file == null && (share != null && share?.note == noteText)) { + DisplayUtils.showSnackMessage(requireActivity(), R.string.share_cannot_update_empty_note) + return } + + when { + // if modifying existing share then directly update the note and send email + share != null && share?.note != noteText -> { + fileOperationsHelper?.updateNoteToShare(share, noteText) + } + file == null -> { + DisplayUtils.showSnackMessage(requireActivity(), R.string.file_not_found_cannot_share) + return + } + else -> { + createShare(noteText) + } + } + removeCurrentFragment() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76ad27e9918f..274cee97f0fd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1097,6 +1097,9 @@ Share link Custom permissions Read + File not found. Unable to create a share. + We couldn’t update the share. Please add a note and try again. + Please select at least one sharing option before continuing. Allow download and sync Create Edit From a0ad2e0c6aaff86f7c9187224fce55697f2bcdb9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 8 May 2025 15:50:17 +0200 Subject: [PATCH 080/110] fix code analytics Signed-off-by: alperozturk --- .../android/datamodel/quickPermission/QuickPermission.kt | 2 +- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt index b6be8070156c..460edeb33350 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/quickPermission/QuickPermission.kt @@ -7,4 +7,4 @@ package com.owncloud.android.datamodel.quickPermission -data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) \ No newline at end of file +data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index bbcb2ccbd39a..cbf0d46e5455 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -724,6 +724,7 @@ class FileDetailsSharingProcessFragment : } } + @Suppress("ReturnCount") private fun createShareOrUpdateNoteShare() { if (!isAnyShareOptionChecked()) { DisplayUtils.showSnackMessage(requireActivity(), R.string.share_option_required) From 638703bf772dcd247aa7cdf390c3ed8db187d3e4 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Mon, 19 May 2025 08:39:31 +0200 Subject: [PATCH 081/110] update lib Signed-off-by: tobiasKaminsky --- gradle/verification-metadata.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c217a0c43d54..4dd88676276f 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -11215,6 +11215,17 @@ + + + + + + + + From 7339c3769f9260ce381e33d2e43b4d6653924ddf Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 12:39:07 +0800 Subject: [PATCH 082/110] fix merge conflict Signed-off-by: alperozturk --- .../90.json | 1355 +++++++++++++++++ .../client/database/NextcloudDatabase.kt | 3 +- .../com/owncloud/android/db/ProviderMeta.java | 2 +- gradle/verification-metadata.xml | 27 +- 4 files changed, 1374 insertions(+), 13 deletions(-) create mode 100644 app/schemas/com.nextcloud.client.database.NextcloudDatabase/90.json diff --git a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/90.json b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/90.json new file mode 100644 index 000000000000..c0b53e5fd543 --- /dev/null +++ b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/90.json @@ -0,0 +1,1355 @@ +{ + "formatVersion": 1, + "database": { + "version": 90, + "identityHash": "93eb4d5fbf952984b6fc2df9f7c369e1", + "entities": [ + { + "tableName": "arbitrary_data", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "cloudId", + "columnName": "cloud_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "capabilities", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `assistant` INTEGER, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER, `forbidden_filename_characters` INTEGER, `forbidden_filenames` INTEGER, `forbidden_filename_extensions` INTEGER, `forbidden_filename_basenames` INTEGER, `files_download_limit` INTEGER, `files_download_limit_default` INTEGER, `recommendation` INTEGER, `notes_folder_path` TEXT, `default_permissions` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "assistant", + "columnName": "assistant", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "accountName", + "columnName": "account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionMajor", + "columnName": "version_mayor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "versionMinor", + "columnName": "version_minor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "versionMicro", + "columnName": "version_micro", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "versionString", + "columnName": "version_string", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionEditor", + "columnName": "version_edition", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "extendedSupport", + "columnName": "extended_support", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "corePollinterval", + "columnName": "core_pollinterval", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingApiEnabled", + "columnName": "sharing_api_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicEnabled", + "columnName": "sharing_public_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicPasswordEnforced", + "columnName": "sharing_public_password_enforced", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicExpireDateEnabled", + "columnName": "sharing_public_expire_date_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicExpireDateDays", + "columnName": "sharing_public_expire_date_days", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicExpireDateEnforced", + "columnName": "sharing_public_expire_date_enforced", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicSendMail", + "columnName": "sharing_public_send_mail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicUpload", + "columnName": "sharing_public_upload", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingUserSendMail", + "columnName": "sharing_user_send_mail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingResharing", + "columnName": "sharing_resharing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingFederationOutgoing", + "columnName": "sharing_federation_outgoing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingFederationIncoming", + "columnName": "sharing_federation_incoming", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesBigfilechunking", + "columnName": "files_bigfilechunking", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesUndelete", + "columnName": "files_undelete", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesVersioning", + "columnName": "files_versioning", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "externalLinks", + "columnName": "external_links", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "serverName", + "columnName": "server_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverColor", + "columnName": "server_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverTextColor", + "columnName": "server_text_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverElementColor", + "columnName": "server_element_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverSlogan", + "columnName": "server_slogan", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverLogo", + "columnName": "server_logo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverBackgroundUrl", + "columnName": "background_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endToEndEncryption", + "columnName": "end_to_end_encryption", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "endToEndEncryptionKeysExist", + "columnName": "end_to_end_encryption_keys_exist", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "endToEndEncryptionApiVersion", + "columnName": "end_to_end_encryption_api_version", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "activity", + "columnName": "activity", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "serverBackgroundDefault", + "columnName": "background_default", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "serverBackgroundPlain", + "columnName": "background_plain", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocument", + "columnName": "richdocument", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentMimetypeList", + "columnName": "richdocument_mimetype_list", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "richdocumentDirectEditing", + "columnName": "richdocument_direct_editing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentTemplates", + "columnName": "richdocument_direct_templates", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentOptionalMimetypeList", + "columnName": "richdocument_optional_mimetype_list", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharingPublicAskForOptionalPassword", + "columnName": "sharing_public_ask_for_optional_password", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentProductName", + "columnName": "richdocument_product_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "directEditingEtag", + "columnName": "direct_editing_etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "userStatus", + "columnName": "user_status", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "userStatusSupportsEmoji", + "columnName": "user_status_supports_emoji", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filesLockingVersion", + "columnName": "files_locking_version", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "groupfolders", + "columnName": "groupfolders", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dropAccount", + "columnName": "drop_account", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "securityGuard", + "columnName": "security_guard", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "forbiddenFileNameCharacters", + "columnName": "forbidden_filename_characters", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "forbiddenFileNames", + "columnName": "forbidden_filenames", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "forbiddenFileNameExtensions", + "columnName": "forbidden_filename_extensions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "forbiddenFilenameBaseNames", + "columnName": "forbidden_filename_basenames", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesDownloadLimit", + "columnName": "files_download_limit", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesDownloadLimitDefault", + "columnName": "files_download_limit_default", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "recommendation", + "columnName": "recommendation", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "notesFolderPath", + "columnName": "notes_folder_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "defaultPermissions", + "columnName": "default_permissions", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "external_links", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `icon_url` TEXT, `language` TEXT, `type` INTEGER, `name` TEXT, `url` TEXT, `redirect` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "language", + "columnName": "language", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "redirect", + "columnName": "redirect", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "filelist", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `filename` TEXT, `encrypted_filename` TEXT, `path` TEXT, `path_decrypted` TEXT, `parent` INTEGER, `created` INTEGER, `modified` INTEGER, `content_type` TEXT, `content_length` INTEGER, `media_path` TEXT, `file_owner` TEXT, `last_sync_date` INTEGER, `last_sync_date_for_data` INTEGER, `modified_at_last_sync_for_data` INTEGER, `etag` TEXT, `etag_on_server` TEXT, `share_by_link` INTEGER, `permissions` TEXT, `remote_id` TEXT, `local_id` INTEGER NOT NULL DEFAULT -1, `update_thumbnail` INTEGER, `is_downloading` INTEGER, `favorite` INTEGER, `hidden` INTEGER, `is_encrypted` INTEGER, `etag_in_conflict` TEXT, `shared_via_users` INTEGER, `mount_type` INTEGER, `has_preview` INTEGER, `unread_comments_count` INTEGER, `owner_id` TEXT, `owner_display_name` TEXT, `note` TEXT, `sharees` TEXT, `rich_workspace` TEXT, `metadata_size` TEXT, `metadata_live_photo` TEXT, `locked` INTEGER, `lock_type` INTEGER, `lock_owner` TEXT, `lock_owner_display_name` TEXT, `lock_owner_editor` TEXT, `lock_timestamp` INTEGER, `lock_timeout` INTEGER, `lock_token` TEXT, `tags` TEXT, `metadata_gps` TEXT, `e2e_counter` INTEGER, `internal_two_way_sync_timestamp` INTEGER, `internal_two_way_sync_result` TEXT, `uploaded` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "filename", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "encryptedName", + "columnName": "encrypted_filename", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pathDecrypted", + "columnName": "path_decrypted", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "creation", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "modified", + "columnName": "modified", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contentLength", + "columnName": "content_length", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "storagePath", + "columnName": "media_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "accountOwner", + "columnName": "file_owner", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastSyncDate", + "columnName": "last_sync_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastSyncDateForData", + "columnName": "last_sync_date_for_data", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "modifiedAtLastSyncForData", + "columnName": "modified_at_last_sync_for_data", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "etagOnServer", + "columnName": "etag_on_server", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedViaLink", + "columnName": "share_by_link", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remote_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "localId", + "columnName": "local_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "updateThumbnail", + "columnName": "update_thumbnail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isDownloading", + "columnName": "is_downloading", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "favorite", + "columnName": "favorite", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isEncrypted", + "columnName": "is_encrypted", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etagInConflict", + "columnName": "etag_in_conflict", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedWithSharee", + "columnName": "shared_via_users", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mountType", + "columnName": "mount_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hasPreview", + "columnName": "has_preview", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "unreadCommentsCount", + "columnName": "unread_comments_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "ownerId", + "columnName": "owner_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ownerDisplayName", + "columnName": "owner_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharees", + "columnName": "sharees", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "richWorkspace", + "columnName": "rich_workspace", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "metadataSize", + "columnName": "metadata_size", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "metadataLivePhoto", + "columnName": "metadata_live_photo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockType", + "columnName": "lock_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockOwner", + "columnName": "lock_owner", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lockOwnerDisplayName", + "columnName": "lock_owner_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lockOwnerEditor", + "columnName": "lock_owner_editor", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lockTimestamp", + "columnName": "lock_timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockTimeout", + "columnName": "lock_timeout", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockToken", + "columnName": "lock_token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "metadataGPS", + "columnName": "metadata_gps", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "e2eCounter", + "columnName": "e2e_counter", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "internalTwoWaySync", + "columnName": "internal_two_way_sync_timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "internalTwoWaySyncResult", + "columnName": "internal_two_way_sync_result", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaded", + "columnName": "uploaded", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "filesystem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `is_folder` INTEGER, `found_at` INTEGER, `upload_triggered` INTEGER, `syncedfolder_id` TEXT, `crc32` TEXT, `modified_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileIsFolder", + "columnName": "is_folder", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileFoundRecently", + "columnName": "found_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileSentForUpload", + "columnName": "upload_triggered", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "syncedFolderId", + "columnName": "syncedfolder_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "crc32", + "columnName": "crc32", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileModified", + "columnName": "modified_at", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ocshares", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` TEXT, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT, `download_limit_limit` INTEGER, `download_limit_count` INTEGER, `attributes` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileSource", + "columnName": "file_source", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "itemSource", + "columnName": "item_source", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "shareType", + "columnName": "share_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "shareWith", + "columnName": "shate_with", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharedDate", + "columnName": "shared_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "expirationDate", + "columnName": "expiration_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shareWithDisplayName", + "columnName": "shared_with_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDirectory", + "columnName": "is_directory", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "idRemoteShared", + "columnName": "id_remote_shared", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "accountOwner", + "columnName": "owner_share", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isPasswordProtected", + "columnName": "is_password_protected", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "hideDownload", + "columnName": "hide_download", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "shareLink", + "columnName": "share_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shareLabel", + "columnName": "share_label", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "downloadLimitLimit", + "columnName": "download_limit_limit", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "downloadLimitCount", + "columnName": "download_limit_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "synced_folders", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `wifi_only` INTEGER, `charging_only` INTEGER, `existing` INTEGER, `enabled` INTEGER, `enabled_timestamp_ms` INTEGER, `subfolder_by_date` INTEGER, `account` TEXT, `upload_option` INTEGER, `name_collision_policy` INTEGER, `type` INTEGER, `hidden` INTEGER, `sub_folder_rule` INTEGER, `exclude_hidden` INTEGER, `last_scan_timestamp_ms` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remotePath", + "columnName": "remote_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "wifiOnly", + "columnName": "wifi_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "chargingOnly", + "columnName": "charging_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "existing", + "columnName": "existing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "enabledTimestampMs", + "columnName": "enabled_timestamp_ms", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "subfolderByDate", + "columnName": "subfolder_by_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploadAction", + "columnName": "upload_option", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nameCollisionPolicy", + "columnName": "name_collision_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "subFolderRule", + "columnName": "sub_folder_rule", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "excludeHidden", + "columnName": "exclude_hidden", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastScanTimestampMs", + "columnName": "last_scan_timestamp_ms", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "list_of_uploads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `account_name` TEXT, `file_size` INTEGER, `status` INTEGER, `local_behaviour` INTEGER, `upload_time` INTEGER, `name_collision_policy` INTEGER, `is_create_remote_folder` INTEGER, `upload_end_timestamp` INTEGER, `last_result` INTEGER, `is_while_charging_only` INTEGER, `is_wifi_only` INTEGER, `created_by` INTEGER, `folder_unlock_token` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remotePath", + "columnName": "remote_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileSize", + "columnName": "file_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localBehaviour", + "columnName": "local_behaviour", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uploadTime", + "columnName": "upload_time", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nameCollisionPolicy", + "columnName": "name_collision_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isCreateRemoteFolder", + "columnName": "is_create_remote_folder", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uploadEndTimestamp", + "columnName": "upload_end_timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastResult", + "columnName": "last_result", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isWhileChargingOnly", + "columnName": "is_while_charging_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isWifiOnly", + "columnName": "is_wifi_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdBy", + "columnName": "created_by", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "folderUnlockToken", + "columnName": "folder_unlock_token", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "virtual", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `ocfile_id` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ocFileId", + "columnName": "ocfile_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "offline_operations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `offline_operations_parent_oc_file_id` INTEGER, `offline_operations_path` TEXT, `offline_operations_type` TEXT, `offline_operations_file_name` TEXT, `offline_operations_created_at` INTEGER, `offline_operations_modified_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "parentOCFileId", + "columnName": "offline_operations_parent_oc_file_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "offline_operations_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "offline_operations_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filename", + "columnName": "offline_operations_file_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "offline_operations_created_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "modifiedAt", + "columnName": "offline_operations_modified_at", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '93eb4d5fbf952984b6fc2df9f7c369e1')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt index 6f0dfca9ca9c..55177ef6e4cf 100644 --- a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt +++ b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt @@ -72,7 +72,8 @@ import com.owncloud.android.db.ProviderMeta AutoMigration(from = 85, to = 86, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), AutoMigration(from = 86, to = 87, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), AutoMigration(from = 87, to = 88, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), - AutoMigration(from = 88, to = 89) + AutoMigration(from = 88, to = 89), + AutoMigration(from = 89, to = 90) ], exportSchema = true ) diff --git a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java index cda0cc1b80dc..120da6ac9d8a 100644 --- a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -25,7 +25,7 @@ */ public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 89; + public static final int DB_VERSION = 90; private ProviderMeta() { // No instance diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 4dd88676276f..50bf059b60f1 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -11215,17 +11215,14 @@ - - - - - - - - + + + + + + + + @@ -11610,6 +11607,14 @@ + + + + + + + + From 2687e38b91e0b291363b3ed7d1b9781de435fb14 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 12:54:28 +0800 Subject: [PATCH 083/110] fix code analytics Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index cbf0d46e5455..97dc408a952c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -541,11 +541,13 @@ class FileDetailsSharingProcessFragment : private fun isAnyShareOptionChecked(): Boolean { return binding.run { val isCustomPermissionChecked = customPermissionRadioButton.isChecked && - (shareReadCheckbox.isChecked || - shareCreateCheckbox.isChecked || - shareEditCheckbox.isChecked || - shareCheckbox.isChecked || - shareDeleteCheckbox.isChecked) + ( + shareReadCheckbox.isChecked || + shareCreateCheckbox.isChecked || + shareEditCheckbox.isChecked || + shareCheckbox.isChecked || + shareDeleteCheckbox.isChecked + ) viewOnlyRadioButton.isChecked || canEditRadioButton.isChecked || From fcbd3da7e9bdfe0902e39a5bed87ffce41301adf Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 18:38:18 +0800 Subject: [PATCH 084/110] prevent shared file, shared back Signed-off-by: alperozturk --- .../ui/fragment/FileDetailFragment.java | 36 ++++++++++++------- app/src/main/res/values/strings.xml | 1 + 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index b5f567d34424..3ad6b09a1386 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -72,6 +72,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import javax.inject.Inject; @@ -509,11 +510,11 @@ public void onClick(View v) { setFileModificationTimestamp(getFile(), showDetailedTimestamp); } else if (id == R.id.folder_sync_button) { if (binding.folderSyncButton.isChecked()) { - getFile().setInternalFolderSyncTimestamp(0L); + getFile().setInternalFolderSyncTimestamp(0L); } else { getFile().setInternalFolderSyncTimestamp(-1L); } - + storageManager.saveFile(getFile()); } else { Log_OC.e(TAG, "Incorrect view clicked!"); @@ -598,11 +599,11 @@ public void updateFileDetails(boolean transferring, boolean refresh) { if (fabMain != null) { fabMain.hide(); } - + binding.syncBlock.setVisibility(file.isFolder() ? View.VISIBLE : View.GONE); - + if (file.isInternalFolderSync()) { - binding.folderSyncButton.setChecked(file.isInternalFolderSync()); + binding.folderSyncButton.setChecked(file.isInternalFolderSync()); } else { if (storageManager.isPartOfInternalTwoWaySync(file)) { binding.folderSyncButton.setChecked(true); @@ -814,18 +815,27 @@ private void showEmptyContent() { /** * open the sharing process fragment for creating new share * - * @param shareeName - * @param shareType */ public void initiateSharingProcess(String shareeName, ShareType shareType, boolean secureShare) { - requireActivity().getSupportFragmentManager().beginTransaction().add(R.id.sharing_frame_container, - FileDetailsSharingProcessFragment.newInstance(getFile(), - shareeName, - shareType, - secureShare), - FileDetailsSharingProcessFragment.TAG) + if (getFile() == null) { + DisplayUtils.showSnackMessage(requireView(), R.string.file_not_found_cannot_share); + return; + } + + final var file = getFile(); + if (Objects.equals(file.getOwnerId(), shareeName)) { + DisplayUtils.showSnackMessage(requireView(), R.string.file_detail_share_already_active); + return; + } + + final var fileShareDetailFragment = FileDetailsSharingProcessFragment.newInstance(file, shareeName, shareType, secureShare); + + requireActivity() + .getSupportFragmentManager() + .beginTransaction() + .add(R.id.sharing_frame_container, fileShareDetailFragment, FileDetailsSharingProcessFragment.TAG) .commit(); showHideFragmentView(true); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 274cee97f0fd..512d252ab328 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -836,6 +836,7 @@ Background image of drawer header Account icon No app available to select contacts + You cannot create a share, sharing is already active from this user. Failed to verify public key Unable to retrieve public key From 29fb583059dd75c74913e634e6d39f14a6cf437f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 18:54:25 +0800 Subject: [PATCH 085/110] fix Share link naming Signed-off-by: alperozturk --- .../ui/adapter/LinkShareViewHolder.java | 41 +++++++++++-------- .../android/ui/adapter/ShareeListAdapter.java | 2 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index 4f545df52ad9..35eb47ed6eb7 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -30,6 +30,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; import androidx.recyclerview.widget.RecyclerView; @@ -54,30 +55,34 @@ public LinkShareViewHolder(FileDetailsShareLinkShareItemBinding binding, this.encrypted = encrypted; } - public void bind(OCShare publicShare, ShareeListAdapterListener listener) { + public void bind(OCShare publicShare, ShareeListAdapterListener listener, int position) { if (ShareType.EMAIL == publicShare.getShareType()) { + final var res = context.getResources(); binding.name.setText(publicShare.getSharedWithDisplayName()); - binding.icon.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), - R.drawable.ic_email, - null)); + + final var emailDrawable = ResourcesCompat.getDrawable(res, R.drawable.ic_email, null); + binding.icon.setImageDrawable(emailDrawable); binding.copyLink.setVisibility(View.GONE); - binding.icon.getBackground().setColorFilter(context.getResources().getColor(R.color.nc_grey), - PorterDuff.Mode.SRC_IN); - binding.icon.getDrawable().mutate().setColorFilter(context.getResources().getColor(R.color.icon_on_nc_grey), - PorterDuff.Mode.SRC_IN); + final var backgroundColor = ContextCompat.getColor(context, R.color.nc_grey); + binding.icon.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC_IN); + + final var drawableColor = ContextCompat.getColor(context, R.color.icon_on_nc_grey); + binding.icon.getDrawable().mutate().setColorFilter(drawableColor, PorterDuff.Mode.SRC_IN); } else { - if (!TextUtils.isEmpty(publicShare.getLabel())) { - String text = String.format(context.getString(R.string.share_link_with_label), publicShare.getLabel()); - binding.name.setText(text); + String label = publicShare.getLabel(); + + if (!TextUtils.isEmpty(label)) { + binding.name.setText(context.getString(R.string.share_link_with_label, label)); + } else if (SharingMenuHelper.isFileRequest(publicShare)) { + binding.name.setText(R.string.share_permission_file_request); + } else if (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted) { + binding.name.setText(R.string.share_permission_secure_file_drop); } else { - if (SharingMenuHelper.isFileRequest(publicShare)) { - binding.name.setText(context.getResources().getString(R.string.share_permission_file_request)); - } else if (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted) { - binding.name.setText(context.getResources().getString(R.string.share_permission_secure_file_drop)); - } else { - binding.name.setText(R.string.share_link); - } + int textRes = (position == 0) ? R.string.share_link : R.string.share_link_with_label; + Object arg = (position == 0) ? null : String.valueOf(position); + binding.name.setText((position == 0) ? context.getString(textRes) + : context.getString(textRes, arg)); } viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index bd2b9c29d1c2..ccb916cc6147 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -156,7 +156,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (holder instanceof LinkShareViewHolder publicShareViewHolder) { - publicShareViewHolder.bind(share, listener); + publicShareViewHolder.bind(share, listener, position); } else if (holder instanceof InternalShareViewHolder internalShareViewHolder) { internalShareViewHolder.bind(share, listener); } else if (holder instanceof NewLinkShareViewHolder newLinkShareViewHolder) { From b5aee03178293c671978bcbafbaf54004576cef3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 18:58:46 +0800 Subject: [PATCH 086/110] fix show all and show less text visibility for external sharee list adapter Signed-off-by: alperozturk --- .../ui/fragment/FileDetailSharingFragment.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 03bcaa459694..3ad54da5c934 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -253,23 +253,15 @@ private void setupView() { viewThemeUtils.material.colorMaterialTextButton(binding.sharesListInternalShowAll); binding.sharesListInternalShowAll.setOnClickListener(view -> { internalShareeListAdapter.toggleShowAll(); - - if (internalShareeListAdapter.isShowAll()) { - binding.sharesListInternalShowAll.setText(R.string.show_less); - } else { - binding.sharesListInternalShowAll.setText(R.string.show_all); - } + int textRes = internalShareeListAdapter.isShowAll() ? R.string.show_less : R.string.show_all; + binding.sharesListInternalShowAll.setText(textRes); }); - + viewThemeUtils.material.colorMaterialTextButton(binding.sharesListExternalShowAll); binding.sharesListExternalShowAll.setOnClickListener(view -> { externalShareeListAdapter.toggleShowAll(); - - if (internalShareeListAdapter.isShowAll()) { - binding.sharesListExternalShowAll.setText(R.string.show_less); - } else { - binding.sharesListExternalShowAll.setText(R.string.show_all); - } + int textRes = externalShareeListAdapter.isShowAll() ? R.string.show_less : R.string.show_all; + binding.sharesListExternalShowAll.setText(textRes); }); if (file.canReshare() && !FileDetailSharingFragmentHelper.isPublicShareDisabled(capabilities)) { From 8cfbd270780e140ef956d9f313a93f10dbb4d3f6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 19:19:21 +0800 Subject: [PATCH 087/110] make background color blue for link shares Signed-off-by: alperozturk --- .../android/ui/adapter/LinkShareViewHolder.java | 12 ++---------- .../android/ui/adapter/ShareeListAdapter.java | 1 - 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index 35eb47ed6eb7..660647255a77 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -15,7 +15,6 @@ package com.owncloud.android.ui.adapter; import android.content.Context; -import android.graphics.PorterDuff; import android.text.TextUtils; import android.view.View; @@ -30,7 +29,6 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import androidx.annotation.NonNull; -import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; import androidx.recyclerview.widget.RecyclerView; @@ -63,12 +61,6 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener, int po final var emailDrawable = ResourcesCompat.getDrawable(res, R.drawable.ic_email, null); binding.icon.setImageDrawable(emailDrawable); binding.copyLink.setVisibility(View.GONE); - - final var backgroundColor = ContextCompat.getColor(context, R.color.nc_grey); - binding.icon.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC_IN); - - final var drawableColor = ContextCompat.getColor(context, R.color.icon_on_nc_grey); - binding.icon.getDrawable().mutate().setColorFilter(drawableColor, PorterDuff.Mode.SRC_IN); } else { String label = publicShare.getLabel(); @@ -84,10 +76,10 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener, int po binding.name.setText((position == 0) ? context.getString(textRes) : context.getString(textRes, arg)); } - - viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon); } + viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon); + FileDownloadLimit downloadLimit = publicShare.getFileDownloadLimit(); if (downloadLimit != null && downloadLimit.getLimit() > 0) { int remaining = downloadLimit.getLimit() - downloadLimit.getCount(); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index ccb916cc6147..16be239081ff 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -154,7 +154,6 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi return; } - if (holder instanceof LinkShareViewHolder publicShareViewHolder) { publicShareViewHolder.bind(share, listener, position); } else if (holder instanceof InternalShareViewHolder internalShareViewHolder) { From f196dda20b352bafab600fff506c69f3d5771903 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 26 May 2025 20:27:05 +0800 Subject: [PATCH 088/110] for empty user name use default user icon Signed-off-by: alperozturk --- .../utils/extensions/ImageViewExtensions.kt | 49 +++++++++++++++++++ .../android/ui/adapter/ShareViewHolder.java | 7 +++ 2 files changed, 56 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt new file mode 100644 index 000000000000..896d26dca84e --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt @@ -0,0 +1,49 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils.extensions + +import android.content.Context +import android.graphics.drawable.GradientDrawable +import android.util.TypedValue +import android.view.ViewOutlineProvider +import android.widget.ImageView +import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes +import androidx.core.content.ContextCompat +import com.owncloud.android.R + +@JvmOverloads +fun ImageView.makeRoundedWithIcon( + context: Context, + @DrawableRes icon: Int, + paddingDp: Int = 6, + @ColorInt backgroundColor: Int = ContextCompat.getColor(context, R.color.primary), + @ColorInt foregroundColor: Int = ContextCompat.getColor(context, R.color.white) +) { + setImageResource(icon) + + val drawable = GradientDrawable().apply { + shape = GradientDrawable.OVAL + setColor(backgroundColor) + } + + background = drawable + clipToOutline = true + scaleType = ImageView.ScaleType.CENTER_INSIDE + outlineProvider = ViewOutlineProvider.BACKGROUND + + setColorFilter(foregroundColor) + + val paddingPx = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + paddingDp.toFloat(), + context.resources.displayMetrics + ).toInt() + + setPadding(paddingPx, paddingPx, paddingPx, paddingPx) +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index bfe4e527c5fc..c592ac14a4ca 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -19,6 +19,7 @@ import android.widget.ImageView; import com.nextcloud.client.account.User; +import com.nextcloud.utils.extensions.ImageViewExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsShareShareItemBinding; import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; @@ -131,6 +132,12 @@ private void setPermissionName(String permissionName) { } private void setImage(ImageView avatar, String name, @DrawableRes int fallback) { + if (TextUtils.isEmpty(name)) { + ImageViewExtensionsKt.makeRoundedWithIcon(avatar, context, fallback); + viewThemeUtils.platform.colorImageViewBackgroundAndIcon(avatar); + return; + } + try { avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension)); } catch (StringIndexOutOfBoundsException e) { From 2917435fb643ada98b545d3da783db131bfd9462 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 12:33:15 +0800 Subject: [PATCH 089/110] extract setUserImage Signed-off-by: alperozturk --- .../android/ui/adapter/ShareViewHolder.java | 85 ++++++++++--------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index c592ac14a4ca..9c6a22d72684 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -29,7 +29,6 @@ import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -72,43 +71,49 @@ public void bind(OCShare share, binding.icon.setTag(null); - switch (share.getShareType()) { - case GROUP: - name = context.getString(R.string.share_group_clarification, name); - viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context); - break; - case ROOM: - name = context.getString(R.string.share_room_clarification, name); - viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context); - break; - case CIRCLE: - viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context); - break; - case FEDERATED: - name = context.getString(R.string.share_remote_clarification, name); - setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_user); - break; - case USER: - binding.icon.setTag(share.getShareWith()); - float avatarRadius = context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius); - DisplayUtils.setAvatar(user, - share.getShareWith(), - share.getSharedWithDisplayName(), - avatarListener, - avatarRadius, - context.getResources(), - binding.icon, - context); - - binding.icon.setOnClickListener(v -> listener.showProfileBottomSheet(user, share.getShareWith())); - default: - setImage(binding.icon, name, R.drawable.ic_user); - break; + if (share.getShareType() != null) { + switch (share.getShareType()) { + case GROUP: + name = context.getString(R.string.share_group_clarification, name); + viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context); + break; + case ROOM: + name = context.getString(R.string.share_room_clarification, name); + viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context); + break; + case CIRCLE: + viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context); + break; + case FEDERATED: + name = context.getString(R.string.share_remote_clarification, name); + setImage(binding.icon, share.getSharedWithDisplayName()); + break; + case USER: + binding.icon.setTag(share.getShareWith()); + float avatarRadius = context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius); + + if (share.getShareWith() != null) { + DisplayUtils.setAvatar(user, + share.getShareWith(), + share.getSharedWithDisplayName(), + avatarListener, + avatarRadius, + context.getResources(), + binding.icon, + context); + } + + binding.icon.setOnClickListener(v -> listener.showProfileBottomSheet(user, share.getShareWith())); + default: + setImage(binding.icon, name); + break; + } } binding.name.setText(name); - if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) { + if (share.getShareWith() != null && share.getShareWith().equalsIgnoreCase(userId) || + share.getUserId() != null && share.getUserId().equalsIgnoreCase(userId)) { binding.overflowMenu.setVisibility(View.VISIBLE); QuickPermissionType quickPermissionType = SharingMenuHelper.getSelectedType(share, encrypted); @@ -131,17 +136,21 @@ private void setPermissionName(String permissionName) { } } - private void setImage(ImageView avatar, String name, @DrawableRes int fallback) { + private void setImage(ImageView avatar, String name) { if (TextUtils.isEmpty(name)) { - ImageViewExtensionsKt.makeRoundedWithIcon(avatar, context, fallback); - viewThemeUtils.platform.colorImageViewBackgroundAndIcon(avatar); + setUserImage(avatar); return; } try { avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension)); } catch (StringIndexOutOfBoundsException e) { - avatar.setImageResource(fallback); + setUserImage(avatar); } } + + private void setUserImage(ImageView avatar) { + ImageViewExtensionsKt.makeRoundedWithIcon(avatar, context, R.drawable.ic_user); + viewThemeUtils.platform.colorImageViewBackgroundAndIcon(avatar); + } } From 01f5f2ff1ccae9bca03f00c09b97ad9c3b5f4c3f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 14:03:10 +0800 Subject: [PATCH 090/110] remove ShareMenuHelper Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 46 ++++----- .../ui/adapter/LinkShareViewHolder.java | 12 +-- .../android/ui/adapter/ShareViewHolder.java | 4 +- ...ileDetailSharingMenuBottomSheetDialog.java | 4 +- .../FileDetailsSharingProcessFragment.kt | 24 +++-- ...ckSharingPermissionsBottomSheetDialog.java | 4 +- .../fragment/util/SharePermissionManager.kt | 99 +++++++++++++++---- .../ui/fragment/util/SharingMenuHelper.java | 88 ----------------- 8 files changed, 124 insertions(+), 157 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 79d147a6038b..60c7ad9f763d 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -41,7 +41,7 @@ import com.owncloud.android.lib.resources.shares.OCShare.Companion.READ_PERMISSI import com.owncloud.android.lib.resources.shares.OCShare.Companion.SHARE_PERMISSION_FLAG import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.ui.activity.FileDisplayActivity -import com.owncloud.android.ui.fragment.util.SharingMenuHelper +import com.owncloud.android.ui.fragment.util.SharePermissionManager import com.owncloud.android.utils.EspressoIdlingResource import com.owncloud.android.utils.ScreenshotTest import org.hamcrest.CoreMatchers.allOf @@ -890,22 +890,22 @@ class FileDetailSharingFragmentIT : AbstractIT() { val share = OCShare().apply { permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER } - assertTrue(SharingMenuHelper.canEdit(share)) + assertTrue(SharePermissionManager.canEdit(share)) share.permissions = NO_PERMISSION - assertFalse(SharingMenuHelper.canEdit(share)) + assertFalse(SharePermissionManager.canEdit(share)) share.permissions = READ_PERMISSION_FLAG - assertFalse(SharingMenuHelper.canEdit(share)) + assertFalse(SharePermissionManager.canEdit(share)) share.permissions = CREATE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.canEdit(share)) + assertFalse(SharePermissionManager.canEdit(share)) share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.canEdit(share)) + assertFalse(SharePermissionManager.canEdit(share)) share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.canEdit(share)) + assertFalse(SharePermissionManager.canEdit(share)) } @Test @@ -914,28 +914,28 @@ class FileDetailSharingFragmentIT : AbstractIT() { val share = OCShare().apply { permissions = 17 } - assertTrue(SharingMenuHelper.isViewOnly(share)) + assertTrue(SharePermissionManager.isViewOnly(share)) share.permissions = NO_PERMISSION - assertFalse(SharingMenuHelper.isViewOnly(share)) + assertFalse(SharePermissionManager.isViewOnly(share)) share.permissions = READ_PERMISSION_FLAG - assertTrue(SharingMenuHelper.isViewOnly(share)) + assertTrue(SharePermissionManager.isViewOnly(share)) share.permissions = CREATE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isViewOnly(share)) + assertFalse(SharePermissionManager.isViewOnly(share)) share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isViewOnly(share)) + assertFalse(SharePermissionManager.isViewOnly(share)) share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isViewOnly(share)) + assertFalse(SharePermissionManager.isViewOnly(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - assertFalse(SharingMenuHelper.isViewOnly(share)) + assertFalse(SharePermissionManager.isViewOnly(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE - assertFalse(SharingMenuHelper.isViewOnly(share)) + assertFalse(SharePermissionManager.isViewOnly(share)) } @Test @@ -944,27 +944,27 @@ class FileDetailSharingFragmentIT : AbstractIT() { val share = OCShare().apply { permissions = 4 } - assertTrue(SharingMenuHelper.isFileRequest(share)) + assertTrue(SharePermissionManager.isFileRequest(share)) share.permissions = NO_PERMISSION - assertFalse(SharingMenuHelper.isFileRequest(share)) + assertFalse(SharePermissionManager.isFileRequest(share)) share.permissions = READ_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isFileRequest(share)) + assertFalse(SharePermissionManager.isFileRequest(share)) share.permissions = CREATE_PERMISSION_FLAG - assertTrue(SharingMenuHelper.isFileRequest(share)) + assertTrue(SharePermissionManager.isFileRequest(share)) share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isFileRequest(share)) + assertFalse(SharePermissionManager.isFileRequest(share)) share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharingMenuHelper.isFileRequest(share)) + assertFalse(SharePermissionManager.isFileRequest(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - assertFalse(SharingMenuHelper.isFileRequest(share)) + assertFalse(SharePermissionManager.isFileRequest(share)) share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE - assertFalse(SharingMenuHelper.isFileRequest(share)) + assertFalse(SharePermissionManager.isFileRequest(share)) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index 660647255a77..15e35a76093f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -25,7 +25,7 @@ import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; -import com.owncloud.android.ui.fragment.util.SharingMenuHelper; +import com.owncloud.android.ui.fragment.util.SharePermissionManager; import com.owncloud.android.utils.theme.ViewThemeUtils; import androidx.annotation.NonNull; @@ -66,9 +66,9 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener, int po if (!TextUtils.isEmpty(label)) { binding.name.setText(context.getString(R.string.share_link_with_label, label)); - } else if (SharingMenuHelper.isFileRequest(publicShare)) { + } else if (SharePermissionManager.INSTANCE.isFileRequest(publicShare)) { binding.name.setText(R.string.share_permission_file_request); - } else if (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted) { + } else if (SharePermissionManager.INSTANCE.isSecureFileDrop(publicShare) && encrypted) { binding.name.setText(R.string.share_permission_secure_file_drop); } else { int textRes = (position == 0) ? R.string.share_link : R.string.share_link_with_label; @@ -91,11 +91,11 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener, int po binding.subline.setVisibility(View.GONE); } - QuickPermissionType quickPermissionType = SharingMenuHelper.getSelectedType(publicShare, encrypted); + QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(publicShare, encrypted); setPermissionName(publicShare, quickPermissionType.getText(context)); binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare)); - if (!SharingMenuHelper.isSecureFileDrop(publicShare) && !encrypted) { + if (!SharePermissionManager.INSTANCE.isSecureFileDrop(publicShare) && !encrypted) { binding.shareByLinkContainer.setOnClickListener(v -> listener.showPermissionsDialog(publicShare)); } @@ -107,7 +107,7 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener, int po } private void setPermissionName(OCShare publicShare, String permissionName) { - if (TextUtils.isEmpty(permissionName) || (SharingMenuHelper.isSecureFileDrop(publicShare) && encrypted)) { + if (TextUtils.isEmpty(permissionName) || (SharePermissionManager.INSTANCE.isSecureFileDrop(publicShare) && encrypted)) { binding.permissionName.setVisibility(View.GONE); return; } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index 9c6a22d72684..974ea6d5655c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -25,7 +25,7 @@ import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.TextDrawable; -import com.owncloud.android.ui.fragment.util.SharingMenuHelper; +import com.owncloud.android.ui.fragment.util.SharePermissionManager; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; @@ -116,7 +116,7 @@ public void bind(OCShare share, share.getUserId() != null && share.getUserId().equalsIgnoreCase(userId)) { binding.overflowMenu.setVisibility(View.VISIBLE); - QuickPermissionType quickPermissionType = SharingMenuHelper.getSelectedType(share, encrypted); + QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(share, encrypted); setPermissionName(quickPermissionType.getText(context)); // bind listener to edit privileges diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java index 46d67917b7ef..86b21f332872 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java @@ -22,7 +22,7 @@ import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.ui.activity.FileActivity; -import com.owncloud.android.ui.fragment.util.SharingMenuHelper; +import com.owncloud.android.ui.fragment.util.SharePermissionManager; import com.owncloud.android.utils.theme.ViewThemeUtils; /** @@ -83,7 +83,7 @@ private void updateUI() { binding.menuShareSendLink.setVisibility(View.GONE); } - if (SharingMenuHelper.isSecureFileDrop(ocShare) && encrypted) { + if (SharePermissionManager.INSTANCE.isSecureFileDrop(ocShare) && encrypted) { binding.menuShareAdvancedPermissions.setVisibility(View.GONE); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 97dc408a952c..bb74617d335f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -30,7 +30,6 @@ import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment import com.owncloud.android.ui.fragment.util.SharePermissionManager -import com.owncloud.android.ui.fragment.util.SharingMenuHelper import com.owncloud.android.ui.helpers.FileOperationsHelper import com.owncloud.android.utils.ClipboardUtil import com.owncloud.android.utils.DisplayUtils @@ -135,7 +134,6 @@ class FileDetailsSharingProcessFragment : private var isReShareShown: Boolean = true // show or hide reShare option private var isExpDateShown: Boolean = true // show or hide expiry date option private var isSecureShare: Boolean = false - private val sharePermissionManager = SharePermissionManager() private lateinit var capabilities: OCCapability @@ -177,7 +175,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: sharePermissionManager.getMaximumPermission(isFolder()) + ?: SharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -291,14 +289,14 @@ class FileDetailsSharingProcessFragment : // custom permissions / read only / allow upload and editing / file request binding.run { when { - SharingMenuHelper.canEdit(share) -> canEditRadioButton.isChecked = true - SharingMenuHelper.isFileRequest(share) && share?.isFolder == true -> + SharePermissionManager.canEdit(share) -> canEditRadioButton.isChecked = true + SharePermissionManager.isFileRequest(share) && share?.isFolder == true -> fileRequestRadioButton.isChecked = true - SharingMenuHelper.isViewOnly(share) -> viewOnlyRadioButton.isChecked = true + SharePermissionManager.isViewOnly(share) -> viewOnlyRadioButton.isChecked = true else -> { - if (sharePermissionManager.isCustomPermission(share) || + if (SharePermissionManager.isCustomPermission(share) || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION ) { customPermissionRadioButton.isChecked = true @@ -394,7 +392,7 @@ class FileDetailsSharingProcessFragment : if (!isReShareShown) { shareCheckbox.visibility = View.GONE } - shareCheckbox.isChecked = SharingMenuHelper.canReshare(share) + shareCheckbox.isChecked = SharePermissionManager.canReshare(share) } } } @@ -406,7 +404,7 @@ class FileDetailsSharingProcessFragment : shareProcessSetPasswordSwitch.visibility = View.VISIBLE if (share != null) { - if (SharingMenuHelper.isFileRequest(share)) { + if (SharePermissionManager.isFileRequest(share)) { shareProcessHideDownloadCheckbox.visibility = View.GONE } else { shareProcessHideDownloadCheckbox.visibility = View.VISIBLE @@ -517,7 +515,7 @@ class FileDetailsSharingProcessFragment : } R.id.can_edit_radio_button -> { - permission = sharePermissionManager.getMaximumPermission(isFolder()) + permission = SharePermissionManager.getMaximumPermission(isFolder()) } R.id.file_request_radio_button -> { @@ -534,7 +532,7 @@ class FileDetailsSharingProcessFragment : } private fun togglePermission(isChecked: Boolean, permissionFlag: Int) { - permission = sharePermissionManager.togglePermission(isChecked, permission, permissionFlag) + permission = SharePermissionManager.togglePermission(isChecked, permission, permissionFlag) toggleNextButtonAvailability(true) } @@ -568,7 +566,7 @@ class FileDetailsSharingProcessFragment : val currentPermissions = share?.permissions ?: permission binding.run { - sharePermissionManager.run { + SharePermissionManager.run { shareReadCheckbox.isChecked = hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG) shareEditCheckbox.isChecked = hasPermission(currentPermissions, OCShare.UPDATE_PERMISSION_FLAG) shareCheckbox.isChecked = hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG) @@ -610,7 +608,7 @@ class FileDetailsSharingProcessFragment : if (!isPublicShare()) { binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> - share?.attributes = sharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) + share?.attributes = SharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 331cb2fe203b..fd4cf254a1f7 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -25,7 +25,7 @@ import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter; -import com.owncloud.android.ui.fragment.util.SharingMenuHelper; +import com.owncloud.android.ui.fragment.util.SharePermissionManager; import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.List; @@ -133,7 +133,7 @@ private void handlePermissionChanged(List quickPermissionList, * Prepare the list of permissions needs to be displayed on recyclerview */ private List getQuickPermissionList() { - final var selectedType = SharingMenuHelper.getSelectedType(ocShare, encrypted); + final var selectedType = SharePermissionManager.INSTANCE.getSelectedType(ocShare, encrypted); final var hasFileRequestPermission = OCShareExtensionsKt.hasFileRequestPermission(ocShare); return QuickPermissionType.Companion.getAvailablePermissions(hasFileRequestPermission, selectedType); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index c3735a0cbcdb..981ae038003a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -7,6 +7,7 @@ package com.owncloud.android.ui.fragment.util +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.attributes.ShareAttributes @@ -14,7 +15,7 @@ import com.owncloud.android.lib.resources.shares.attributes.ShareAttributesJsonH import com.owncloud.android.lib.resources.shares.attributes.getDownloadAttribute import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Companion.TAG -class SharePermissionManager { +object SharePermissionManager { fun togglePermission(isChecked: Boolean, permission: Int, permissionFlag: Int): Int { Log_OC.d(TAG, "togglePermission before: $permission") @@ -61,26 +62,6 @@ class SharePermissionManager { return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag } - @Suppress("ReturnCount") - fun isCustomPermission(share: OCShare?): Boolean { - if (share == null) return false - val permissions = share.permissions - if (permissions == OCShare.NO_PERMISSION) return false - - val hasRead = hasPermission(permissions, OCShare.READ_PERMISSION_FLAG) - if (!hasRead) return false - - val hasCreate = hasPermission(permissions, OCShare.CREATE_PERMISSION_FLAG) - val hasUpdate = hasPermission(permissions, OCShare.UPDATE_PERMISSION_FLAG) - val hasDelete = hasPermission(permissions, OCShare.DELETE_PERMISSION_FLAG) - val hasShare = hasPermission(permissions, OCShare.SHARE_PERMISSION_FLAG) - - return when { - share.isFolder -> hasCreate || hasUpdate || hasDelete || hasShare - else -> hasUpdate || hasShare - } - } - fun getMaximumPermission(isFolder: Boolean): Int { return if (isFolder) { OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER @@ -110,6 +91,82 @@ class SharePermissionManager { return getShareAttributes(share).getDownloadAttribute()?.value == true } + // region Helper Methods + fun canEdit(share: OCShare?): Boolean { + if (share == null) { + return false + } + + val permissionToCheck = if (share.isFolder) { + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + } else { + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + } + + return hasPermission(share.permissions, permissionToCheck) + } + + fun isViewOnly(share: OCShare?): Boolean { + return share?.permissions != OCShare.NO_PERMISSION && share?.permissions == OCShare.READ_PERMISSION_FLAG + } + + fun isFileRequest(share: OCShare?): Boolean { + return share?.permissions != OCShare.NO_PERMISSION && share?.permissions == OCShare.CREATE_PERMISSION_FLAG + } + + fun isSecureFileDrop(share: OCShare?): Boolean { + if (share == null) { + return false + } + + return hasPermission(share.permissions, OCShare.CREATE_PERMISSION_FLAG + OCShare.READ_PERMISSION_FLAG) + } + + fun canReshare(share: OCShare?): Boolean { + if (share == null) { + return false + } + + return (share.permissions and OCShare.Companion.SHARE_PERMISSION_FLAG) > 0 + } + + fun getSelectedType(share: OCShare, encrypted: Boolean): QuickPermissionType { + return if (canEdit(share)) { + QuickPermissionType.CAN_EDIT + } else if (encrypted && isSecureFileDrop(share)) { + QuickPermissionType.SECURE_FILE_DROP + } else if (isFileRequest(share)) { + QuickPermissionType.FILE_REQUEST + } else if (isViewOnly(share)) { + QuickPermissionType.VIEW_ONLY + } else if (isCustomPermission(share)) { + QuickPermissionType.CUSTOM_PERMISSIONS + } else { + QuickPermissionType.NONE + } + } + + @Suppress("ReturnCount") + fun isCustomPermission(share: OCShare?): Boolean { + if (share == null) return false + val permissions = share.permissions + if (permissions == OCShare.NO_PERMISSION) return false + + val hasRead = hasPermission(permissions, OCShare.READ_PERMISSION_FLAG) + if (!hasRead) return false + + val hasCreate = hasPermission(permissions, OCShare.CREATE_PERMISSION_FLAG) + val hasUpdate = hasPermission(permissions, OCShare.UPDATE_PERMISSION_FLAG) + val hasDelete = hasPermission(permissions, OCShare.DELETE_PERMISSION_FLAG) + val hasShare = hasPermission(permissions, OCShare.SHARE_PERMISSION_FLAG) + + return when { + share.isFolder -> hasCreate || hasUpdate || hasDelete || hasShare + else -> hasUpdate || hasShare + } + } + // endregion + private fun getShareAttributes(share: OCShare?): List? { return share?.attributes?.let { ShareAttributesJsonHandler.toList(it) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java deleted file mode 100644 index c7d3d8830c3b..000000000000 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharingMenuHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Andy Scherzinger - * @author TSI-mc - * Copyright (C) 2018 Andy Scherzinger - * Copyright (C) 2021 TSI-mc - * - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ - -package com.owncloud.android.ui.fragment.util; - -import com.owncloud.android.datamodel.quickPermission.QuickPermissionType; -import com.owncloud.android.lib.resources.shares.OCShare; - -import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; -import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER; -import static com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION; -import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG; -import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG; - -/** - * Helper calls for visibility logic of the sharing menu. - */ -public final class SharingMenuHelper { - - private static final SharePermissionManager sharePermissionManager = new SharePermissionManager(); - - private SharingMenuHelper() { - // utility class -> private constructor - } - - public static boolean canEdit(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & (share.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : - MAXIMUM_PERMISSIONS_FOR_FILE)) == (share.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : - MAXIMUM_PERMISSIONS_FOR_FILE); - } - - public static boolean isViewOnly(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == READ_PERMISSION_FLAG; - } - - public static boolean isFileRequest(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG; - } - - public static boolean isSecureFileDrop(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG; - } - - public static QuickPermissionType getSelectedType(OCShare share, boolean encrypted) { - if (SharingMenuHelper.canEdit(share)) { - return QuickPermissionType.CAN_EDIT; - } else if (encrypted && SharingMenuHelper.isSecureFileDrop(share)) { - return QuickPermissionType.SECURE_FILE_DROP; - } else if (SharingMenuHelper.isFileRequest(share)) { - return QuickPermissionType.FILE_REQUEST; - } else if (SharingMenuHelper.isViewOnly(share)) { - return QuickPermissionType.VIEW_ONLY; - } else if (sharePermissionManager.isCustomPermission(share)) { - return QuickPermissionType.CUSTOM_PERMISSIONS; - } - - return QuickPermissionType.NONE; - } - - public static boolean canReshare(OCShare share) { - return (share.getPermissions() & SHARE_PERMISSION_FLAG) > 0; - } -} From 2744eaac1e45c0e0e8e2f090ea1ffedbd13efd51 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 14:05:45 +0800 Subject: [PATCH 091/110] refactor SharePermissionManager Signed-off-by: alperozturk --- .../fragment/util/SharePermissionManager.kt | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index 981ae038003a..6e7a98fd0d63 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -17,6 +17,7 @@ import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Compan object SharePermissionManager { + // region Permission change fun togglePermission(isChecked: Boolean, permission: Int, permissionFlag: Int): Int { Log_OC.d(TAG, "togglePermission before: $permission") @@ -35,6 +36,12 @@ object SharePermissionManager { return result } + // endregion + + // region Permission check + fun hasPermission(permission: Int, permissionFlag: Int): Boolean { + return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag + } @Suppress("ReturnCount") private fun isPermissionValid(permission: Int): Boolean { @@ -57,19 +64,9 @@ object SharePermissionManager { return true } + // endregion - fun hasPermission(permission: Int, permissionFlag: Int): Boolean { - return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag - } - - fun getMaximumPermission(isFolder: Boolean): Int { - return if (isFolder) { - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER - } else { - OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - } - } - + // region DownloadAttribute fun toggleAllowDownloadAndSync(isChecked: Boolean, share: OCShare?): String? { val shareAttributes = getShareAttributes(share)?.toMutableList() if (shareAttributes == null) { @@ -91,19 +88,18 @@ object SharePermissionManager { return getShareAttributes(share).getDownloadAttribute()?.value == true } + private fun getShareAttributes(share: OCShare?): List? { + return share?.attributes?.let { ShareAttributesJsonHandler.toList(it) } + } + // endregion + // region Helper Methods fun canEdit(share: OCShare?): Boolean { if (share == null) { return false } - val permissionToCheck = if (share.isFolder) { - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER - } else { - OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - } - - return hasPermission(share.permissions, permissionToCheck) + return hasPermission(share.permissions, getMaximumPermission(share.isFolder)) } fun isViewOnly(share: OCShare?): Boolean { @@ -165,9 +161,13 @@ object SharePermissionManager { else -> hasUpdate || hasShare } } - // endregion - private fun getShareAttributes(share: OCShare?): List? { - return share?.attributes?.let { ShareAttributesJsonHandler.toList(it) } + fun getMaximumPermission(isFolder: Boolean): Int { + return if (isFolder) { + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + } else { + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + } } + // endregion } From 86e9aea4c9d3e2921acd16895afe1976cf48138c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 15:13:17 +0800 Subject: [PATCH 092/110] add SharePermissionManagerTest Signed-off-by: alperozturk --- .../utils/SharePermissionManagerTest.kt | 271 ++++++++++++++++++ .../fragment/util/SharePermissionManager.kt | 4 + 2 files changed, 275 insertions(+) create mode 100644 app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt diff --git a/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt b/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt new file mode 100644 index 000000000000..011f9e63273d --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt @@ -0,0 +1,271 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils + +import com.google.gson.Gson +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType +import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.ShareType +import com.owncloud.android.lib.resources.shares.attributes.ShareAttributes +import com.owncloud.android.ui.fragment.util.SharePermissionManager +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertFalse +import junit.framework.TestCase.assertNotNull +import junit.framework.TestCase.assertTrue +import org.junit.Test + +class SharePermissionManagerTest { + + private fun createShare( + sharePermission: Int, + isFolder: Boolean = false, + attributesJson: String? = null + ): OCShare { + return if (isFolder) { + OCShare("/test") + .apply { + permissions = sharePermission + attributes = attributesJson + shareType = ShareType.INTERNAL + sharedDate = 1188206955 + shareWith = "User 1" + sharedWithDisplayName = "User 1" + } + } else { + OCShare("/test.png") + .apply { + permissions = sharePermission + attributes = attributesJson + shareType = ShareType.INTERNAL + sharedDate = 1188206955 + shareWith = "User 1" + sharedWithDisplayName = "User 1" + } + }.apply { + this.isFolder = isFolder + } + } + + // region Permission change tests + @Test + fun testTogglePermissionShouldAddPermissionFlagWhenChecked() { + val initialPermission = OCShare.READ_PERMISSION_FLAG + val updatedPermission = + SharePermissionManager.togglePermission(true, initialPermission, OCShare.UPDATE_PERMISSION_FLAG) + val updatedShare = createShare(updatedPermission) + assertTrue(SharePermissionManager.isCustomPermission(updatedShare)) + } + + @Test + fun testTogglePermissionShouldRemovePermissionFlagWhenUnchecked() { + val initialPermission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + val updatedPermission = + SharePermissionManager.togglePermission(false, initialPermission, OCShare.UPDATE_PERMISSION_FLAG) + val updatedShare = createShare(updatedPermission) + assertTrue(SharePermissionManager.isViewOnly(updatedShare)) + } + // endregion + + // region HasPermissions tests + @Test + fun testHasPermissionShouldReturnTrueIfPermissionPresent() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + assertTrue(SharePermissionManager.hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG)) + } + + @Test + fun testHasPermissionShouldReturnFalseIfPermissionNotPresent() { + val permission = OCShare.READ_PERMISSION_FLAG + assertFalse(SharePermissionManager.hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG)) + } + // endregion + + // region Helper Method Tests + @Test + fun testCanEditShouldReturnTrueIfAllPermissionsPresent() { + val share = createShare(OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, isFolder = true) + assertTrue(SharePermissionManager.canEdit(share)) + } + + @Test + fun testCanEditShouldReturnFalseIfPermissionsAreInsufficient() { + val share = createShare(OCShare.READ_PERMISSION_FLAG) + assertFalse(SharePermissionManager.canEdit(share)) + } + + @Test + fun testIsViewOnlyShouldReturnTrueIfOnlyReadPermissionSet() { + val share = createShare(OCShare.READ_PERMISSION_FLAG) + assertTrue(SharePermissionManager.isViewOnly(share)) + } + + @Test + fun testIsFileRequestShouldReturnTrueIfOnlyCreatePermissionSetOnFolder() { + val share = createShare(OCShare.CREATE_PERMISSION_FLAG, isFolder = true) + assertTrue(SharePermissionManager.isFileRequest(share)) + } + + @Test + fun testIsFileRequestShouldReturnFalseIfOnlyCreatePermissionSetOnFile() { + val share = createShare(OCShare.CREATE_PERMISSION_FLAG) + assertFalse(SharePermissionManager.isFileRequest(share)) + } + + @Test + fun testIsSecureFileDropShouldReturnTrueIfReadAndCreatePermissionsPresent() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG + val share = createShare(permission) + assertTrue(SharePermissionManager.isSecureFileDrop(share)) + } + + @Test + fun testCanReshareShouldReturnTrueIfSharePermissionIsPresent() { + val share = createShare(OCShare.SHARE_PERMISSION_FLAG) + assertTrue(SharePermissionManager.canReshare(share)) + } + + @Test + fun testGetMaximumPermissionForFolder() { + assertEquals( + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, + SharePermissionManager.getMaximumPermission(isFolder = true) + ) + } + + @Test + fun testGetMaximumPermissionForFile() { + assertEquals( + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE, + SharePermissionManager.getMaximumPermission(isFolder = false) + ) + } + // endregion + + // region GetSelectedTypeTests + @Test + fun testGetSelectedTypeShouldReturnCanEditWhenFullPermissionsGiven() { + val share = createShare(OCShare.MAXIMUM_PERMISSIONS_FOR_FILE) + assertEquals(QuickPermissionType.CAN_EDIT, SharePermissionManager.getSelectedType(share, encrypted = false)) + } + + @Test + fun testGetSelectedTypeShouldReturnSecureFileDropWhenEncryptedAndReadCreateGiven() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG + val share = createShare(permission) + assertEquals( + QuickPermissionType.SECURE_FILE_DROP, + SharePermissionManager.getSelectedType(share, encrypted = true) + ) + } + + @Test + fun testGetSelectedTypeShouldReturnFileRequestWhenCreatePermissionGiven() { + val share = createShare(OCShare.CREATE_PERMISSION_FLAG, isFolder = true) + assertEquals(QuickPermissionType.FILE_REQUEST, SharePermissionManager.getSelectedType(share, encrypted = false)) + } + + @Test + fun testGetSelectedTypeShouldReturnViewOnlyWhenReadPermissionGiven() { + val share = createShare(OCShare.READ_PERMISSION_FLAG) + assertEquals(QuickPermissionType.VIEW_ONLY, SharePermissionManager.getSelectedType(share, encrypted = false)) + } + + @Test + fun testGetSelectedTypeShouldReturnCustomPermissionOnlyWhenCustomPermissionGiven() { + val share = createShare(OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG) + assertEquals( + QuickPermissionType.CUSTOM_PERMISSIONS, + SharePermissionManager.getSelectedType(share, encrypted = false) + ) + } + + @Test + fun testGetSelectedTypeShouldReturnNoneOnlyWhenNoPermissionGiven() { + val share = createShare(OCShare.NO_PERMISSION) + assertEquals( + QuickPermissionType.NONE, + SharePermissionManager.getSelectedType(share, encrypted = false) + ) + } + // endregion + + // region CustomPermissions Tests + @Test + fun testIsCustomPermissionShouldReturnFalseWhenNoPermissionsGiven() { + val permission = OCShare.NO_PERMISSION + val share = createShare(permission, isFolder = false) + assertFalse(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnFalseWhenNoReadPermissionsGiven() { + val permission = OCShare.SHARE_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + val share = createShare(permission, isFolder = false) + assertFalse(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnTrueWhenUpdatePermissionsGivenOnFile() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + val share = createShare(permission, isFolder = false) + assertTrue(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnTrueWhenUpdateAndSharePermissionsGivenOnFile() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + OCShare.SHARE_PERMISSION_FLAG + val share = createShare(permission, isFolder = false) + assertTrue(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnFalseWhenCreatePermissionsGivenOnFile() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG + val share = createShare(permission, isFolder = false) + assertFalse(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnFalseWhenDeletePermissionsGivenOnFile() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.DELETE_PERMISSION_FLAG + val share = createShare(permission, isFolder = false) + assertFalse(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnTrueWhenCreatePermissionsGivenOnFolder() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG + val share = createShare(permission, isFolder = true) + assertTrue(SharePermissionManager.isCustomPermission(share)) + } + + @Test + fun testIsCustomPermissionShouldReturnTrueWhenMixedPermissionsOnFile() { + val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + val share = createShare(permission, isFolder = false) + assertTrue(SharePermissionManager.isCustomPermission(share)) + } + // endregion + + // region Attributes Tests + @Test + fun testToggleAllowDownloadAndSyncShouldCreateAttributeJsonIfNoneExists() { + val json = SharePermissionManager.toggleAllowDownloadAndSync(true, null) + assertNotNull(json) + val downloadAttribute = ShareAttributes.createDownloadAttributes(true) + val expectedJson = Gson().toJson(listOf(downloadAttribute)) + assertEquals(json, expectedJson) + } + + @Test + fun testIsAllowDownloadAndSyncEnabledShouldReturnFalseIfAttributeIsMissing() { + val share = createShare(OCShare.READ_PERMISSION_FLAG, attributesJson = null) + assertFalse(SharePermissionManager.isAllowDownloadAndSyncEnabled(share)) + } + // endregion +} diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index 6e7a98fd0d63..b6e709237ba3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -107,6 +107,10 @@ object SharePermissionManager { } fun isFileRequest(share: OCShare?): Boolean { + if (share?.isFolder == false) { + return false + } + return share?.permissions != OCShare.NO_PERMISSION && share?.permissions == OCShare.CREATE_PERMISSION_FLAG } From a5c60e7752606168489f3f12e2e1c307e6c066cd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 17:34:22 +0800 Subject: [PATCH 093/110] fix usage of defaultPermissions Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index bb74617d335f..03d9816b0d62 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -524,6 +524,9 @@ class FileDetailsSharingProcessFragment : } val isCustomPermissionSelected = (optionId == R.id.custom_permission_radio_button) + if (isCustomPermissionSelected) { + permission = SharePermissionManager.getMaximumPermission(isFolder()) + } customPermissionLayout.setVisibilityWithAnimation(isCustomPermissionSelected) toggleNextButtonAvailability(true) } From 4a95453688962360be7c0821fb4417d0272efa83 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 17:48:07 +0800 Subject: [PATCH 094/110] fix usage of defaultPermissions Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 30 ++++++++++++------- .../file_details_sharing_process_fragment.xml | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 03d9816b0d62..a4d56462d164 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -187,9 +187,9 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if (shareProcessStep == SCREEN_TYPE_PERMISSION || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { - showShareProcessFirst() + setupUI() } else { - updateViewForNoteScreenType() + setupUIForNoteScreenType() } implementClickEvents() @@ -267,15 +267,15 @@ class FileDetailsSharingProcessFragment : } } - private fun showShareProcessFirst() { + private fun setupUI() { binding.shareProcessGroupOne.visibility = View.VISIBLE binding.shareProcessEditShareLink.visibility = View.VISIBLE binding.shareProcessGroupTwo.visibility = View.GONE if (share != null) { - setupModificationUI() + setupUIForUpdate() } else { - setupUpdateUI() + setupUIForCreate() } // show or hide expiry date @@ -283,7 +283,7 @@ class FileDetailsSharingProcessFragment : shareProcessStep = SCREEN_TYPE_PERMISSION } - private fun setupModificationUI() { + private fun setupUIForUpdate() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() // custom permissions / read only / allow upload and editing / file request @@ -327,7 +327,7 @@ class FileDetailsSharingProcessFragment : showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) } - private fun setupUpdateUI() { + private fun setupUIForCreate() { binding.shareProcessBtnNext.text = getString(R.string.common_next) file.let { if (file?.isFolder == true) { @@ -340,6 +340,14 @@ class FileDetailsSharingProcessFragment : showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) + setMaxPermissionsIfDefaultPermissionExists() + } + + private fun setMaxPermissionsIfDefaultPermissionExists() { + if (capabilities.defaultPermissions != null) { + binding.canEditRadioButton.isChecked = true + permission = SharePermissionManager.getMaximumPermission(isFolder()) + } } // region ViewUpdates @@ -460,7 +468,7 @@ class FileDetailsSharingProcessFragment : } } - private fun updateViewForNoteScreenType() { + private fun setupUIForNoteScreenType() { binding.run { shareProcessGroupOne.visibility = View.GONE shareProcessEditShareLink.visibility = View.GONE @@ -508,7 +516,7 @@ class FileDetailsSharingProcessFragment : } // region RadioButtons - shareProcessPermissionRadioGroup.setOnCheckedChangeListener { _, optionId -> + shareRadioGroup.setOnCheckedChangeListener { _, optionId -> when (optionId) { R.id.view_only_radio_button -> { permission = OCShare.READ_PERMISSION_FLAG @@ -645,7 +653,7 @@ class FileDetailsSharingProcessFragment : // and if user is in step 1 (permission screen) then remove the fragment else { if (shareProcessStep == SCREEN_TYPE_NOTE) { - showShareProcessFirst() + setupUI() } else { removeCurrentFragment() } @@ -723,7 +731,7 @@ class FileDetailsSharingProcessFragment : removeCurrentFragment() } else { // else show step 2 (note screen) - updateViewForNoteScreenType() + setupUIForNoteScreenType() } } diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 6a39600b5dc1..60ac7edbebd0 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -39,7 +39,7 @@ android:textStyle="bold" /> From da31ece7a8dcd00013ad0e2008456c1c6daf0a5c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 27 May 2025 19:59:03 +0800 Subject: [PATCH 095/110] fix code analytics Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/SharePermissionManagerTest.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt b/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt index 011f9e63273d..bf990f982642 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt @@ -21,11 +21,7 @@ import org.junit.Test class SharePermissionManagerTest { - private fun createShare( - sharePermission: Int, - isFolder: Boolean = false, - attributesJson: String? = null - ): OCShare { + private fun createShare(sharePermission: Int, isFolder: Boolean = false, attributesJson: String? = null): OCShare { return if (isFolder) { OCShare("/test") .apply { From 469c558fe532d3a1a436b23aa52f303a5e6ffe3f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 28 May 2025 19:22:53 +0800 Subject: [PATCH 096/110] fix code analytics Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/SharePermissionManagerTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt b/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt index bf990f982642..071adc9915c3 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/SharePermissionManagerTest.kt @@ -19,6 +19,7 @@ import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import org.junit.Test +@Suppress("TooManyFunctions") class SharePermissionManagerTest { private fun createShare(sharePermission: Int, isFolder: Boolean = false, attributesJson: String? = null): OCShare { From c8e5634a50e61d1d106653bac6a26a6312d77b06 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 28 May 2025 19:38:40 +0800 Subject: [PATCH 097/110] add download attribute for create share Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index a4d56462d164..2175f812d74c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -138,6 +138,7 @@ class FileDetailsSharingProcessFragment : private lateinit var capabilities: OCCapability private var expirationDatePickerFragment: ExpirationDatePickerDialogFragment? = null + private var downloadAttribute: String? = null override fun onAttach(context: Context) { super.onAttach(context) @@ -619,7 +620,9 @@ class FileDetailsSharingProcessFragment : if (!isPublicShare()) { binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked -> - share?.attributes = SharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) + val result = SharePermissionManager.toggleAllowDownloadAndSync(isChecked, share) + share?.attributes = result + downloadAttribute = result } } } @@ -808,7 +811,7 @@ class FileDetailsSharingProcessFragment : binding.shareProcessEnterPassword.text.toString().trim(), chosenExpDateInMills, noteText, - share?.attributes, + downloadAttribute, binding.shareProcessChangeName.text.toString().trim(), true ) From c0a4c83d563660d346806528078ae8be3d06c770 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 14:12:29 +0800 Subject: [PATCH 098/110] better debug Signed-off-by: alperozturk --- .../android/services/OperationsService.java | 6 + .../fragment/FileDetailSharingFragment.java | 2 +- .../FileDetailsSharingProcessFragment.kt | 106 +++++++++--------- .../fragment/util/SharePermissionManager.kt | 2 +- 4 files changed, 61 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 48b0373b34d9..40d5d28afc47 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -438,6 +438,12 @@ private void nextOperation() { // perform the operation try { result = mCurrentOperation.execute(mOwnCloudClient); + if (!result.isSuccess()) { + final var code = "code: " + result.getCode(); + final var httpCode = "HTTP_CODE: " + result.getHttpCode(); + final var exception = "exception: " + result.getException().getLocalizedMessage(); + Log_OC.e(TAG,"Operation failed " + code + httpCode + exception); + } } catch (UnsupportedOperationException e) { // TODO remove - added to aid in transition to NextcloudClient diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 3ad54da5c934..f39587780121 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -685,7 +685,7 @@ public void onQuickPermissionChanged(OCShare share, int permission) { @Override public void openShareDetail(OCShare share) { - modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_CUSTOM_PERMISSION); + modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION); } //launcher for contact permission diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 2175f812d74c..ffb34dea3705 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -24,6 +24,7 @@ import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.quickPermission.QuickPermissionType import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.status.OCCapability @@ -67,7 +68,6 @@ class FileDetailsSharingProcessFragment : // types of screens to be displayed const val SCREEN_TYPE_PERMISSION = 1 // permissions screen const val SCREEN_TYPE_NOTE = 2 // note screen - const val SCREEN_TYPE_CUSTOM_PERMISSION = 3 // custom permissions screen /** * fragment instance to be called while creating new share for internal and external share @@ -187,10 +187,10 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (shareProcessStep == SCREEN_TYPE_PERMISSION || shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION) { + if (shareProcessStep == SCREEN_TYPE_PERMISSION) { setupUI() } else { - setupUIForNoteScreenType() + updateViewForNoteScreenType() } implementClickEvents() @@ -274,9 +274,9 @@ class FileDetailsSharingProcessFragment : binding.shareProcessGroupTwo.visibility = View.GONE if (share != null) { - setupUIForUpdate() + updateViewForUpdate() } else { - setupUIForCreate() + updateViewForCreate() } // show or hide expiry date @@ -284,25 +284,52 @@ class FileDetailsSharingProcessFragment : shareProcessStep = SCREEN_TYPE_PERMISSION } - private fun setupUIForUpdate() { + private fun setMaxPermissionsIfDefaultPermissionExists() { + if (capabilities.defaultPermissions != null) { + binding.canEditRadioButton.isChecked = true + permission = SharePermissionManager.getMaximumPermission(isFolder()) + } + } + + // region ViewUpdates + private fun updateViewForCreate() { + binding.shareProcessBtnNext.text = getString(R.string.common_next) + file.let { + if (file?.isFolder == true) { + updateViewForFolder() + } else { + updateViewForFile() + } + updateViewForShareType() + } + showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) + showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) + showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) + setMaxPermissionsIfDefaultPermissionExists() + } + + private fun updateViewForUpdate() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() // custom permissions / read only / allow upload and editing / file request + val selectedType = SharePermissionManager.getSelectedType(share, encrypted = file?.isEncrypted == true) binding.run { - when { - SharePermissionManager.canEdit(share) -> canEditRadioButton.isChecked = true - SharePermissionManager.isFileRequest(share) && share?.isFolder == true -> - fileRequestRadioButton.isChecked = - true - - SharePermissionManager.isViewOnly(share) -> viewOnlyRadioButton.isChecked = true + when(selectedType) { + QuickPermissionType.VIEW_ONLY -> { + viewOnlyRadioButton.isChecked = true + } + QuickPermissionType.CAN_EDIT -> { + canEditRadioButton.isChecked = true + } + QuickPermissionType.FILE_REQUEST -> { + fileRequestRadioButton.isChecked = true + } + QuickPermissionType.CUSTOM_PERMISSIONS -> { + customPermissionRadioButton.isChecked = true + customPermissionLayout.setVisibilityWithAnimation(true) + } else -> { - if (SharePermissionManager.isCustomPermission(share) || - shareProcessStep == SCREEN_TYPE_CUSTOM_PERMISSION - ) { - customPermissionRadioButton.isChecked = true - customPermissionLayout.setVisibilityWithAnimation(true) - } + } } } @@ -328,30 +355,6 @@ class FileDetailsSharingProcessFragment : showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) } - private fun setupUIForCreate() { - binding.shareProcessBtnNext.text = getString(R.string.common_next) - file.let { - if (file?.isFolder == true) { - updateViewForFolder() - } else { - updateViewForFile() - } - updateViewForShareType() - } - showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) - showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) - showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) - setMaxPermissionsIfDefaultPermissionExists() - } - - private fun setMaxPermissionsIfDefaultPermissionExists() { - if (capabilities.defaultPermissions != null) { - binding.canEditRadioButton.isChecked = true - permission = SharePermissionManager.getMaximumPermission(isFolder()) - } - } - - // region ViewUpdates private fun updateViewForShareType() { when (shareType) { ShareType.EMAIL -> { @@ -423,9 +426,6 @@ class FileDetailsSharingProcessFragment : } } - /** - * update expiration date view while modifying the share - */ private fun updateExpirationDateView() { share?.let { share -> if (share.expirationDate > 0) { @@ -469,7 +469,7 @@ class FileDetailsSharingProcessFragment : } } - private fun setupUIForNoteScreenType() { + private fun updateViewForNoteScreenType() { binding.run { shareProcessGroupOne.visibility = View.GONE shareProcessEditShareLink.visibility = View.GONE @@ -543,11 +543,6 @@ class FileDetailsSharingProcessFragment : } } - private fun togglePermission(isChecked: Boolean, permissionFlag: Int) { - permission = SharePermissionManager.togglePermission(isChecked, permission, permissionFlag) - toggleNextButtonAvailability(true) - } - private fun isAnyShareOptionChecked(): Boolean { return binding.run { val isCustomPermissionChecked = customPermissionRadioButton.isChecked && @@ -627,6 +622,11 @@ class FileDetailsSharingProcessFragment : } } + private fun togglePermission(isChecked: Boolean, permissionFlag: Int) { + permission = SharePermissionManager.togglePermission(isChecked, permission, permissionFlag) + toggleNextButtonAvailability(true) + } + private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) { val dialog = ExpirationDatePickerDialogFragment.newInstance(chosenDateInMillis) dialog.setOnExpiryDateListener(this) @@ -734,7 +734,7 @@ class FileDetailsSharingProcessFragment : removeCurrentFragment() } else { // else show step 2 (note screen) - setupUIForNoteScreenType() + updateViewForNoteScreenType() } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt index b6e709237ba3..14e8a7dbddc0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/util/SharePermissionManager.kt @@ -130,7 +130,7 @@ object SharePermissionManager { return (share.permissions and OCShare.Companion.SHARE_PERMISSION_FLAG) > 0 } - fun getSelectedType(share: OCShare, encrypted: Boolean): QuickPermissionType { + fun getSelectedType(share: OCShare?, encrypted: Boolean): QuickPermissionType { return if (canEdit(share)) { QuickPermissionType.CAN_EDIT } else if (encrypted && isSecureFileDrop(share)) { From 7f70a9aea924cbb7a1de9498fb9d10f0eb0a2591 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 14:19:40 +0800 Subject: [PATCH 099/110] better debug Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 13 +++++++++++ .../ui/helpers/FileOperationsHelper.java | 22 +++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index ffb34dea3705..46cbefdbd771 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -25,6 +25,7 @@ import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.quickPermission.QuickPermissionType +import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.lib.resources.status.OCCapability @@ -198,6 +199,18 @@ class FileDetailsSharingProcessFragment : themeView() setVisibilitiesOfShareOption() toggleNextButtonAvailability(isAnyShareOptionChecked()) + logShareInfo() + } + + private fun logShareInfo() { + share?.run { + Log_OC.i(TAG, "-----BEFORE UPDATE SHARE-----") + Log_OC.i(TAG, "ID: $id") + Log_OC.i(TAG, "Permission: $permissions") + Log_OC.i(TAG, "Hide File Download: $isHideFileDownload") + Log_OC.i(TAG, "Label: $label") + Log_OC.i(TAG, "Attributes: $attributes") + } } private fun setVisibilitiesOfShareOption() { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 211dcfaec3bc..5acc339d4949 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -750,19 +750,33 @@ public void updateFilesDownloadLimit(OCShare share, int newLimit) { * leaving the link unrestricted. Zero makes no change. * @param label new label */ - public void updateShareInformation(OCShare share, int permissions, - boolean hideFileDownload, String password, long expirationTimeInMillis, + public void updateShareInformation(OCShare share, + int permissions, + boolean hideFileDownload, + String password, + long expirationTimeInMillis, String label) { + final var id = share.getId(); + final var attributes = share.getAttributes(); + + Log_OC.i(TAG, "-----AFTER UPDATE SHARE-----"); + Log_OC.i(TAG, "ID: " + id); + Log_OC.i(TAG, "Permission: " + permissions); + Log_OC.i(TAG, "Hide File Download: " + hideFileDownload); + Log_OC.i(TAG, "Label: " + label); + Log_OC.i(TAG, "Attributes: " + attributes); + + Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_INFO); updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); - updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId()); + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, id); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_HIDE_FILE_DOWNLOAD, hideFileDownload); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label); - updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ATTRIBUTES, share.getAttributes()); + updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ATTRIBUTES, attributes); queueShareIntent(updateShareIntent); } From 87580541becc7791cac252ec88903aef64823c6f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 15:12:03 +0800 Subject: [PATCH 100/110] better debug Signed-off-by: alperozturk --- .../java/com/owncloud/android/services/OperationsService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 40d5d28afc47..d2b8a9c75dae 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -441,8 +441,7 @@ private void nextOperation() { if (!result.isSuccess()) { final var code = "code: " + result.getCode(); final var httpCode = "HTTP_CODE: " + result.getHttpCode(); - final var exception = "exception: " + result.getException().getLocalizedMessage(); - Log_OC.e(TAG,"Operation failed " + code + httpCode + exception); + Log_OC.e(TAG,"Operation failed " + code + httpCode); } } catch (UnsupportedOperationException e) { // TODO remove - added to aid in transition to NextcloudClient From e937ec7f6099a5a85cae4063a641487abd95a4f2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 16:40:11 +0800 Subject: [PATCH 101/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 46cbefdbd771..4e89e01a63c6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -327,7 +327,7 @@ class FileDetailsSharingProcessFragment : // custom permissions / read only / allow upload and editing / file request val selectedType = SharePermissionManager.getSelectedType(share, encrypted = file?.isEncrypted == true) binding.run { - when(selectedType) { + when (selectedType) { QuickPermissionType.VIEW_ONLY -> { viewOnlyRadioButton.isChecked = true } @@ -342,7 +342,6 @@ class FileDetailsSharingProcessFragment : customPermissionLayout.setVisibilityWithAnimation(true) } else -> { - } } } From e02c6947f19a37924aec1a48f8f0e02eb268f089 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 17:06:50 +0800 Subject: [PATCH 102/110] fix custom permission selection Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragment.java | 4 +- .../FileDetailsSharingProcessFragment.kt | 111 +++++++++++------- ...ckSharingPermissionsBottomSheetDialog.java | 4 +- 3 files changed, 72 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index f39587780121..bc4bc399b938 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -684,8 +684,8 @@ public void onQuickPermissionChanged(OCShare share, int permission) { } @Override - public void openShareDetail(OCShare share) { - modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION); + public void openShareDetailWithCustomPermissions(OCShare share) { + modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION); } //launcher for contact permission diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 4e89e01a63c6..c72ceaf28537 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -69,6 +69,7 @@ class FileDetailsSharingProcessFragment : // types of screens to be displayed const val SCREEN_TYPE_PERMISSION = 1 // permissions screen const val SCREEN_TYPE_NOTE = 2 // note screen + const val SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION = 3 // permissions screen with custom permission /** * fragment instance to be called while creating new share for internal and external share @@ -153,6 +154,18 @@ class FileDetailsSharingProcessFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + initArguments() + fileActivity = activity as FileActivity? + capabilities = CapabilityUtils.getCapability(context) + + requireNotNull(fileActivity) { "FileActivity may not be null" } + + permission = share?.permissions + ?: capabilities.defaultPermissions + ?: SharePermissionManager.getMaximumPermission(isFolder()) + } + + private fun initArguments() { arguments?.let { file = it.getParcelableArgument(ARG_OCFILE, OCFile::class.java) shareeName = it.getString(ARG_SHAREE_NAME) @@ -169,15 +182,6 @@ class FileDetailsSharingProcessFragment : isExpDateShown = it.getBoolean(ARG_EXP_DATE_SHOWN, true) isSecureShare = it.getBoolean(ARG_SECURE_SHARE, false) } - - fileActivity = activity as FileActivity? - capabilities = CapabilityUtils.getCapability(context) - - requireNotNull(fileActivity) { "FileActivity may not be null" } - - permission = share?.permissions - ?: capabilities.defaultPermissions - ?: SharePermissionManager.getMaximumPermission(isFolder()) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -188,7 +192,8 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (shareProcessStep == SCREEN_TYPE_PERMISSION) { + if (shareProcessStep == SCREEN_TYPE_PERMISSION || + shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION) { setupUI() } else { updateViewForNoteScreenType() @@ -282,19 +287,25 @@ class FileDetailsSharingProcessFragment : } private fun setupUI() { - binding.shareProcessGroupOne.visibility = View.VISIBLE - binding.shareProcessEditShareLink.visibility = View.VISIBLE - binding.shareProcessGroupTwo.visibility = View.GONE + binding.run { + shareProcessGroupOne.visibility = View.VISIBLE + shareProcessEditShareLink.visibility = View.VISIBLE + shareProcessGroupTwo.visibility = View.GONE + } + + updateView() + + // show or hide expiry date + binding.shareProcessSetExpDateSwitch.setVisibleIf(isExpDateShown && !isSecureShare) + shareProcessStep = SCREEN_TYPE_PERMISSION + } + private fun updateView() { if (share != null) { updateViewForUpdate() } else { updateViewForCreate() } - - // show or hide expiry date - binding.shareProcessSetExpDateSwitch.setVisibleIf(isExpDateShown && !isSecureShare) - shareProcessStep = SCREEN_TYPE_PERMISSION } private fun setMaxPermissionsIfDefaultPermissionExists() { @@ -307,43 +318,31 @@ class FileDetailsSharingProcessFragment : // region ViewUpdates private fun updateViewForCreate() { binding.shareProcessBtnNext.text = getString(R.string.common_next) - file.let { - if (file?.isFolder == true) { + updateViewAccordingToFile() + showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) + showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) + showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) + setMaxPermissionsIfDefaultPermissionExists() + } + + private fun updateViewAccordingToFile() { + file?.run { + if (isFolder == true) { updateViewForFolder() } else { updateViewForFile() } updateViewForShareType() } - showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) - showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) - showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) - setMaxPermissionsIfDefaultPermissionExists() } private fun updateViewForUpdate() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() - // custom permissions / read only / allow upload and editing / file request - val selectedType = SharePermissionManager.getSelectedType(share, encrypted = file?.isEncrypted == true) - binding.run { - when (selectedType) { - QuickPermissionType.VIEW_ONLY -> { - viewOnlyRadioButton.isChecked = true - } - QuickPermissionType.CAN_EDIT -> { - canEditRadioButton.isChecked = true - } - QuickPermissionType.FILE_REQUEST -> { - fileRequestRadioButton.isChecked = true - } - QuickPermissionType.CUSTOM_PERMISSIONS -> { - customPermissionRadioButton.isChecked = true - customPermissionLayout.setVisibilityWithAnimation(true) - } - else -> { - } - } + selectRadioButtonAccordingToPermission() + + if (shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION) { + selectCustomPermissionLayout() } shareType = share?.shareType ?: ShareType.NO_SHARED @@ -367,6 +366,32 @@ class FileDetailsSharingProcessFragment : showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked) } + private fun selectRadioButtonAccordingToPermission() { + val selectedType = SharePermissionManager.getSelectedType(share, encrypted = file?.isEncrypted == true) + binding.run { + when (selectedType) { + QuickPermissionType.VIEW_ONLY -> { + viewOnlyRadioButton.isChecked = true + } + QuickPermissionType.CAN_EDIT -> { + canEditRadioButton.isChecked = true + } + QuickPermissionType.FILE_REQUEST -> { + fileRequestRadioButton.isChecked = true + } + QuickPermissionType.CUSTOM_PERMISSIONS -> { + selectCustomPermissionLayout() + } + else -> Unit + } + } + } + + private fun selectCustomPermissionLayout() { + binding.customPermissionRadioButton.isChecked = true + binding.customPermissionLayout.setVisibilityWithAnimation(true) + } + private fun updateViewForShareType() { when (shareType) { ShareType.EMAIL -> { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index fd4cf254a1f7..f662522ccfb2 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -88,7 +88,7 @@ private void setUpRecyclerView() { @Override public void onCustomPermissionSelected() { dismiss(); - actions.openShareDetail(ocShare); + actions.openShareDetailWithCustomPermissions(ocShare); } @Override @@ -147,6 +147,6 @@ protected void onStop() { public interface QuickPermissionSharingBottomSheetActions { void onQuickPermissionChanged(OCShare share, int permission); - void openShareDetail(OCShare share); + void openShareDetailWithCustomPermissions(OCShare share); } } From bab83db3069b24ca93c726f93df7f7cf722af62a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 17:09:00 +0800 Subject: [PATCH 103/110] extract set downloadlimit Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index c72ceaf28537..ac85b940d347 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -821,15 +821,7 @@ class FileDetailsSharingProcessFragment : ) if (canSetDownloadLimit()) { - val downloadLimitInput = binding.shareProcessSetDownloadLimitInput.text.toString().trim() - val downloadLimit = - if (binding.shareProcessSetDownloadLimitSwitch.isChecked && downloadLimitInput.isNotEmpty()) { - downloadLimitInput.toInt() - } else { - 0 - } - - fileOperationsHelper?.updateFilesDownloadLimit(share, downloadLimit) + setDownloadLimit() } // copy the share link if available @@ -838,6 +830,18 @@ class FileDetailsSharingProcessFragment : } } + private fun setDownloadLimit() { + val downloadLimitInput = binding.shareProcessSetDownloadLimitInput.text.toString().trim() + val downloadLimit = + if (binding.shareProcessSetDownloadLimitSwitch.isChecked && downloadLimitInput.isNotEmpty()) { + downloadLimitInput.toInt() + } else { + 0 + } + + fileOperationsHelper?.updateFilesDownloadLimit(share, downloadLimit) + } + private fun createShare(noteText: String) { fileOperationsHelper?.shareFileWithSharee( file, From ba5ce544cadc1a1ac836bcaebd4eccdfc3809a34 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 17:15:09 +0800 Subject: [PATCH 104/110] fix customPermissionLayout select logic Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index ac85b940d347..70f9148db0ed 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -570,9 +570,6 @@ class FileDetailsSharingProcessFragment : } val isCustomPermissionSelected = (optionId == R.id.custom_permission_radio_button) - if (isCustomPermissionSelected) { - permission = SharePermissionManager.getMaximumPermission(isFolder()) - } customPermissionLayout.setVisibilityWithAnimation(isCustomPermissionSelected) toggleNextButtonAvailability(true) } From 2354f6568bbbb4753e96583865e2cba0eb1a6a1f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 17:38:40 +0800 Subject: [PATCH 105/110] fix code analytics Signed-off-by: alperozturk --- .../android/ui/fragment/FileDetailsSharingProcessFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 70f9148db0ed..a8b9b7ce9020 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -193,7 +193,8 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if (shareProcessStep == SCREEN_TYPE_PERMISSION || - shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION) { + shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION + ) { setupUI() } else { updateViewForNoteScreenType() From 011f098b114c0a3db19a707597d7dc8fadfa5c22 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 18:22:21 +0800 Subject: [PATCH 106/110] fix ShareProcessStep check Signed-off-by: alperozturk --- .../FileDetailsSharingProcessFragment.kt | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index a8b9b7ce9020..41df46f90c8f 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -162,7 +162,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: SharePermissionManager.getMaximumPermission(isFolder()) + ?: SharePermissionManager.getMaximumPermission(isFolder()) } private fun initArguments() { @@ -192,9 +192,7 @@ class FileDetailsSharingProcessFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (shareProcessStep == SCREEN_TYPE_PERMISSION || - shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION - ) { + if (isShareProcessStepIsPermission()) { setupUI() } else { updateViewForNoteScreenType() @@ -342,7 +340,7 @@ class FileDetailsSharingProcessFragment : selectRadioButtonAccordingToPermission() - if (shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION) { + if (isShareProcessStepIsCustomPermission()) { selectCustomPermissionLayout() } @@ -374,15 +372,19 @@ class FileDetailsSharingProcessFragment : QuickPermissionType.VIEW_ONLY -> { viewOnlyRadioButton.isChecked = true } + QuickPermissionType.CAN_EDIT -> { canEditRadioButton.isChecked = true } + QuickPermissionType.FILE_REQUEST -> { fileRequestRadioButton.isChecked = true } + QuickPermissionType.CUSTOM_PERMISSIONS -> { selectCustomPermissionLayout() } + else -> Unit } } @@ -532,7 +534,7 @@ class FileDetailsSharingProcessFragment : onCancelClick() } shareProcessBtnNext.setOnClickListener { - if (shareProcessStep == SCREEN_TYPE_PERMISSION) { + if (isShareProcessStepIsPermission()) { validateShareProcessFirst() } else { createShareOrUpdateNoteShare() @@ -687,10 +689,11 @@ class FileDetailsSharingProcessFragment : if (share != null) { removeCurrentFragment() } + // else we have to check if user is in step 2(note screen) then show step 1 (permission screen) // and if user is in step 1 (permission screen) then remove the fragment else { - if (shareProcessStep == SCREEN_TYPE_NOTE) { + if (isShareProcessStepIsNote()) { setupUI() } else { removeCurrentFragment() @@ -791,10 +794,12 @@ class FileDetailsSharingProcessFragment : share != null && share?.note != noteText -> { fileOperationsHelper?.updateNoteToShare(share, noteText) } + file == null -> { DisplayUtils.showSnackMessage(requireActivity(), R.string.file_not_found_cannot_share) return } + else -> { createShare(noteText) } @@ -876,6 +881,14 @@ class FileDetailsSharingProcessFragment : } // region Helpers + private fun isShareProcessStepIsPermission(): Boolean = (shareProcessStep == SCREEN_TYPE_PERMISSION || + isShareProcessStepIsCustomPermission()) + + private fun isShareProcessStepIsCustomPermission(): Boolean = + (shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION) + + private fun isShareProcessStepIsNote(): Boolean = (shareProcessStep == SCREEN_TYPE_NOTE) + private fun isFolder(): Boolean = (file?.isFolder == true || share?.isFolder == true) private fun canSetFileRequest(): Boolean = isFolder() && shareType.isPublicOrMail() From 70ea4b3a33bc6c2bb185d75cdc3393334dd66c89 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 30 May 2025 18:41:57 +0800 Subject: [PATCH 107/110] fix code analytics Signed-off-by: alperozturk --- .../ui/fragment/FileDetailsSharingProcessFragment.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 41df46f90c8f..7479c07467c0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -162,7 +162,7 @@ class FileDetailsSharingProcessFragment : permission = share?.permissions ?: capabilities.defaultPermissions - ?: SharePermissionManager.getMaximumPermission(isFolder()) + ?: SharePermissionManager.getMaximumPermission(isFolder()) } private fun initArguments() { @@ -881,8 +881,10 @@ class FileDetailsSharingProcessFragment : } // region Helpers - private fun isShareProcessStepIsPermission(): Boolean = (shareProcessStep == SCREEN_TYPE_PERMISSION || - isShareProcessStepIsCustomPermission()) + private fun isShareProcessStepIsPermission(): Boolean = ( + shareProcessStep == SCREEN_TYPE_PERMISSION || + isShareProcessStepIsCustomPermission() + ) private fun isShareProcessStepIsCustomPermission(): Boolean = (shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION) From 49838e1467dc4fb801160082fe115b1daf4f78b3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 3 Jun 2025 19:30:48 +0800 Subject: [PATCH 108/110] solve git conflicts Signed-off-by: alperozturk --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7555c7e33b26..86a21eb332df 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ */ buildscript { ext { - androidLibraryVersion ="8e561c7e65f208492c20b106eb25cfbe43dc7189" + androidLibraryVersion ="efceb970c7" androidCommonLibraryVersion = "0.25.0" androidPluginVersion = "8.9.2" androidxMediaVersion = "1.5.1" From 6e5ade0e53735e4570e018a5edba6c755e9e06fc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 10 Jun 2025 10:34:42 +0200 Subject: [PATCH 109/110] update lib Signed-off-by: alperozturk --- build.gradle | 2 +- gradle/verification-metadata.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 86a21eb332df..09c2ba8dd76c 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ */ buildscript { ext { - androidLibraryVersion ="efceb970c7" + androidLibraryVersion ="d862794d794a7e8d8b53da98aa801753e684bf52" androidCommonLibraryVersion = "0.25.0" androidPluginVersion = "8.9.2" androidxMediaVersion = "1.5.1" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 50bf059b60f1..863002282126 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -11567,6 +11567,14 @@ + + + + + + + + From 3d2feb283b1d6187b5fc9aa12a5866397bbdb0a0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 10 Jun 2025 14:50:03 +0200 Subject: [PATCH 110/110] fix tests Signed-off-by: alperozturk --- .../fragment/FileDetailSharingFragmentIT.kt | 113 +++++++----------- 1 file changed, 44 insertions(+), 69 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 60c7ad9f763d..c3a0db94d87c 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -49,8 +49,7 @@ import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.CoreMatchers.`is` import org.hamcrest.CoreMatchers.not import org.junit.After -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule import org.junit.Test @@ -887,84 +886,60 @@ class FileDetailSharingFragmentIT : AbstractIT() { @Test fun testUploadAndEditingSharePermissions() { - val share = OCShare().apply { - permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER + val testCases = mapOf( + MAXIMUM_PERMISSIONS_FOR_FOLDER to true, + NO_PERMISSION to false, + READ_PERMISSION_FLAG to false, + CREATE_PERMISSION_FLAG to false, + DELETE_PERMISSION_FLAG to false, + SHARE_PERMISSION_FLAG to false + ) + + val share = OCShare() + for ((permission, expected) in testCases) { + share.permissions = permission + assertEquals("Failed for permission: $permission", expected, SharePermissionManager.canEdit(share)) } - assertTrue(SharePermissionManager.canEdit(share)) - - share.permissions = NO_PERMISSION - assertFalse(SharePermissionManager.canEdit(share)) - - share.permissions = READ_PERMISSION_FLAG - assertFalse(SharePermissionManager.canEdit(share)) - - share.permissions = CREATE_PERMISSION_FLAG - assertFalse(SharePermissionManager.canEdit(share)) - - share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharePermissionManager.canEdit(share)) - - share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharePermissionManager.canEdit(share)) } @Test - @Suppress("MagicNumber") fun testReadOnlySharePermissions() { - val share = OCShare().apply { - permissions = 17 + val testCases = mapOf( + READ_PERMISSION_FLAG to true, + NO_PERMISSION to false, + CREATE_PERMISSION_FLAG to false, + DELETE_PERMISSION_FLAG to false, + SHARE_PERMISSION_FLAG to false, + MAXIMUM_PERMISSIONS_FOR_FOLDER to false, + MAXIMUM_PERMISSIONS_FOR_FILE to false + ) + + val share = OCShare() + for ((permission, expected) in testCases) { + share.permissions = permission + assertEquals("Failed for permission: $permission", expected, SharePermissionManager.isViewOnly(share)) } - assertTrue(SharePermissionManager.isViewOnly(share)) - - share.permissions = NO_PERMISSION - assertFalse(SharePermissionManager.isViewOnly(share)) - - share.permissions = READ_PERMISSION_FLAG - assertTrue(SharePermissionManager.isViewOnly(share)) - - share.permissions = CREATE_PERMISSION_FLAG - assertFalse(SharePermissionManager.isViewOnly(share)) - - share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharePermissionManager.isViewOnly(share)) - - share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharePermissionManager.isViewOnly(share)) - - share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - assertFalse(SharePermissionManager.isViewOnly(share)) - - share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE - assertFalse(SharePermissionManager.isViewOnly(share)) } @Test - @Suppress("MagicNumber") - fun testFileDropSharePermissions() { + fun testFileRequestSharePermission() { + val testCases = mapOf( + CREATE_PERMISSION_FLAG to true, + NO_PERMISSION to false, + READ_PERMISSION_FLAG to false, + DELETE_PERMISSION_FLAG to false, + SHARE_PERMISSION_FLAG to false, + MAXIMUM_PERMISSIONS_FOR_FOLDER to false, + MAXIMUM_PERMISSIONS_FOR_FILE to false + ) + val share = OCShare().apply { - permissions = 4 + isFolder = true } - assertTrue(SharePermissionManager.isFileRequest(share)) - - share.permissions = NO_PERMISSION - assertFalse(SharePermissionManager.isFileRequest(share)) - share.permissions = READ_PERMISSION_FLAG - assertFalse(SharePermissionManager.isFileRequest(share)) - - share.permissions = CREATE_PERMISSION_FLAG - assertTrue(SharePermissionManager.isFileRequest(share)) - - share.permissions = DELETE_PERMISSION_FLAG - assertFalse(SharePermissionManager.isFileRequest(share)) - - share.permissions = SHARE_PERMISSION_FLAG - assertFalse(SharePermissionManager.isFileRequest(share)) - - share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER - assertFalse(SharePermissionManager.isFileRequest(share)) - - share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE - assertFalse(SharePermissionManager.isFileRequest(share)) + for ((permission, expected) in testCases) { + share.permissions = permission + assertEquals("Failed for permission: $permission", expected, SharePermissionManager.isFileRequest(share)) + } } }