From e73eb9a10304b4048b5ac4fe0ad273065da27716 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 11:21:29 +0100 Subject: [PATCH 01/24] Rename .java to .kt Signed-off-by: alperozturk96 --- .../holder/{LinkShareViewHolder.java => LinkShareViewHolder.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/{LinkShareViewHolder.java => LinkShareViewHolder.kt} (100%) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt similarity index 100% rename from app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.java rename to app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt From 099e1e7834e7a5949465cebdbe2fb8333026af07 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 11:21:30 +0100 Subject: [PATCH 02/24] fix(share): permission Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 87 +++++-- .../adapter/QuickSharingPermissionsAdapter.kt | 16 +- .../share/adapter/ShareeListAdapter.java | 4 +- .../adapter/holder/LinkShareViewHolder.kt | 228 +++++++++++------- .../share/adapter/holder/ShareViewHolder.java | 7 +- ...ivityShareItemActionBottomSheetDialog.java | 4 +- ...ckSharingPermissionsBottomSheetDialog.java | 98 +++----- .../share/helper/SharePermissionManager.kt | 86 +++++++ .../notes/share/helper/SharingMenuHelper.java | 109 --------- ...kPermissionModel.kt => QuickPermission.kt} | 2 +- .../notes/share/model/QuickPermissionType.kt | 45 ++++ .../owncloud/notes/util/OCShareExtensions.kt | 23 ++ app/src/main/res/drawable/ic_eye.xml | 16 ++ app/src/main/res/drawable/ic_file_request.xml | 16 ++ app/src/main/res/drawable/ic_unknown.xml | 17 ++ .../res/layout/activity_note_share_detail.xml | 4 +- app/src/main/res/values/arrays.xml | 11 - app/src/main/res/values/strings.xml | 3 + 18 files changed, 462 insertions(+), 314 deletions(-) create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt delete mode 100644 app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharingMenuHelper.java rename app/src/main/java/it/niedermann/owncloud/notes/share/model/{QuickPermissionModel.kt => QuickPermission.kt} (72%) create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt create mode 100644 app/src/main/res/drawable/ic_eye.xml create mode 100644 app/src/main/res/drawable/ic_file_request.xml create mode 100644 app/src/main/res/drawable/ic_unknown.xml diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 532d2edd0..2ea4e477e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -25,13 +25,15 @@ import it.niedermann.owncloud.notes.databinding.ActivityNoteShareDetailBinding import it.niedermann.owncloud.notes.persistence.entity.Note import it.niedermann.owncloud.notes.persistence.isSuccess import it.niedermann.owncloud.notes.share.dialog.ExpirationDatePickerDialogFragment -import it.niedermann.owncloud.notes.share.helper.SharingMenuHelper +import it.niedermann.owncloud.notes.share.helper.SharePermissionManager +import it.niedermann.owncloud.notes.share.model.QuickPermissionType import it.niedermann.owncloud.notes.share.model.SharePasswordRequest import it.niedermann.owncloud.notes.share.repository.ShareRepository import it.niedermann.owncloud.notes.shared.util.DisplayUtils import it.niedermann.owncloud.notes.shared.util.clipboard.ClipboardUtil import it.niedermann.owncloud.notes.shared.util.extensions.getParcelableArgument import it.niedermann.owncloud.notes.shared.util.extensions.getSerializableArgument +import it.niedermann.owncloud.notes.util.isPublicOrMail import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -113,7 +115,7 @@ class NoteShareDetailActivity : val ssoAcc = SingleAccountHelper.getCurrentSingleSignOnAccount(this@NoteShareDetailActivity) repository = ShareRepository(this@NoteShareDetailActivity, ssoAcc) - permission = repository.getCapabilities().defaultPermission + permission = share?.permissions ?: repository.getCapabilities().defaultPermission withContext(Dispatchers.Main) { if (shareProcessStep == SCREEN_TYPE_PERMISSION) { @@ -135,8 +137,8 @@ class NoteShareDetailActivity : binding.run { util.platform.run { - themeRadioButton(shareProcessPermissionReadOnly) - themeRadioButton(shareProcessPermissionUploadEditing) + themeRadioButton(canViewRadioButton) + themeRadioButton(canEditRadioButton) themeRadioButton(shareProcessPermissionFileDrop) colorTextView(shareProcessEditShareLink) @@ -212,14 +214,7 @@ class NoteShareDetailActivity : private fun setupModificationUI() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() - // read only / allow upload and editing / file drop - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - binding.shareProcessPermissionUploadEditing.isChecked = true - } else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) { - binding.shareProcessPermissionFileDrop.isChecked = true - } else if (SharingMenuHelper.isReadOnly(share)) { - binding.shareProcessPermissionReadOnly.isChecked = true - } + selectRadioButtonAccordingToPermission() shareType = share?.shareType ?: ShareType.NO_SHARED @@ -238,6 +233,35 @@ class NoteShareDetailActivity : showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) updateExpirationDateView() showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) + setMaxPermissionsIfDefaultPermissionExists() + } + + private fun selectRadioButtonAccordingToPermission() { + val selectedType = SharePermissionManager.getSelectedType(share, encrypted = false) + binding.run { + when (selectedType) { + QuickPermissionType.VIEW_ONLY -> { + canViewRadioButton.isChecked = true + } + + QuickPermissionType.CAN_EDIT -> { + canEditRadioButton.isChecked = true + } + + QuickPermissionType.FILE_REQUEST -> { + shareProcessPermissionFileDrop.isChecked = true + } + + else -> Unit + } + } + } + + private fun setMaxPermissionsIfDefaultPermissionExists() { + if (repository.getCapabilities().defaultPermission != OCShare.NO_PERMISSION) { + binding.canEditRadioButton.isChecked = true + permission = SharePermissionManager.getMaximumPermission(isFolder()) + } } private fun setupUpdateUI() { @@ -300,7 +324,7 @@ class NoteShareDetailActivity : shareProcessAllowResharingCheckbox.visibility = View.GONE } shareProcessAllowResharingCheckbox.isChecked = - SharingMenuHelper.canReshare(share) + SharePermissionManager.canReshare(share) } } } @@ -315,7 +339,7 @@ class NoteShareDetailActivity : shareProcessSetPasswordSwitch.visibility = View.VISIBLE if (share != null) { - if (SharingMenuHelper.isFileDrop(share)) { + if (SharePermissionManager.isFileRequest(share)) { shareProcessHideDownloadCheckbox.visibility = View.GONE } else { shareProcessHideDownloadCheckbox.visibility = View.VISIBLE @@ -343,13 +367,13 @@ class NoteShareDetailActivity : } private fun updateViewForFile() { - binding.shareProcessPermissionUploadEditing.text = getString(R.string.link_share_editing) + binding.canEditRadioButton.text = getString(R.string.link_share_editing) binding.shareProcessPermissionFileDrop.visibility = View.GONE } private fun updateViewForFolder() { binding.run { - shareProcessPermissionUploadEditing.text = + canEditRadioButton.text = getString(R.string.link_share_allow_upload_and_editing) shareProcessPermissionFileDrop.visibility = View.VISIBLE if (isSecureShare) { @@ -382,6 +406,7 @@ class NoteShareDetailActivity : } } + @Suppress("LongMethod") private fun implementClickEvents() { binding.run { shareProcessBtnCancel.setOnClickListener { @@ -406,6 +431,24 @@ class NoteShareDetailActivity : shareProcessSelectExpDate.setOnClickListener { showExpirationDateDialog() } + + // region RadioButtons + shareProcessPermissionRadioGroup.setOnCheckedChangeListener { _, optionId -> + when (optionId) { + R.id.can_view_radio_button -> { + permission = OCShare.READ_PERMISSION_FLAG + } + + R.id.can_edit_radio_button -> { + permission = SharePermissionManager.getMaximumPermission(isFolder()) + } + + R.id.share_process_permission_file_drop -> { + permission = OCShare.CREATE_PERMISSION_FLAG + } + } + } + // endregion } } @@ -526,8 +569,8 @@ class NoteShareDetailActivity : */ private fun getSelectedPermission() = when { binding.shareProcessAllowResharingCheckbox.isChecked -> getReSharePermission() - binding.shareProcessPermissionReadOnly.isChecked -> OCShare.READ_PERMISSION_FLAG - binding.shareProcessPermissionUploadEditing.isChecked -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + binding.canViewRadioButton.isChecked -> OCShare.READ_PERMISSION_FLAG + binding.canEditRadioButton.isChecked -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE binding.shareProcessPermissionFileDrop.isChecked -> OCShare.CREATE_PERMISSION_FLAG else -> permission } @@ -627,4 +670,12 @@ class NoteShareDetailActivity : override fun onDateUnSet() { binding.shareProcessSetExpDateSwitch.isChecked = false } + + // region Helpers + private fun isFolder(): Boolean = (share?.isFolder == true) + + private fun canSetFileRequest(): Boolean = isFolder() && shareType.isPublicOrMail() + + private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK) + // endregion } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/QuickSharingPermissionsAdapter.kt index 062ff37f4..eae3259c5 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/QuickSharingPermissionsAdapter.kt @@ -6,19 +6,19 @@ */ package it.niedermann.owncloud.notes.share.adapter +import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.annotation.ColorInt import androidx.recyclerview.widget.RecyclerView import com.nextcloud.android.common.ui.theme.utils.ColorRole import it.niedermann.owncloud.notes.branding.Branded import it.niedermann.owncloud.notes.branding.BrandingUtil import it.niedermann.owncloud.notes.databinding.ItemQuickSharePermissionsBinding -import it.niedermann.owncloud.notes.share.model.QuickPermissionModel +import it.niedermann.owncloud.notes.share.model.QuickPermission class QuickSharingPermissionsAdapter( - private val quickPermissionList: MutableList, + private val quickPermissionList: MutableList, private val onPermissionChangeListener: QuickSharingPermissionViewHolder.OnPermissionChangeListener, private var color: Int = 0 ) : @@ -45,6 +45,7 @@ class QuickSharingPermissionsAdapter( return quickPermissionList.size } + @SuppressLint("NotifyDataSetChanged") override fun applyBrand(color: Int) { this.color = color notifyDataSetChanged() @@ -59,9 +60,10 @@ class QuickSharingPermissionsAdapter( RecyclerView .ViewHolder(itemView) { - fun bindData(quickPermissionModel: QuickPermissionModel) { - binding.tvQuickShareName.text = quickPermissionModel.permissionName - if (quickPermissionModel.isSelected) { + fun bindData(quickPermission: QuickPermission) { + val permissionName = quickPermission.type.getText(itemView.context) + binding.tvQuickShareName.text = permissionName + if (quickPermission.isSelected) { binding.tvQuickShareCheckIcon.visibility = View.VISIBLE } else { binding.tvQuickShareCheckIcon.visibility = View.INVISIBLE @@ -69,7 +71,7 @@ class QuickSharingPermissionsAdapter( itemView.setOnClickListener { // if user select different options then only update the permission - if (!quickPermissionModel.isSelected) { + if (!quickPermission.isSelected) { onPermissionChangeListener.onPermissionChanged(adapterPosition) } else { // dismiss sheet on selection of same permission diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java index 3c45dbd63..a3935442e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java @@ -99,7 +99,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int layoutInflater, parent, false); brandingUtil.platform.colorTextView(binding.name, ColorRole.ON_SURFACE); brandingUtil.platform.colorTextView(binding.subline, ColorRole.ON_SURFACE_VARIANT); - return new LinkShareViewHolder(binding, activity); + return new LinkShareViewHolder(binding); } case NEW_PUBLIC_LINK -> { ItemAddPublicShareBinding binding = ItemAddPublicShareBinding.inflate( @@ -135,7 +135,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) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt index 58ed535f2..1244ae7c1 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt @@ -1,124 +1,168 @@ /* * Nextcloud Notes - Android Client * - * SPDX-FileCopyrightText: 2015-2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2015-2026 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ -package it.niedermann.owncloud.notes.share.adapter.holder; +package it.niedermann.owncloud.notes.share.adapter.holder + +import android.text.TextUtils +import android.view.View +import androidx.core.content.res.ResourcesCompat +import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.ShareType +import it.niedermann.owncloud.notes.R +import it.niedermann.owncloud.notes.branding.BrandedViewHolder +import it.niedermann.owncloud.notes.branding.BrandingUtil +import it.niedermann.owncloud.notes.databinding.ItemShareLinkShareBinding +import it.niedermann.owncloud.notes.share.helper.SharePermissionManager +import it.niedermann.owncloud.notes.share.helper.SharePermissionManager.isSecureFileDrop +import it.niedermann.owncloud.notes.share.listener.ShareeListAdapterListener +import it.niedermann.owncloud.notes.share.model.QuickPermissionType +import it.niedermann.owncloud.notes.util.remainingDownloadLimit + +class LinkShareViewHolder( + private val binding: ItemShareLinkShareBinding +) : BrandedViewHolder(binding.root) { + + init { + bindBranding() + } -import android.content.Context; -import android.text.TextUtils; -import android.view.View; + fun bind(publicShare: OCShare, listener: ShareeListAdapterListener, position: Int) { + val quickPermissionType = SharePermissionManager.getSelectedType(publicShare, false) -import androidx.annotation.NonNull; -import androidx.core.content.res.ResourcesCompat; + setName(binding, publicShare, position) + setSubline(binding, publicShare) + setPermissionName(binding, publicShare, quickPermissionType) + setOnClickListeners(binding, listener, publicShare) + configureCopyLink(binding, listener, publicShare) + } -import com.nextcloud.android.common.ui.theme.utils.ColorRole; -import com.owncloud.android.lib.resources.shares.OCShare; -import com.owncloud.android.lib.resources.shares.ShareType; + @Suppress("ReturnCount") + private fun setName( + binding: ItemShareLinkShareBinding?, + publicShare: OCShare, + position: Int + ) { + val context = binding?.root?.context -import java.text.SimpleDateFormat; -import java.util.Date; + if (binding == null || context == null) { + return + } -import it.niedermann.owncloud.notes.R; -import it.niedermann.owncloud.notes.branding.BrandedViewHolder; -import it.niedermann.owncloud.notes.branding.BrandingUtil; -import it.niedermann.owncloud.notes.databinding.ItemShareLinkShareBinding; -import it.niedermann.owncloud.notes.share.helper.SharingMenuHelper; -import it.niedermann.owncloud.notes.share.listener.ShareeListAdapterListener; + if (ShareType.PUBLIC_LINK == publicShare.shareType) { + val label = publicShare.label + binding.name.text = when { + label.isNullOrBlank() && position == 0 -> + context.getString(R.string.share_link) -public class LinkShareViewHolder extends BrandedViewHolder { - private ItemShareLinkShareBinding binding; - private Context context; + label.isNullOrBlank() -> + context.getString(R.string.share_link_with_label, position.toString()) - private BrandingUtil brandingUtil; + else -> + context.getString(R.string.share_link_with_label, label) + } + return + } - public LinkShareViewHolder(@NonNull View itemView) { - super(itemView); - bindBranding(); - } + if (ShareType.EMAIL == publicShare.shareType) { + binding.name.text = publicShare.sharedWithDisplayName - public LinkShareViewHolder(ItemShareLinkShareBinding binding, Context context) { - this(binding.getRoot()); - this.binding = binding; - this.context = context; - bindBranding(); + val emailDrawable = ResourcesCompat.getDrawable(context.resources, R.drawable.ic_email, null) + binding.icon.setImageDrawable(emailDrawable) + binding.copyLink.visibility = View.GONE + return + } + + val label = publicShare.label + if (!label.isNullOrEmpty()) { + binding.name.text = context.getString(R.string.share_link_with_label, label) + } } - public void bind(OCShare publicShare, ShareeListAdapterListener listener) { - if (publicShare.getShareType() != null && ShareType.EMAIL == publicShare.getShareType()) { - binding.name.setText(publicShare.getSharedWithDisplayName()); - binding.icon.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), - R.drawable.ic_email, - null)); - if (publicShare.getLabel() != null && !publicShare.getLabel().isEmpty()) { - brandingUtil.platform.colorTextView(binding.name, ColorRole.ON_SURFACE_VARIANT); - binding.label.setText(publicShare.getLabel()); - binding.label.setVisibility(View.VISIBLE); - } else { - brandingUtil.platform.colorTextView(binding.name, ColorRole.ON_SURFACE); - binding.label.setVisibility(View.GONE); - } - binding.copyLink.setVisibility(View.GONE); - } else { - brandingUtil.platform.colorTextView(binding.name, ColorRole.ON_SURFACE); - if (!TextUtils.isEmpty(publicShare.getLabel())) { - String text = String.format(context.getString(R.string.share_link_with_label), publicShare.getLabel()); - binding.name.setText(text); - } 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); - } - } + private fun setSubline(binding: ItemShareLinkShareBinding?, publicShare: OCShare) { + val context = binding?.root?.context + if (binding == null || context == null) { + return } - binding.subline.setVisibility(View.GONE); + val downloadLimit = publicShare.fileDownloadLimit + if (downloadLimit != null) { + val remaining = publicShare.remainingDownloadLimit() ?: return + val text = context.resources.getQuantityString( + R.plurals.share_download_limit_description, + remaining, + remaining + ) + + binding.subline.text = text + binding.subline.visibility = View.VISIBLE + return + } + + binding.subline.visibility = View.GONE + } - String permissionName = SharingMenuHelper.getPermissionName(context, publicShare); - setPermissionName(publicShare, permissionName); + private fun setPermissionName( + binding: ItemShareLinkShareBinding?, + publicShare: OCShare?, + quickPermissionType: QuickPermissionType + ) { + val context = binding?.root?.context - binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare)); - if (!SharingMenuHelper.isSecureFileDrop(publicShare)) { - binding.shareByLinkContainer.setOnClickListener(v -> listener.showPermissionsDialog(publicShare)); + if (binding == null || context == null) { + return } - if (publicShare.getExpirationDate() > 0) { - String expirationDescription = context.getString( - R.string.share_expires, - SimpleDateFormat.getDateInstance().format(new Date(publicShare.getExpirationDate())) - ); - binding.expirationStatus.setContentDescription(expirationDescription); - binding.expirationStatus.setVisibility(View.VISIBLE); - binding.shareIconContainer.setOnClickListener( - v -> listener.showShareExpirationSnackbar(publicShare) - ); - } else { - binding.expirationStatus.setContentDescription(null); - binding.expirationStatus.setVisibility(View.GONE); + val permissionName = quickPermissionType.getText(context) + + if (TextUtils.isEmpty(permissionName) || (isSecureFileDrop(publicShare))) { + binding.permissionName.visibility = View.GONE + return } - binding.copyLink.setOnClickListener(v -> listener.copyLink(publicShare)); + binding.permissionName.text = permissionName + binding.permissionName.visibility = View.VISIBLE } - private void setPermissionName(OCShare publicShare, String permissionName) { - if (!TextUtils.isEmpty(permissionName) && !SharingMenuHelper.isSecureFileDrop(publicShare)) { - binding.permissionName.setText(permissionName); - binding.permissionName.setVisibility(View.VISIBLE); - } else { - binding.permissionName.setVisibility(View.GONE); + private fun setOnClickListeners( + binding: ItemShareLinkShareBinding?, + listener: ShareeListAdapterListener, + publicShare: OCShare + ) { + if (binding == null) { + return + } + + binding.overflowMenu.setOnClickListener { + listener.showSharingMenuActionSheet(publicShare) + } + binding.shareByLinkContainer.setOnClickListener { + listener.showPermissionsDialog(publicShare) } } - @Override - public void applyBrand(int color) { - brandingUtil = BrandingUtil.of(color, context); - if (binding != null) { - brandingUtil.androidx.colorPrimaryTextViewElement(binding.permissionName); - brandingUtil.platform.colorTextView(binding.label, ColorRole.ON_SURFACE); - brandingUtil.platform.colorImageViewBackgroundAndIcon(binding.icon); - brandingUtil.platform.colorImageView(binding.expirationStatus, ColorRole.ON_PRIMARY_CONTAINER); + private fun configureCopyLink( + binding: ItemShareLinkShareBinding?, + listener: ShareeListAdapterListener, + publicShare: OCShare + ) { + val context = binding?.root?.context + + if (binding == null || context == null) { + return } + + binding.copyLink.setOnClickListener { listener.copyLink(publicShare) } + } + + override fun applyBrand(color: Int) { + val brandingUtil = BrandingUtil.of(color, binding.root.context) + brandingUtil.androidx.colorPrimaryTextViewElement(binding.permissionName) + brandingUtil.platform.colorTextView(binding.label, ColorRole.ON_SURFACE) + brandingUtil.platform.colorImageViewBackgroundAndIcon(binding.icon) + brandingUtil.platform.colorImageView(binding.expirationStatus, ColorRole.ON_PRIMARY_CONTAINER) } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java index 660461bcb..cf5245ade 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java @@ -23,8 +23,9 @@ import it.niedermann.owncloud.notes.databinding.ItemShareShareBinding; import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.share.helper.AvatarLoader; -import it.niedermann.owncloud.notes.share.helper.SharingMenuHelper; +import it.niedermann.owncloud.notes.share.helper.SharePermissionManager; import it.niedermann.owncloud.notes.share.listener.ShareeListAdapterListener; +import it.niedermann.owncloud.notes.share.model.QuickPermissionType; import it.niedermann.owncloud.notes.shared.util.FilesSpecificViewThemeUtils; public class ShareViewHolder extends BrandedViewHolder { @@ -101,8 +102,8 @@ public void bind(OCShare share, ShareeListAdapterListener listener) { accountUserName.equalsIgnoreCase(share.getUserId())) { binding.overflowMenu.setVisibility(View.VISIBLE); - String permissionName = SharingMenuHelper.getPermissionName(context, share); - setPermissionName(permissionName); + QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(share, false); + setPermissionName(quickPermissionType.getText(context)); // bind listener to edit privileges binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(share)); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java index 6700e6367..fcdf7daad 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java @@ -19,7 +19,7 @@ import it.niedermann.owncloud.notes.branding.BrandedBottomSheetDialog; import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.ItemNoteShareActionBinding; -import it.niedermann.owncloud.notes.share.helper.SharingMenuHelper; +import it.niedermann.owncloud.notes.share.helper.SharePermissionManager; import it.niedermann.owncloud.notes.share.listener.NoteShareItemAction; public class NoteShareActivityShareItemActionBottomSheetDialog extends BrandedBottomSheetDialog { @@ -63,7 +63,7 @@ private void updateUI() { binding.menuShareSendLink.setVisibility(View.GONE); } - if (SharingMenuHelper.isSecureFileDrop(ocShare)) { + if (SharePermissionManager.INSTANCE.isSecureFileDrop(ocShare)) { binding.menuShareAdvancedPermissions.setVisibility(View.GONE); binding.menuShareAddAnotherLink.setVisibility(View.GONE); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java index b39c95401..0f651d005 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java @@ -6,10 +6,6 @@ */ package it.niedermann.owncloud.notes.share.dialog; -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.READ_PERMISSION_FLAG; import android.app.Activity; import android.os.Bundle; @@ -21,16 +17,15 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.owncloud.android.lib.resources.shares.OCShare; -import java.util.ArrayList; import java.util.List; -import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.branding.BrandedBottomSheetDialog; import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; import it.niedermann.owncloud.notes.share.adapter.QuickSharingPermissionsAdapter; -import it.niedermann.owncloud.notes.share.helper.SharingMenuHelper; -import it.niedermann.owncloud.notes.share.model.QuickPermissionModel; +import it.niedermann.owncloud.notes.share.helper.SharePermissionManager; +import it.niedermann.owncloud.notes.share.model.QuickPermission; +import it.niedermann.owncloud.notes.util.OCShareExtensionsKt; /** * File Details Quick Sharing permissions options {@link android.app.Dialog} styled as a bottom sheet for main actions. @@ -72,78 +67,47 @@ protected void onCreate(Bundle savedInstanceState) { } private void setUpRecyclerView() { - List quickPermissionModelList = getQuickPermissionList(); - adapter = new QuickSharingPermissionsAdapter( - quickPermissionModelList, - new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() { - @Override - public void onPermissionChanged(int position) { - handlePermissionChanged(quickPermissionModelList, position); - } - - @Override - public void onDismissSheet() { - dismiss(); - } - }, - color + List quickPermissionList = getQuickPermissionList(); + QuickSharingPermissionsAdapter adapter = new QuickSharingPermissionsAdapter( + quickPermissionList, + new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() { + @Override + public void onPermissionChanged(int position) { + handlePermissionChanged(quickPermissionList, position); + } + + @Override + public void onDismissSheet() { + dismiss(); + } + }, + color ); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity); - adapter.applyBrand(color); binding.rvQuickSharePermissions.setLayoutManager(linearLayoutManager); binding.rvQuickSharePermissions.setAdapter(adapter); + adapter.applyBrand(color); } - private void handlePermissionChanged(List quickPermissionModelList, int position) { - if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(activity.getResources().getString(R.string.link_share_allow_upload_and_editing)) - || quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(activity.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(activity.getResources().getString(R.string - .link_share_view_only))) { - actions.onQuickPermissionChanged(ocShare, - READ_PERMISSION_FLAG); - - } else if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(activity.getResources().getString(R.string - .link_share_file_drop))) { - actions.onQuickPermissionChanged(ocShare, - CREATE_PERMISSION_FLAG); - } + /** + * Handle permission changed on click of selected permission + */ + private void handlePermissionChanged(List quickPermissionList, int position) { + final var type = quickPermissionList.get(position).getType(); + int permissionFlag = type.getPermissionFlag(ocShare.isFolder()); + actions.onQuickPermissionChanged(ocShare, permissionFlag); dismiss(); } /** - * prepare the list of permissions needs to be displayed on recyclerview - * @return + * Prepare the list of permissions needs to be displayed on recyclerview */ - private List getQuickPermissionList() { - - String[] permissionArray; - if (ocShare.isFolder()) { - permissionArray = - activity.getResources().getStringArray(R.array.quick_sharing_permission_bottom_sheet_dialog_folder_share_values); - } else { - permissionArray = - activity.getResources().getStringArray(R.array.quick_sharing_permission_bottom_sheet_dialog_note_share_values); - } - //get the checked item position - int checkedItem = SharingMenuHelper.getPermissionCheckedItem(activity, 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); - } - return quickPermissionModelList; + private List getQuickPermissionList() { + final var selectedType = SharePermissionManager.INSTANCE.getSelectedType(ocShare, false); + final var hasFileRequestPermission = OCShareExtensionsKt.hasFileRequestPermission(ocShare); + return selectedType.getAvailablePermissions(hasFileRequestPermission); } - @Override protected void onStop() { super.onStop(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt new file mode 100644 index 000000000..5a61c24f9 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt @@ -0,0 +1,86 @@ +/* + * Nextcloud Notes - Android Client + * + * SPDX-FileCopyrightText: 2015-2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package it.niedermann.owncloud.notes.share.helper + +import com.owncloud.android.lib.resources.shares.OCShare +import it.niedermann.owncloud.notes.share.model.QuickPermissionType + +object SharePermissionManager { + + // region Permission check + fun hasPermission(permission: Int, permissionFlag: Int): Boolean = + permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag + + // region Helper Methods + fun canEdit(share: OCShare?): Boolean { + if (share == null) { + return false + } + + return hasPermission(share.permissions, getMaximumPermission(share.isFolder)) + } + + fun isViewOnly(share: OCShare?): Boolean { + if (share == null) { + return false + } + + return share.permissions != OCShare.NO_PERMISSION && + ( + share.permissions == OCShare.READ_PERMISSION_FLAG || + share.permissions == OCShare.READ_PERMISSION_FLAG + OCShare.SHARE_PERMISSION_FLAG + ) + } + + @Suppress("ReturnCount") + fun isFileRequest(share: OCShare?): Boolean { + if (share == null) { + return false + } + + if (!share.isFolder) { + return false + } + + 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.SHARE_PERMISSION_FLAG) > 0 + } + + fun getSelectedType(share: OCShare?, encrypted: Boolean): QuickPermissionType = if (canEdit(share)) { + QuickPermissionType.CAN_EDIT + } else if (encrypted && isSecureFileDrop(share)) { + QuickPermissionType.SECURE_FILE_DROP + } else if (isViewOnly(share)) { + QuickPermissionType.VIEW_ONLY + } else if (isFileRequest(share)) { + QuickPermissionType.FILE_REQUEST + } else { + QuickPermissionType.NONE + } + + fun getMaximumPermission(isFolder: Boolean): Int = if (isFolder) { + OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER + } else { + OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + } + // endregion +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharingMenuHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharingMenuHelper.java deleted file mode 100644 index 5eb0bae70..000000000 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharingMenuHelper.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Nextcloud Notes - Android Client - * - * SPDX-FileCopyrightText: 2015-2025 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package it.niedermann.owncloud.notes.share.helper; - -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; - -import android.content.Context; - -import com.owncloud.android.lib.resources.shares.OCShare; - -import it.niedermann.owncloud.notes.R; - -/** - * Helper calls for visibility logic of the sharing menu. - */ -public final class SharingMenuHelper { - - private SharingMenuHelper() { - // utility class -> private constructor - } - - public static boolean isUploadAndEditingAllowed(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 isReadOnly(OCShare share) { - if (share.getPermissions() == NO_PERMISSION) { - return false; - } - - return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == READ_PERMISSION_FLAG; - } - - public static boolean isFileDrop(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 String getPermissionName(Context context, OCShare share) { - if (SharingMenuHelper.isUploadAndEditingAllowed(share)) { - return context.getResources().getString(R.string.share_permission_can_edit); - } else if (SharingMenuHelper.isReadOnly(share)) { - return context.getResources().getString(R.string.share_permission_view_only); - } else if (SharingMenuHelper.isSecureFileDrop(share)) { - return context.getResources().getString(R.string.share_permission_secure_file_drop); - } else if (SharingMenuHelper.isFileDrop(share)) { - return context.getResources().getString(R.string.share_permission_file_drop); - } - return null; - } - - /** - * method to get the current checked index from the list of permissions - * - */ - public static int getPermissionCheckedItem(Context context, OCShare share, String[] permissionArray) { - 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); - } - } else if (SharingMenuHelper.isReadOnly(share)) { - 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); - } - return 0;//default first item selected - } - - 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; - } - - public static boolean canReshare(OCShare share) { - return (share.getPermissions() & SHARE_PERMISSION_FLAG) > 0; - } -} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionModel.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermission.kt similarity index 72% rename from app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionModel.kt rename to app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermission.kt index 6a7bec0e8..b4f215e63 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionModel.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermission.kt @@ -6,4 +6,4 @@ */ package it.niedermann.owncloud.notes.share.model -data class QuickPermissionModel(val permissionName: String, val isSelected: Boolean) +data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt new file mode 100644 index 000000000..376a15256 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt @@ -0,0 +1,45 @@ +/* + * Nextcloud Notes - Android Client + * + * SPDX-FileCopyrightText: 2015-2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package it.niedermann.owncloud.notes.share.model + +import android.content.Context +import android.graphics.drawable.Drawable +import androidx.core.content.ContextCompat +import com.owncloud.android.lib.resources.shares.OCShare +import it.niedermann.owncloud.notes.R + +enum class QuickPermissionType(val iconId: Int, val textId: Int) { + NONE(R.drawable.ic_unknown, R.string.share_permission_unknown), + 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.share_permission_file_request), + SECURE_FILE_DROP(R.drawable.ic_file_request, R.string.share_permission_secure_file_drop); + + fun getText(context: Context): String = context.getString(textId) + + fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, iconId) + + fun getPermissionFlag(isFolder: Boolean): Int = when (this) { + NONE -> OCShare.NO_PERMISSION + VIEW_ONLY -> OCShare.READ_PERMISSION_FLAG + CAN_EDIT -> if (isFolder) OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER else OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + FILE_REQUEST -> OCShare.CREATE_PERMISSION_FLAG + SECURE_FILE_DROP -> OCShare.CREATE_PERMISSION_FLAG + OCShare.READ_PERMISSION_FLAG + } + + fun getAvailablePermissions(hasFileRequestPermission: Boolean): List { + val permissions = listOf(VIEW_ONLY, CAN_EDIT, FILE_REQUEST) + val result = if (hasFileRequestPermission) permissions else permissions.filter { it != FILE_REQUEST } + + return result.map { type -> + QuickPermission( + type = type, + isSelected = (type == this) + ) + } + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt b/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt new file mode 100644 index 000000000..b292c2c49 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt @@ -0,0 +1,23 @@ +/* + * Nextcloud Notes - Android Client + * + * SPDX-FileCopyrightText: 2015-2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package it.niedermann.owncloud.notes.util + +import com.owncloud.android.lib.resources.shares.OCShare +import com.owncloud.android.lib.resources.shares.ShareType + +fun OCShare.hasFileRequestPermission(): Boolean = (isFolder && shareType?.isPublicOrMail() == true) + +fun ShareType.isPublicOrMail(): Boolean = (this == ShareType.PUBLIC_LINK || this == ShareType.EMAIL) + +fun OCShare?.remainingDownloadLimit(): Int? { + val downloadLimit = this?.fileDownloadLimit ?: return null + return if (downloadLimit.limit > 0) { + downloadLimit.limit - downloadLimit.count + } else { + null + } +} 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 000000000..c62b99ba8 --- /dev/null +++ b/app/src/main/res/drawable/ic_eye.xml @@ -0,0 +1,16 @@ + + + + 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 000000000..58194805b --- /dev/null +++ b/app/src/main/res/drawable/ic_file_request.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/drawable/ic_unknown.xml b/app/src/main/res/drawable/ic_unknown.xml new file mode 100644 index 000000000..09be873b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_unknown.xml @@ -0,0 +1,17 @@ + + + + diff --git a/app/src/main/res/layout/activity_note_share_detail.xml b/app/src/main/res/layout/activity_note_share_detail.xml index a782f5b60..58e81049b 100644 --- a/app/src/main/res/layout/activity_note_share_detail.xml +++ b/app/src/main/res/layout/activity_note_share_detail.xml @@ -65,14 +65,14 @@ android:orientation="vertical"> .txt .md - - - - @string/link_share_view_only - @string/link_share_allow_upload_and_editing - @string/link_share_file_drop - - - @string/link_share_view_only - @string/link_share_editing - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3dfe25173..e49b1dcb1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -135,6 +135,9 @@ File drop (upload only) Could not retrieve shares View only + Unknown + + File request Can edit File drop Secure file drop From bfedd26476f30bbadacfb0ac2d74777aab3ffdff Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 11:40:59 +0100 Subject: [PATCH 03/24] fix(share): permission Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 2ea4e477e..62b2a5be0 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.Date +import kotlin.text.clear /** * Activity class to show share permission options, set expiration date, change label, set password, send note @@ -119,11 +120,12 @@ class NoteShareDetailActivity : withContext(Dispatchers.Main) { if (shareProcessStep == SCREEN_TYPE_PERMISSION) { - showShareProcessFirst() + setupUI() } else { - showShareProcessSecond() + updateViewForNoteScreenType() } implementClickEvents() + setVisibilitiesOfShareOption() } } } @@ -132,6 +134,16 @@ class NoteShareDetailActivity : finish() } + private fun setVisibilitiesOfShareOption() { + binding.run { + if (canSetFileRequest()) { + shareProcessPermissionFileDrop.visibility = View.VISIBLE + } else { + shareProcessPermissionFileDrop.visibility = View.GONE + } + } + } + override fun applyBrand(color: Int) { val util = BrandingUtil.of(color, this) @@ -184,17 +196,15 @@ class NoteShareDetailActivity : } } - private fun showShareProcessFirst() { - binding.shareProcessGroupOne.visibility = View.VISIBLE - binding.shareProcessEditShareLink.visibility = View.VISIBLE - binding.shareProcessGroupTwo.visibility = View.GONE - - if (share != null) { - setupModificationUI() - } else { - setupUpdateUI() + private fun setupUI() { + binding.run { + shareProcessGroupOne.visibility = View.VISIBLE + shareProcessEditShareLink.visibility = View.VISIBLE + shareProcessGroupTwo.visibility = View.GONE } + updateView() + if (isSecureShare) { binding.shareProcessAdvancePermissionTitle.visibility = View.GONE } @@ -211,7 +221,15 @@ class NoteShareDetailActivity : shareProcessStep = SCREEN_TYPE_PERMISSION } - private fun setupModificationUI() { + private fun updateView() { + if (share != null) { + updateViewForUpdate() + } else { + updateViewForCreate() + } + } + + private fun updateViewForUpdate() { if (share?.isFolder == true) updateViewForFolder() else updateViewForFile() selectRadioButtonAccordingToPermission() @@ -221,7 +239,7 @@ class NoteShareDetailActivity : // 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.note_share_detail_activity_share_copy_link } else { R.string.note_share_detail_activity_common_confirm @@ -233,7 +251,22 @@ class NoteShareDetailActivity : showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) updateExpirationDateView() showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) - setMaxPermissionsIfDefaultPermissionExists() + maskPasswordInput() + } + + private fun maskPasswordInput() { + if (share?.isPasswordProtected == false) { + return + } + + binding.shareProcessEnterPassword.run { + setText("••••••") + setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + text?.clear() + } + } + } } private fun selectRadioButtonAccordingToPermission() { @@ -264,7 +297,7 @@ class NoteShareDetailActivity : } } - private fun setupUpdateUI() { + private fun updateViewForCreate() { binding.shareProcessBtnNext.text = getString(R.string.note_share_detail_activity_common_next) note.let { @@ -273,6 +306,7 @@ class NoteShareDetailActivity : } showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked) showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked) + setMaxPermissionsIfDefaultPermissionExists() } private fun updateViewForShareType() { @@ -387,7 +421,7 @@ class NoteShareDetailActivity : /** * update views for screen type Note */ - private fun showShareProcessSecond() { + private fun updateViewForNoteScreenType() { binding.run { shareProcessGroupOne.visibility = View.GONE shareProcessEditShareLink.visibility = View.GONE @@ -477,7 +511,7 @@ class NoteShareDetailActivity : // and if user is in step 1 (permission screen) then remove the activity else { if (shareProcessStep == SCREEN_TYPE_NOTE) { - showShareProcessFirst() + setupUI() } else { finish() } @@ -560,7 +594,7 @@ class NoteShareDetailActivity : } } else { // else show step 2 (note screen) - showShareProcessSecond() + updateViewForNoteScreenType() } } From 7744c723519f752ef9a828502cfb0eba0f347e03 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 11:59:02 +0100 Subject: [PATCH 04/24] fix link label update Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 25 ++++++++++--------- .../notes/share/model/UpdateShareRequest.kt | 3 +++ .../notes/share/repository/ShareRepository.kt | 2 ++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 62b2a5be0..7a48ebf6c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -39,7 +39,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.Date -import kotlin.text.clear /** * Activity class to show share permission options, set expiration date, change label, set password, send note @@ -589,8 +588,8 @@ class NoteShareDetailActivity : lifecycleScope.launch(Dispatchers.IO) { val noteText = binding.noteText.text.toString().trim() val password = binding.shareProcessEnterPassword.text.toString().trim() - - updateShare(noteText, password, false) + val label = binding.shareProcessChangeName.text.toString() + updateShare(noteText, label, password, false) } } else { // else show step 2 (note screen) @@ -618,23 +617,25 @@ class NoteShareDetailActivity : lifecycleScope.launch(Dispatchers.IO) { if (share != null && share?.note != noteText) { - updateShare(noteText, password, true) + val label = binding.shareProcessChangeName.text.toString() + updateShare(noteText, label, password, true) } else { createShare(noteText, password) } } } - private suspend fun updateShare(noteText: String, password: String, sendEmail: Boolean) { + private suspend fun updateShare(noteText: String, label: String, password: String, sendEmail: Boolean) { val downloadPermission = !binding.shareProcessHideDownloadCheckbox.isChecked val requestBody = repository.getUpdateShareRequest( - downloadPermission, - share, - noteText, - password, - sendEmail, - chosenExpDateInMills, - permission + downloadPermission = downloadPermission, + share = share, + noteText = noteText, + label = label, + password = password, + sendEmail = sendEmail, + chosenExpDateInMills = chosenExpDateInMills, + permission = permission ) val updateShareResult = repository.updateShare(share!!.id, requestBody) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt index 67c88f174..ac3af6d29 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt @@ -24,6 +24,9 @@ data class UpdateShareRequest( @Expose val expireDate: String?, + @Expose + val label: String?, + @Expose val note: String, diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index 8b7c7e478..d1f7854ca 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -206,6 +206,7 @@ class ShareRepository(private val applicationContext: Context, private val accou downloadPermission: Boolean, share: OCShare?, noteText: String, + label: String, password: String, sendEmail: Boolean, chosenExpDateInMills: Long, @@ -238,6 +239,7 @@ class ShareRepository(private val applicationContext: Context, private val accou password = password, publicUpload = "false", expireDate = getExpirationDate(chosenExpDateInMills), + label = label, note = noteText, attributes = attributes, sendMail = sendEmail.toString() From 53e651faf9b55a9ebd550b0ac5b0e1b626a9cdf7 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 11:59:55 +0100 Subject: [PATCH 05/24] fix link label update Signed-off-by: alperozturk96 --- .../it/niedermann/owncloud/notes/share/NoteShareActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index b5fb2d543..6c6aae534 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -885,6 +885,7 @@ public void setPasswordToShare(@NotNull OCShare share, @Nullable String password false, share, "", + "", password, false, -1, From e533fa49615d96cdf10acc46e0cb3bf7343dbe82 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 15:03:49 +0100 Subject: [PATCH 06/24] remove unexisting permissions Signed-off-by: alperozturk96 --- .../notes/persistence/NotesDatabase.java | 29 ++++---- .../notes/persistence/NotesRepository.java | 4 ++ .../notes/persistence/dao/ShareDao.kt | 4 ++ .../notes/persistence/entity/ShareEntity.kt | 3 +- .../notes/persistence/sync/ShareAPI.kt | 14 ++-- .../notes/share/NoteShareActivity.java | 51 ++++---------- .../notes/share/NoteShareDetailActivity.kt | 61 +++------------- .../share/adapter/ShareeListAdapter.java | 2 +- .../holder/InternalShareViewHolder.java | 13 +--- .../adapter/holder/LinkShareViewHolder.kt | 8 +-- .../share/adapter/holder/ShareViewHolder.java | 2 +- ...ivityShareItemActionBottomSheetDialog.java | 6 -- ...ckSharingPermissionsBottomSheetDialog.java | 8 +-- .../share/helper/SharePermissionManager.kt | 35 +--------- .../notes/share/repository/ShareRepository.kt | 69 +++++++------------ .../owncloud/notes/util/OCShareExtensions.kt | 2 - .../res/layout/activity_note_share_detail.xml | 7 -- 17 files changed, 89 insertions(+), 229 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java index f711af4ca..3bbfe0e20 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java @@ -50,20 +50,21 @@ import it.niedermann.owncloud.notes.shared.model.Capabilities; @Database( - entities = { - Account.class, - Note.class, - CategoryOptions.class, - SingleNoteWidgetData.class, - NotesListWidgetData.class, - ShareEntity.class, - Capabilities.class - }, version = 28, - autoMigrations = { - @AutoMigration(from = 25, to = 26), - @AutoMigration(from = 26, to = 27), - @AutoMigration(from = 27, to = 28), - } + entities = { + Account.class, + Note.class, + CategoryOptions.class, + SingleNoteWidgetData.class, + NotesListWidgetData.class, + ShareEntity.class, + Capabilities.class + }, version = 29, + autoMigrations = { + @AutoMigration(from = 25, to = 26), + @AutoMigration(from = 26, to = 27), + @AutoMigration(from = 27, to = 28), + @AutoMigration(from = 28, to = 29), + } ) @TypeConverters({Converters.class}) public abstract class NotesDatabase extends RoomDatabase { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java index 47f15caa7..482fa080f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java @@ -1010,6 +1010,10 @@ public List getShareEntities(String path) { return db.getShareDao().getShareEntities(path); } + public void deleteShareById(int id) { + db.getShareDao().deleteById(id); + } + public void updateNote(Note note) { db.getNoteDao().updateNote(note); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/ShareDao.kt b/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/ShareDao.kt index 01f540e19..efdc01651 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/ShareDao.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/ShareDao.kt @@ -7,6 +7,7 @@ package it.niedermann.owncloud.notes.persistence.dao import androidx.room.Dao +import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query @@ -19,4 +20,7 @@ interface ShareDao { @Query("SELECT * FROM share_table WHERE path = :path") fun getShareEntities(path: String): List + + @Query("DELETE FROM share_table WHERE id = :id") + fun deleteById(id: Int) } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/ShareEntity.kt b/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/ShareEntity.kt index c8bfd4fcf..65dffdd02 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/ShareEntity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/ShareEntity.kt @@ -25,5 +25,6 @@ data class ShareEntity( val uid_owner: String? = null, val displayname_owner: String? = null, val url: String? = null, - val expiration_date: Long? = null + val expiration_date: Long? = null, + val permissions: Double? = null ) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt index 69c7429ba..34d20fd86 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt @@ -24,7 +24,7 @@ import retrofit2.http.Query interface ShareAPI { @GET("sharees") - fun getSharees( + fun fetchSharees( @Query("format") format: String = "json", @Query("itemType") itemType: String = "file", @Query("search") search: String, @@ -33,14 +33,8 @@ interface ShareAPI { @Query("lookup") lookup: String = "false", ): LinkedTreeMap? - @GET("shares/{remoteId}?format=json") - fun getShares( - @Path("remoteId") remoteId: Long, - @Query("include_tags") includeTags: Boolean = true, - ): Call>> - @GET("shares/?format=json") - fun getSharesForSpecificNote( + fun fetchSharesForSpecificNote( @Query("path") path: String, @Query("reshares") reshares: Boolean = true, @Query("subfiles") subfiles: Boolean = true @@ -65,8 +59,8 @@ interface ShareAPI { ): Call> @GET("shares/?format=json") - fun getShareFromNote( + fun fetchSharesFromNote( @Query("path") path: String, - @Query("shared_with_me") sharedWithMe: Boolean = true + @Query("shared_with_me") sharedWithMe: Boolean = false ): Call>> } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index 6c6aae534..3ffca123d 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -161,7 +161,7 @@ private void initializeArguments() { final var ssoAcc = SingleAccountHelper.getCurrentSingleSignOnAccount(NoteShareActivity.this); repository = new ShareRepository(NoteShareActivity.this, ssoAcc); capabilities = repository.getCapabilities(); - repository.getSharesForNotesAndSaveShareEntities(); + repository.fetchSharesForNotesAndSaveShareEntities(); runOnUiThread(() -> { binding.fileName.setText(note.getTitle()); @@ -519,17 +519,16 @@ public void updateShareeListAdapter() { return; } - List tempShares = new ArrayList<>(); - - // to show share with users/groups info + List remoteNotes; if (note != null) { - // get shares from local DB - populateSharesList(tempShares); + remoteNotes = repository.fetchSharesFromNote(note); + } else { + remoteNotes = new ArrayList<>(); } runOnUiThread(() -> { shares.clear(); - shares.addAll(tempShares); + shares.addAll(remoteNotes); adapter.removeAll(); adapter.addShares(shares); @@ -544,35 +543,6 @@ public void updateShareeListAdapter() { }); } - private void populateSharesList(List targetList) { - // Get shares from local DB - final var shareEntities = repository.getShareEntitiesForSpecificNote(note); - for (var entity : shareEntities) { - if (entity.getId() != null) { - addSharesToList(entity.getId(), targetList); - } - } - - // Get shares from remote - final var remoteShares = repository.getShareFromNote(note); - if (remoteShares != null) { - for (var entity : remoteShares) { - addSharesToList(entity.getId(), targetList); - } - } - } - - private void addSharesToList(long id, List targetList) { - final var result = repository.getShares(id); - if (result != null) { - for (OCShare ocShare : result) { - if (!targetList.contains(ocShare)) { - targetList.add(ocShare); - } - } - } - } - private void addPublicShares(ShareeListAdapter adapter) { List publicShares = new ArrayList<>(); @@ -759,12 +729,17 @@ public void onQuickPermissionChanged(OCShare share, int permission) { } private void updateShare(OCShare share) { + if (note == null) { + Log_OC.e(TAG, "note is null, cannot update share"); + return; + } + executorService.submit(() -> { try { - final var updatedShares = repository.getShares(share.getId()); + final var updatedShares = repository.fetchSharesFromNote(note); runOnUiThread(() -> { - if (updatedShares != null && binding.sharesList.getAdapter() instanceof ShareeListAdapter adapter) { + if (binding.sharesList.getAdapter() instanceof ShareeListAdapter adapter) { OCShare updatedShare = null; for (int i=0;i { @@ -280,10 +268,6 @@ class NoteShareDetailActivity : canEditRadioButton.isChecked = true } - QuickPermissionType.FILE_REQUEST -> { - shareProcessPermissionFileDrop.isChecked = true - } - else -> Unit } } @@ -292,7 +276,7 @@ class NoteShareDetailActivity : private fun setMaxPermissionsIfDefaultPermissionExists() { if (repository.getCapabilities().defaultPermission != OCShare.NO_PERMISSION) { binding.canEditRadioButton.isChecked = true - permission = SharePermissionManager.getMaximumPermission(isFolder()) + permission = SharePermissionManager.getMaximumPermission() } } @@ -372,13 +356,8 @@ class NoteShareDetailActivity : shareProcessSetPasswordSwitch.visibility = View.VISIBLE if (share != null) { - if (SharePermissionManager.isFileRequest(share)) { - shareProcessHideDownloadCheckbox.visibility = View.GONE - } else { - shareProcessHideDownloadCheckbox.visibility = View.VISIBLE - shareProcessHideDownloadCheckbox.isChecked = - share?.isHideFileDownload == true - } + shareProcessHideDownloadCheckbox.visibility = View.VISIBLE + shareProcessHideDownloadCheckbox.isChecked = share?.isHideFileDownload == true } } } @@ -401,20 +380,6 @@ class NoteShareDetailActivity : private fun updateViewForFile() { binding.canEditRadioButton.text = getString(R.string.link_share_editing) - binding.shareProcessPermissionFileDrop.visibility = View.GONE - } - - private fun updateViewForFolder() { - binding.run { - canEditRadioButton.text = - getString(R.string.link_share_allow_upload_and_editing) - shareProcessPermissionFileDrop.visibility = View.VISIBLE - if (isSecureShare) { - shareProcessPermissionFileDrop.visibility = View.GONE - shareProcessAllowResharingCheckbox.visibility = View.GONE - shareProcessSetExpDateSwitch.visibility = View.GONE - } - } } /** @@ -473,11 +438,7 @@ class NoteShareDetailActivity : } R.id.can_edit_radio_button -> { - permission = SharePermissionManager.getMaximumPermission(isFolder()) - } - - R.id.share_process_permission_file_drop -> { - permission = OCShare.CREATE_PERMISSION_FLAG + permission = SharePermissionManager.getMaximumPermission() } } } @@ -604,7 +565,6 @@ class NoteShareDetailActivity : binding.shareProcessAllowResharingCheckbox.isChecked -> getReSharePermission() binding.canViewRadioButton.isChecked -> OCShare.READ_PERMISSION_FLAG binding.canEditRadioButton.isChecked -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - binding.shareProcessPermissionFileDrop.isChecked -> OCShare.CREATE_PERMISSION_FLAG else -> permission } @@ -627,9 +587,10 @@ class NoteShareDetailActivity : private suspend fun updateShare(noteText: String, label: String, password: String, sendEmail: Boolean) { val downloadPermission = !binding.shareProcessHideDownloadCheckbox.isChecked + val requestBody = repository.getUpdateShareRequest( downloadPermission = downloadPermission, - share = share, + share = share!!, noteText = noteText, label = label, password = password, @@ -673,7 +634,7 @@ class NoteShareDetailActivity : ) if (result.isSuccess()) { - repository.getSharesForNotesAndSaveShareEntities() + repository.fetchSharesForNotesAndSaveShareEntities() } handleResult(result.isSuccess()) @@ -707,9 +668,7 @@ class NoteShareDetailActivity : } // region Helpers - private fun isFolder(): Boolean = (share?.isFolder == true) - - private fun canSetFileRequest(): Boolean = isFolder() && shareType.isPublicOrMail() + private fun canSetFileRequest(): Boolean = shareType.isPublicOrMail() private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK) // endregion diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java index a3935442e..53a8a2818 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/ShareeListAdapter.java @@ -137,7 +137,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (holder instanceof LinkShareViewHolder publicShareViewHolder) { publicShareViewHolder.bind(share, listener, position); } else if (holder instanceof InternalShareViewHolder internalShareViewHolder) { - internalShareViewHolder.bind(share, listener); + internalShareViewHolder.bind(listener); } else if (holder instanceof NewLinkShareViewHolder newLinkShareViewHolder) { newLinkShareViewHolder.bind(listener); } else { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/InternalShareViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/InternalShareViewHolder.java index f81984d4c..0b2e7919c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/InternalShareViewHolder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/InternalShareViewHolder.java @@ -7,15 +7,11 @@ package it.niedermann.owncloud.notes.share.adapter.holder; import android.content.Context; -import android.graphics.PorterDuff; import android.view.View; import androidx.annotation.NonNull; -import androidx.core.content.res.ResourcesCompat; import androidx.recyclerview.widget.RecyclerView; -import com.owncloud.android.lib.resources.shares.OCShare; - import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.databinding.ItemInternalShareLinkBinding; import it.niedermann.owncloud.notes.share.listener.ShareeListAdapterListener; @@ -34,13 +30,8 @@ public InternalShareViewHolder(ItemInternalShareLinkBinding binding, Context con this.context = context; } - public void bind(OCShare share, ShareeListAdapterListener listener) { - if (share.isFolder()) { - binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_folder_text)); - } else { - binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_file_text)); - } - + public void bind(ShareeListAdapterListener listener) { + binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_file_text)); binding.copyInternalContainer.setOnClickListener(l -> listener.copyInternalLink()); } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt index 1244ae7c1..ad83c5543 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.kt @@ -17,7 +17,6 @@ import it.niedermann.owncloud.notes.branding.BrandedViewHolder import it.niedermann.owncloud.notes.branding.BrandingUtil import it.niedermann.owncloud.notes.databinding.ItemShareLinkShareBinding import it.niedermann.owncloud.notes.share.helper.SharePermissionManager -import it.niedermann.owncloud.notes.share.helper.SharePermissionManager.isSecureFileDrop import it.niedermann.owncloud.notes.share.listener.ShareeListAdapterListener import it.niedermann.owncloud.notes.share.model.QuickPermissionType import it.niedermann.owncloud.notes.util.remainingDownloadLimit @@ -31,11 +30,11 @@ class LinkShareViewHolder( } fun bind(publicShare: OCShare, listener: ShareeListAdapterListener, position: Int) { - val quickPermissionType = SharePermissionManager.getSelectedType(publicShare, false) + val quickPermissionType = SharePermissionManager.getSelectedType(publicShare) setName(binding, publicShare, position) setSubline(binding, publicShare) - setPermissionName(binding, publicShare, quickPermissionType) + setPermissionName(binding, quickPermissionType) setOnClickListeners(binding, listener, publicShare) configureCopyLink(binding, listener, publicShare) } @@ -107,7 +106,6 @@ class LinkShareViewHolder( private fun setPermissionName( binding: ItemShareLinkShareBinding?, - publicShare: OCShare?, quickPermissionType: QuickPermissionType ) { val context = binding?.root?.context @@ -118,7 +116,7 @@ class LinkShareViewHolder( val permissionName = quickPermissionType.getText(context) - if (TextUtils.isEmpty(permissionName) || (isSecureFileDrop(publicShare))) { + if (TextUtils.isEmpty(permissionName)) { binding.permissionName.visibility = View.GONE return } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java index cf5245ade..654462baf 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/ShareViewHolder.java @@ -102,7 +102,7 @@ public void bind(OCShare share, ShareeListAdapterListener listener) { accountUserName.equalsIgnoreCase(share.getUserId())) { binding.overflowMenu.setVisibility(View.VISIBLE); - QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(share, false); + QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(share); setPermissionName(quickPermissionType.getText(context)); // bind listener to edit privileges diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java index fcdf7daad..b9e9418db 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java @@ -19,7 +19,6 @@ import it.niedermann.owncloud.notes.branding.BrandedBottomSheetDialog; import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.ItemNoteShareActionBinding; -import it.niedermann.owncloud.notes.share.helper.SharePermissionManager; import it.niedermann.owncloud.notes.share.listener.NoteShareItemAction; public class NoteShareActivityShareItemActionBottomSheetDialog extends BrandedBottomSheetDialog { @@ -62,11 +61,6 @@ private void updateUI() { binding.menuShareAddAnotherLink.setVisibility(View.GONE); binding.menuShareSendLink.setVisibility(View.GONE); } - - if (SharePermissionManager.INSTANCE.isSecureFileDrop(ocShare)) { - binding.menuShareAdvancedPermissions.setVisibility(View.GONE); - binding.menuShareAddAnotherLink.setVisibility(View.GONE); - } } private void setupClickListener() { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java index 0f651d005..a0dae07da 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java @@ -25,7 +25,6 @@ import it.niedermann.owncloud.notes.share.adapter.QuickSharingPermissionsAdapter; import it.niedermann.owncloud.notes.share.helper.SharePermissionManager; import it.niedermann.owncloud.notes.share.model.QuickPermission; -import it.niedermann.owncloud.notes.util.OCShareExtensionsKt; /** * File Details Quick Sharing permissions options {@link android.app.Dialog} styled as a bottom sheet for main actions. @@ -94,7 +93,7 @@ public void onDismissSheet() { */ private void handlePermissionChanged(List quickPermissionList, int position) { final var type = quickPermissionList.get(position).getType(); - int permissionFlag = type.getPermissionFlag(ocShare.isFolder()); + int permissionFlag = type.getPermissionFlag(false); actions.onQuickPermissionChanged(ocShare, permissionFlag); dismiss(); } @@ -103,9 +102,8 @@ private void handlePermissionChanged(List quickPermissionList, * Prepare the list of permissions needs to be displayed on recyclerview */ private List getQuickPermissionList() { - final var selectedType = SharePermissionManager.INSTANCE.getSelectedType(ocShare, false); - final var hasFileRequestPermission = OCShareExtensionsKt.hasFileRequestPermission(ocShare); - return selectedType.getAvailablePermissions(hasFileRequestPermission); + final var selectedType = SharePermissionManager.INSTANCE.getSelectedType(ocShare); + return selectedType.getAvailablePermissions(false); } @Override diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt index 5a61c24f9..84e4ce473 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt @@ -21,7 +21,7 @@ object SharePermissionManager { return false } - return hasPermission(share.permissions, getMaximumPermission(share.isFolder)) + return hasPermission(share.permissions, getMaximumPermission()) } fun isViewOnly(share: OCShare?): Boolean { @@ -36,27 +36,6 @@ object SharePermissionManager { ) } - @Suppress("ReturnCount") - fun isFileRequest(share: OCShare?): Boolean { - if (share == null) { - return false - } - - if (!share.isFolder) { - return false - } - - 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 @@ -65,22 +44,14 @@ object SharePermissionManager { return (share.permissions and OCShare.SHARE_PERMISSION_FLAG) > 0 } - fun getSelectedType(share: OCShare?, encrypted: Boolean): QuickPermissionType = if (canEdit(share)) { + fun getSelectedType(share: OCShare?): QuickPermissionType = if (canEdit(share)) { QuickPermissionType.CAN_EDIT - } else if (encrypted && isSecureFileDrop(share)) { - QuickPermissionType.SECURE_FILE_DROP } else if (isViewOnly(share)) { QuickPermissionType.VIEW_ONLY - } else if (isFileRequest(share)) { - QuickPermissionType.FILE_REQUEST } else { QuickPermissionType.NONE } - fun getMaximumPermission(isFolder: Boolean): Int = if (isFolder) { - OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER - } else { - OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - } + fun getMaximumPermission(): Int = OCShare.MAXIMUM_PERMISSIONS_FOR_FILE // endregion } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index d1f7854ca..1f526a5d0 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -68,11 +68,6 @@ class ShareRepository(private val applicationContext: Context, private val accou } } - fun getShareEntitiesForSpecificNote(note: Note): List { - val path = getNotePath(note) - return notesRepository.getShareEntities(path) - } - private fun getExpirationDate(chosenExpDateInMills: Long): String? { if (chosenExpDateInMills == -1L) { return null @@ -84,13 +79,13 @@ class ShareRepository(private val applicationContext: Context, private val accou fun getCapabilities(): Capabilities = notesRepository.capabilities // region API calls - fun getSharesForNotesAndSaveShareEntities() { + fun fetchSharesForNotesAndSaveShareEntities() { val notesPathResponseResult = getNotesPathResponseResult() ?: return val notesPath = notesPathResponseResult.notesPath val remotePath = "/$notesPath" val shareAPI = apiProvider.getShareAPI(applicationContext, account) - val call = shareAPI.getSharesForSpecificNote(remotePath) + val call = shareAPI.fetchSharesForSpecificNote(remotePath) val entities = arrayListOf() try { @@ -111,6 +106,7 @@ class ShareRepository(private val applicationContext: Context, private val accou val displayNameOwner = map?.get("displayname_owner") as? String val url = map?.get("url") as? String val expirationDateString = map?.get("expiration") as? String + val permissions = map?.get("permissions") as? Double id?.toInt()?.let { val entity = ShareEntity( @@ -125,7 +121,8 @@ class ShareRepository(private val applicationContext: Context, private val accou uid_owner = uidOwner, displayname_owner = displayNameOwner, url = url, - expiration_date = expirationDateString?.toExpirationDateLong() + expiration_date = expirationDateString?.toExpirationDateLong(), + permissions = permissions ) entities.add(entity) @@ -153,7 +150,7 @@ class ShareRepository(private val applicationContext: Context, private val accou */ fun getSharees(searchString: String, page: Int, perPage: Int): ArrayList { val shareAPI = apiProvider.getShareAPI(applicationContext, account) - val call = shareAPI.getSharees( + val call = shareAPI.fetchSharees( search = searchString, page = page.toString(), perPage = perPage.toString() @@ -204,7 +201,7 @@ class ShareRepository(private val applicationContext: Context, private val accou fun getUpdateShareRequest( downloadPermission: Boolean, - share: OCShare?, + share: OCShare, noteText: String, label: String, password: String, @@ -234,7 +231,7 @@ class ShareRepository(private val applicationContext: Context, private val accou val attributes = gson.toJson(shareAttributes) return UpdateShareRequest( - share_id = share!!.id.toInt(), + share_id = share.id.toInt(), permissions = if (permission == -1) null else permission, password = password, publicUpload = "false", @@ -246,33 +243,6 @@ class ShareRepository(private val applicationContext: Context, private val accou ) } - /** - * Fetches all shares for the given file or folder identified by its remote ID. - * - * @param remoteId The remote file ID on the server for which to retrieve shares. - * @return A list of [OCShare] objects if the request is successful, or `null` if the request fails or an exception - * occurs. - */ - fun getShares(remoteId: Long): List? { - val shareAPI = apiProvider.getShareAPI(applicationContext, account) - val call = shareAPI.getShares(remoteId) - val response = call.execute() - - return try { - if (response.isSuccessful) { - val result = - response.body()?.ocs?.data ?: throw RuntimeException("No shares available") - result.toOCShareList() - } else { - Log_OC.d(tag, "Failed to getShares: ${response.errorBody()?.string()}") - null - } - } catch (e: Exception) { - Log_OC.d(tag, "Exception while getShares: $e") - null - } - } - fun sendEmail(shareId: Long, requestBody: SharePasswordRequest): Boolean { val shareAPI = apiProvider.getShareAPI(applicationContext, account) val call = shareAPI.sendEmail(shareId, requestBody) @@ -291,25 +261,31 @@ class ShareRepository(private val applicationContext: Context, private val accou } } - fun getShareFromNote(note: Note): List? { - val shareAPI = apiProvider.getShareAPI(applicationContext, account) - val path = getNotePath(note) ?: return null - val call = shareAPI.getShareFromNote(path) + fun fetchSharesFromNote(note: Note): List { + val sharesWithMe = fetchShares(note, sharedWithMe = true) + val sharesWithOthers = fetchShares(note, sharedWithMe = false) + return sharesWithOthers + sharesWithMe + } + + private fun fetchShares(note: Note, sharedWithMe: Boolean): List { + val api = apiProvider.getShareAPI(applicationContext, account) + val path = getNotePath(note) ?: return emptyList() + val call = api.fetchSharesFromNote(path, sharedWithMe) val response = call.execute() return try { if (response.isSuccessful) { val body = response.body() Log_OC.d(tag, "Response successful: $body") - body?.ocs?.data?.toOCShareList() + body?.ocs?.data?.toOCShareList() ?: emptyList() } else { val errorBody = response.errorBody()?.string() Log_OC.d(tag, "Response failed: $errorBody") - null + emptyList() } } catch (e: Exception) { Log_OC.d(tag, "Exception while getting share from note: ", e) - null + emptyList() } } @@ -325,6 +301,9 @@ class ShareRepository(private val applicationContext: Context, private val accou updateNote(note) } + // delete previously stored shared + notesRepository.deleteShareById(share.id.toInt()) + Log_OC.d(tag, "Share removed successfully.") } else { Log_OC.d(tag, "Failed to remove share: ${response.errorBody()?.string()}") diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt b/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt index b292c2c49..f67b19624 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/OCShareExtensions.kt @@ -9,8 +9,6 @@ package it.niedermann.owncloud.notes.util import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType -fun OCShare.hasFileRequestPermission(): Boolean = (isFolder && shareType?.isPublicOrMail() == true) - fun ShareType.isPublicOrMail(): Boolean = (this == ShareType.PUBLIC_LINK || this == ShareType.EMAIL) fun OCShare?.remainingDownloadLimit(): Int? { diff --git a/app/src/main/res/layout/activity_note_share_detail.xml b/app/src/main/res/layout/activity_note_share_detail.xml index 58e81049b..12aa37268 100644 --- a/app/src/main/res/layout/activity_note_share_detail.xml +++ b/app/src/main/res/layout/activity_note_share_detail.xml @@ -78,13 +78,6 @@ android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/link_share_allow_upload_and_editing" /> - - Date: Tue, 10 Feb 2026 15:27:50 +0100 Subject: [PATCH 07/24] remove unexisting permissions Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 30 +------------------ .../res/layout/activity_note_share_detail.xml | 18 ----------- 2 files changed, 1 insertion(+), 47 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 1e00046e5..c6b460a39 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -16,7 +16,6 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.android.sso.helper.SingleAccountHelper 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.lib.resources.shares.ShareType import it.niedermann.owncloud.notes.R import it.niedermann.owncloud.notes.branding.BrandedActivity @@ -141,10 +140,6 @@ class NoteShareDetailActivity : themeRadioButton(canEditRadioButton) colorTextView(shareProcessEditShareLink) - colorTextView(shareProcessAdvancePermissionTitle) - - themeCheckbox(shareProcessAllowResharingCheckbox) - colorTextView(title, ColorRole.ON_SURFACE) } @@ -192,10 +187,6 @@ class NoteShareDetailActivity : updateView() - if (isSecureShare) { - binding.shareProcessAdvancePermissionTitle.visibility = View.GONE - } - // show or hide expiry date if (isExpDateShown && !isSecureShare) { binding.shareProcessSetExpDateSwitch.visibility = View.VISIBLE @@ -329,20 +320,7 @@ class NoteShareDetailActivity : shareProcessChangeNameSwitch.visibility = View.GONE shareProcessChangeNameContainer.visibility = View.GONE shareProcessHideDownloadCheckbox.visibility = View.GONE - if (isSecureShare) { - shareProcessAllowResharingCheckbox.visibility = View.GONE - } else { - shareProcessAllowResharingCheckbox.visibility = View.VISIBLE - } shareProcessSetPasswordSwitch.visibility = View.GONE - - if (share != null) { - if (!isReShareShown) { - shareProcessAllowResharingCheckbox.visibility = View.GONE - } - shareProcessAllowResharingCheckbox.isChecked = - SharePermissionManager.canReshare(share) - } } } @@ -352,7 +330,6 @@ class NoteShareDetailActivity : private fun updateViewForExternalAndLinkShare() { binding.run { shareProcessHideDownloadCheckbox.visibility = View.VISIBLE - shareProcessAllowResharingCheckbox.visibility = View.GONE shareProcessSetPasswordSwitch.visibility = View.VISIBLE if (share != null) { @@ -499,10 +476,6 @@ class NoteShareDetailActivity : } } - private fun getReSharePermission(): Int = SharePermissionsBuilder().apply { - setSharePermission(true) - }.build() - /** * method to validate the step 1 screen information */ @@ -562,9 +535,8 @@ class NoteShareDetailActivity : * get the permissions on the basis of selection */ private fun getSelectedPermission() = when { - binding.shareProcessAllowResharingCheckbox.isChecked -> getReSharePermission() binding.canViewRadioButton.isChecked -> OCShare.READ_PERMISSION_FLAG - binding.canEditRadioButton.isChecked -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE + binding.canEditRadioButton.isChecked -> SharePermissionManager.getMaximumPermission() else -> permission } diff --git a/app/src/main/res/layout/activity_note_share_detail.xml b/app/src/main/res/layout/activity_note_share_detail.xml index 12aa37268..e4d501bf5 100644 --- a/app/src/main/res/layout/activity_note_share_detail.xml +++ b/app/src/main/res/layout/activity_note_share_detail.xml @@ -80,24 +80,6 @@ - - - - Date: Tue, 10 Feb 2026 15:28:07 +0100 Subject: [PATCH 08/24] remove unexisting permissions Signed-off-by: alperozturk96 --- .../notes/share/helper/SharePermissionManager.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt index 84e4ce473..9f66bada1 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/helper/SharePermissionManager.kt @@ -11,11 +11,9 @@ import it.niedermann.owncloud.notes.share.model.QuickPermissionType object SharePermissionManager { - // region Permission check fun hasPermission(permission: Int, permissionFlag: Int): Boolean = permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag - // region Helper Methods fun canEdit(share: OCShare?): Boolean { if (share == null) { return false @@ -36,14 +34,6 @@ object SharePermissionManager { ) } - fun canReshare(share: OCShare?): Boolean { - if (share == null) { - return false - } - - return (share.permissions and OCShare.SHARE_PERMISSION_FLAG) > 0 - } - fun getSelectedType(share: OCShare?): QuickPermissionType = if (canEdit(share)) { QuickPermissionType.CAN_EDIT } else if (isViewOnly(share)) { @@ -53,5 +43,4 @@ object SharePermissionManager { } fun getMaximumPermission(): Int = OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - // endregion } From 64a332b8064bf14f6dd3cdf2b354338efcf1d1a9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 15:28:39 +0100 Subject: [PATCH 09/24] remove unexisting permissions Signed-off-by: alperozturk96 --- .../owncloud/notes/share/NoteShareDetailActivity.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index c6b460a39..6035418a3 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -90,7 +90,7 @@ class NoteShareDetailActivity : binding = ActivityNoteShareDetailBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.toolbar) - binding.toolbar.setNavigationOnClickListener({ v -> backPressed() }) + binding.toolbar.setNavigationOnClickListener { backPressed() } val arguments = intent.extras arguments?.let { @@ -639,9 +639,5 @@ class NoteShareDetailActivity : binding.shareProcessSetExpDateSwitch.isChecked = false } - // region Helpers - private fun canSetFileRequest(): Boolean = shareType.isPublicOrMail() - private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK) - // endregion } From e0a3db4c97346b4d862a5a18ee4d07f4068b9e03 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 15:28:47 +0100 Subject: [PATCH 10/24] remove unexisting permissions Signed-off-by: alperozturk96 --- .../niedermann/owncloud/notes/share/NoteShareDetailActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 6035418a3..14bc4be1e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -32,7 +32,6 @@ import it.niedermann.owncloud.notes.shared.util.DisplayUtils import it.niedermann.owncloud.notes.shared.util.clipboard.ClipboardUtil import it.niedermann.owncloud.notes.shared.util.extensions.getParcelableArgument import it.niedermann.owncloud.notes.shared.util.extensions.getSerializableArgument -import it.niedermann.owncloud.notes.util.isPublicOrMail import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext From 669cc8b7ace7a1e98c01969a2ef13421da58eee5 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 15:47:32 +0100 Subject: [PATCH 11/24] remove unexisting permissions Signed-off-by: alperozturk96 --- .../notes/share/NoteShareActivity.java | 10 ++--- .../notes/share/NoteShareDetailActivity.kt | 8 ++-- .../notes/share/model/UpdateShareRequest.kt | 43 +++++++----------- .../notes/share/repository/ShareRepository.kt | 44 +++---------------- 4 files changed, 29 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index 3ffca123d..ab0b1c88c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -857,14 +857,12 @@ public void setPasswordToShare(@NotNull OCShare share, @Nullable String password executorService.submit(() -> { { final var requestBody = repository.getUpdateShareRequest( - false, - share, - "", - "", + share.getNote(), + share.getLabel(), password, - false, -1, - share.getPermissions() + share.getPermissions(), + share.isHideFileDownload() ); final var result = repository.updateShare(share.getId(), requestBody); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 14bc4be1e..d7ec122ac 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -557,17 +557,15 @@ class NoteShareDetailActivity : } private suspend fun updateShare(noteText: String, label: String, password: String, sendEmail: Boolean) { - val downloadPermission = !binding.shareProcessHideDownloadCheckbox.isChecked + val hideDownload = binding.shareProcessHideDownloadCheckbox.isChecked val requestBody = repository.getUpdateShareRequest( - downloadPermission = downloadPermission, - share = share!!, noteText = noteText, label = label, password = password, - sendEmail = sendEmail, chosenExpDateInMills = chosenExpDateInMills, - permission = permission + permission = permission, + hideDownload = hideDownload ) val updateShareResult = repository.updateShare(share!!.id, requestBody) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt index ac3af6d29..c94f3d1a2 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt @@ -7,47 +7,34 @@ package it.niedermann.owncloud.notes.share.model import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName data class UpdateShareRequest( @Expose - val share_id: Int, + @SerializedName("permissions") + val permissions: Int? = null, @Expose - val permissions: Int?, + @SerializedName("password") + val password: String? = null, @Expose - val password: String, + @SerializedName("note") + val note: String? = null, @Expose - val publicUpload: String, + @SerializedName("label") + val label: String? = null, @Expose - val expireDate: String?, + @SerializedName("expireDate") + val expireDate: String? = null, @Expose - val label: String?, + @SerializedName("hideDownload") + val hideDownload: String? = null, @Expose - val note: String, - - /** - * Array of ShareAttributes data class in JSON format - */ - @Expose - val attributes: String?, - - @Expose - val sendMail: String -) - -data class ShareAttributesV2( - var scope: String, - var key: String, - var value: Boolean -) - -data class ShareAttributesV1( - var scope: String, - var key: String, - var enabled: Boolean + @SerializedName("attributes") + val attributes: String? = null ) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index 1f526a5d0..781067bfb 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -21,8 +21,6 @@ import it.niedermann.owncloud.notes.persistence.entity.Note import it.niedermann.owncloud.notes.persistence.entity.ShareEntity import it.niedermann.owncloud.notes.share.model.CreateShareRequest import it.niedermann.owncloud.notes.share.model.CreateShareResponse -import it.niedermann.owncloud.notes.share.model.ShareAttributesV1 -import it.niedermann.owncloud.notes.share.model.ShareAttributesV2 import it.niedermann.owncloud.notes.share.model.SharePasswordRequest import it.niedermann.owncloud.notes.share.model.UpdateSharePermissionRequest import it.niedermann.owncloud.notes.share.model.UpdateShareRequest @@ -200,46 +198,21 @@ class ShareRepository(private val applicationContext: Context, private val accou } fun getUpdateShareRequest( - downloadPermission: Boolean, - share: OCShare, - noteText: String, - label: String, + noteText: String?, + label: String?, password: String, - sendEmail: Boolean, chosenExpDateInMills: Long, - permission: Int + permission: Int, + hideDownload: Boolean ): UpdateShareRequest { - val capabilities = getCapabilities() - val shouldUseShareAttributesV2 = (capabilities.nextcloudMajorVersion?.toInt() ?: 0) >= 30 - - val shareAttributes = arrayOf( - if (shouldUseShareAttributesV2) { - ShareAttributesV2( - scope = "permissions", - key = "download", - value = downloadPermission - ) - } else { - ShareAttributesV1( - scope = "permissions", - key = "download", - enabled = downloadPermission - ) - } - ) - - val attributes = gson.toJson(shareAttributes) - return UpdateShareRequest( - share_id = share.id.toInt(), permissions = if (permission == -1) null else permission, password = password, - publicUpload = "false", expireDate = getExpirationDate(chosenExpDateInMills), label = label, note = noteText, - attributes = attributes, - sendMail = sendEmail.toString() + attributes = "[]", + hideDownload = hideDownload.toString() ) } @@ -386,10 +359,7 @@ class ShareRepository(private val applicationContext: Context, private val accou message = applicationContext.getString(R.string.note_share_created) ) } else { - val errorMessage = response.getErrorMessage() - if (errorMessage == null) { - return ApiResult.Error(message = defaultErrorMessage) - } + val errorMessage = response.getErrorMessage() ?: return ApiResult.Error(message = defaultErrorMessage) Log_OC.d(tag, "Response failed: $errorMessage") ApiResult.Error(message = errorMessage) } From e3358c534757e2789ebe833c67efcd0f596dc7ef Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 15:55:53 +0100 Subject: [PATCH 12/24] fix update share Signed-off-by: alperozturk96 --- .../notes/share/NoteShareActivity.java | 17 +++++++----- .../notes/share/NoteShareDetailActivity.kt | 16 ++++++----- .../notes/share/repository/ShareRepository.kt | 27 ------------------- .../owncloud/notes/util/DateUtil.kt | 20 ++++++++++++++ 4 files changed, 40 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/util/DateUtil.kt diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index ab0b1c88c..47a5a8ba4 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -76,6 +76,7 @@ import it.niedermann.owncloud.notes.share.listener.ShareeListAdapterListener; import it.niedermann.owncloud.notes.share.model.CreateShareResponse; import it.niedermann.owncloud.notes.share.model.CreateShareResponseExtensionsKt; +import it.niedermann.owncloud.notes.share.model.UpdateShareRequest; import it.niedermann.owncloud.notes.share.model.UsersAndGroupsSearchConfig; import it.niedermann.owncloud.notes.share.repository.ShareRepository; import it.niedermann.owncloud.notes.shared.model.Capabilities; @@ -84,6 +85,7 @@ import it.niedermann.owncloud.notes.shared.util.ShareUtil; import it.niedermann.owncloud.notes.shared.util.clipboard.ClipboardUtil; import it.niedermann.owncloud.notes.shared.util.extensions.BundleExtensionsKt; +import it.niedermann.owncloud.notes.util.DateUtil; public class NoteShareActivity extends BrandedActivity implements ShareeListAdapterListener, NoteShareItemAction, QuickSharingPermissionsBottomSheetDialog.QuickPermissionSharingBottomSheetActions, SharePasswordDialogFragment.SharePasswordDialogListener { @@ -856,13 +858,14 @@ public void setPasswordToShare(@NotNull OCShare share, @Nullable String password executorService.submit(() -> { { - final var requestBody = repository.getUpdateShareRequest( - share.getNote(), - share.getLabel(), - password, - -1, - share.getPermissions(), - share.isHideFileDownload() + final var requestBody = new UpdateShareRequest( + share.getPermissions(), + password, + share.getNote(), + share.getLabel(), + DateUtil.INSTANCE.getExpirationDate(share.getExpirationDate()), + "[]", + Boolean.toString(share.isHideFileDownload()) ); final var result = repository.updateShare(share.getId(), requestBody); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index d7ec122ac..cd091c342 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -27,11 +27,14 @@ import it.niedermann.owncloud.notes.share.dialog.ExpirationDatePickerDialogFragm import it.niedermann.owncloud.notes.share.helper.SharePermissionManager import it.niedermann.owncloud.notes.share.model.QuickPermissionType import it.niedermann.owncloud.notes.share.model.SharePasswordRequest +import it.niedermann.owncloud.notes.share.model.UpdateShareRequest import it.niedermann.owncloud.notes.share.repository.ShareRepository import it.niedermann.owncloud.notes.shared.util.DisplayUtils import it.niedermann.owncloud.notes.shared.util.clipboard.ClipboardUtil import it.niedermann.owncloud.notes.shared.util.extensions.getParcelableArgument import it.niedermann.owncloud.notes.shared.util.extensions.getSerializableArgument +import it.niedermann.owncloud.notes.shared.util.extensions.toExpirationDateString +import it.niedermann.owncloud.notes.util.DateUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -559,13 +562,14 @@ class NoteShareDetailActivity : private suspend fun updateShare(noteText: String, label: String, password: String, sendEmail: Boolean) { val hideDownload = binding.shareProcessHideDownloadCheckbox.isChecked - val requestBody = repository.getUpdateShareRequest( - noteText = noteText, - label = label, + val requestBody = UpdateShareRequest( + permissions = if (permission == -1) null else permission, password = password, - chosenExpDateInMills = chosenExpDateInMills, - permission = permission, - hideDownload = hideDownload + expireDate = DateUtil.getExpirationDate(chosenExpDateInMills), + label = label, + note = noteText, + attributes = "[]", + hideDownload = hideDownload.toString() ) val updateShareResult = repository.updateShare(share!!.id, requestBody) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index 781067bfb..aad7d3509 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -66,14 +66,6 @@ class ShareRepository(private val applicationContext: Context, private val accou } } - private fun getExpirationDate(chosenExpDateInMills: Long): String? { - if (chosenExpDateInMills == -1L) { - return null - } - - return Date(chosenExpDateInMills).toExpirationDateString() - } - fun getCapabilities(): Capabilities = notesRepository.capabilities // region API calls @@ -197,25 +189,6 @@ class ShareRepository(private val applicationContext: Context, private val accou } } - fun getUpdateShareRequest( - noteText: String?, - label: String?, - password: String, - chosenExpDateInMills: Long, - permission: Int, - hideDownload: Boolean - ): UpdateShareRequest { - return UpdateShareRequest( - permissions = if (permission == -1) null else permission, - password = password, - expireDate = getExpirationDate(chosenExpDateInMills), - label = label, - note = noteText, - attributes = "[]", - hideDownload = hideDownload.toString() - ) - } - fun sendEmail(shareId: Long, requestBody: SharePasswordRequest): Boolean { val shareAPI = apiProvider.getShareAPI(applicationContext, account) val call = shareAPI.sendEmail(shareId, requestBody) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/DateUtil.kt b/app/src/main/java/it/niedermann/owncloud/notes/util/DateUtil.kt new file mode 100644 index 000000000..ebc52538b --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/DateUtil.kt @@ -0,0 +1,20 @@ +/* + * Nextcloud Notes - Android Client + * + * SPDX-FileCopyrightText: 2015-2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package it.niedermann.owncloud.notes.util + +import it.niedermann.owncloud.notes.shared.util.extensions.toExpirationDateString +import java.util.Date + +object DateUtil { + fun getExpirationDate(chosenExpDateInMills: Long): String? { + if (chosenExpDateInMills == -1L) { + return null + } + + return Date(chosenExpDateInMills).toExpirationDateString() + } +} From 2d9095b078300f2815659fce233c17e675ee039d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 16:08:27 +0100 Subject: [PATCH 13/24] handle set password Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 15 +++++++++++---- .../notes/share/repository/ShareRepository.kt | 5 +++-- app/src/main/res/values/strings.xml | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index cd091c342..0117297ca 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -21,6 +21,7 @@ import it.niedermann.owncloud.notes.R import it.niedermann.owncloud.notes.branding.BrandedActivity import it.niedermann.owncloud.notes.branding.BrandingUtil import it.niedermann.owncloud.notes.databinding.ActivityNoteShareDetailBinding +import it.niedermann.owncloud.notes.persistence.ApiResult import it.niedermann.owncloud.notes.persistence.entity.Note import it.niedermann.owncloud.notes.persistence.isSuccess import it.niedermann.owncloud.notes.share.dialog.ExpirationDatePickerDialogFragment @@ -578,10 +579,15 @@ class NoteShareDetailActivity : val sendEmailResult = repository.sendEmail(share!!.id, SharePasswordRequest(password)) handleResult(sendEmailResult) } else { - handleResult(updateShareResult.isSuccess()) + val errorResult = updateShareResult as ApiResult.Error + var errorMessage: String? = null + if (errorResult.message.contains("password")) { + errorMessage = getString(R.string.note_share_detail_activity_password_error_message) + } + handleResult(false, errorMessage = errorMessage) } - if (!sendEmail) { + if (updateShareResult.isSuccess() && !sendEmail) { withContext(Dispatchers.Main) { if (!TextUtils.isEmpty(share?.shareLink)) { ClipboardUtil.copyToClipboard(this@NoteShareDetailActivity, share?.shareLink) @@ -613,16 +619,17 @@ class NoteShareDetailActivity : handleResult(result.isSuccess()) } - private suspend fun handleResult(success: Boolean) { + private suspend fun handleResult(success: Boolean, errorMessage: String? = null) { withContext(Dispatchers.Main) { if (success) { val resultIntent = Intent() setResult(RESULT_OK, resultIntent) finish() } else { + val message = errorMessage ?: getString(R.string.note_share_detail_activity_create_share_error) DisplayUtils.showSnackMessage( this@NoteShareDetailActivity, - getString(R.string.note_share_detail_activity_create_share_error) + message ) } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index aad7d3509..c93ff25e7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -280,8 +280,9 @@ class ShareRepository(private val applicationContext: Context, private val accou message = applicationContext.getString(R.string.note_share_created) ) } else { - Log_OC.d(tag, "Failed to update share: ${response.errorBody()?.string()}") - ApiResult.Error(message = response.getErrorMessage() ?: "") + val message = response.errorBody()?.string() + Log_OC.d(tag, "Failed to update share: $message") + ApiResult.Error(message = message ?: "") } } catch (e: Exception) { Log_OC.d(tag, "Exception while updating share", e) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e49b1dcb1..b103732dd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -69,7 +69,7 @@ - Advanced Settings + This password looks a bit weak. For better security, try using a longer password with a mix of letters, numbers, and symbols. Hide download Note to recipient Note From 72bbad5405994e15fda75a749736610d80a7f4c6 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 16:11:40 +0100 Subject: [PATCH 14/24] remove unexisting share types Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 1 - ...uickSharingPermissionsBottomSheetDialog.java | 4 ++-- .../notes/share/model/QuickPermissionType.kt | 17 ++++++----------- .../notes/share/repository/ShareRepository.kt | 2 -- app/src/main/res/drawable/ic_file_request.xml | 16 ---------------- 5 files changed, 8 insertions(+), 32 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_file_request.xml diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 0117297ca..10006e39f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -34,7 +34,6 @@ import it.niedermann.owncloud.notes.shared.util.DisplayUtils import it.niedermann.owncloud.notes.shared.util.clipboard.ClipboardUtil import it.niedermann.owncloud.notes.shared.util.extensions.getParcelableArgument import it.niedermann.owncloud.notes.shared.util.extensions.getSerializableArgument -import it.niedermann.owncloud.notes.shared.util.extensions.toExpirationDateString import it.niedermann.owncloud.notes.util.DateUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java index a0dae07da..665e35e5d 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/QuickSharingPermissionsBottomSheetDialog.java @@ -93,7 +93,7 @@ public void onDismissSheet() { */ private void handlePermissionChanged(List quickPermissionList, int position) { final var type = quickPermissionList.get(position).getType(); - int permissionFlag = type.getPermissionFlag(false); + int permissionFlag = type.getPermissionFlag(); actions.onQuickPermissionChanged(ocShare, permissionFlag); dismiss(); } @@ -103,7 +103,7 @@ private void handlePermissionChanged(List quickPermissionList, */ private List getQuickPermissionList() { final var selectedType = SharePermissionManager.INSTANCE.getSelectedType(ocShare); - return selectedType.getAvailablePermissions(false); + return selectedType.getAvailablePermissions(); } @Override diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt index 376a15256..7706e0398 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt @@ -15,27 +15,22 @@ import it.niedermann.owncloud.notes.R enum class QuickPermissionType(val iconId: Int, val textId: Int) { NONE(R.drawable.ic_unknown, R.string.share_permission_unknown), 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.share_permission_file_request), - SECURE_FILE_DROP(R.drawable.ic_file_request, R.string.share_permission_secure_file_drop); + CAN_EDIT(R.drawable.ic_edit, R.string.share_permission_can_edit); fun getText(context: Context): String = context.getString(textId) fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, iconId) - fun getPermissionFlag(isFolder: Boolean): Int = when (this) { + fun getPermissionFlag(): Int = when (this) { NONE -> OCShare.NO_PERMISSION VIEW_ONLY -> OCShare.READ_PERMISSION_FLAG - CAN_EDIT -> if (isFolder) OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER else OCShare.MAXIMUM_PERMISSIONS_FOR_FILE - FILE_REQUEST -> OCShare.CREATE_PERMISSION_FLAG - SECURE_FILE_DROP -> OCShare.CREATE_PERMISSION_FLAG + OCShare.READ_PERMISSION_FLAG + CAN_EDIT -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE } - fun getAvailablePermissions(hasFileRequestPermission: Boolean): List { - val permissions = listOf(VIEW_ONLY, CAN_EDIT, FILE_REQUEST) - val result = if (hasFileRequestPermission) permissions else permissions.filter { it != FILE_REQUEST } + fun getAvailablePermissions(): List { + val permissions = listOf(VIEW_ONLY, CAN_EDIT) - return result.map { type -> + return permissions.map { type -> QuickPermission( type = type, isSelected = (type == this) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index c93ff25e7..0f33ba7f0 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -32,9 +32,7 @@ import it.niedermann.owncloud.notes.shared.model.OcsResponse import it.niedermann.owncloud.notes.shared.util.StringConstants import it.niedermann.owncloud.notes.shared.util.extensions.getErrorMessage import it.niedermann.owncloud.notes.shared.util.extensions.toExpirationDateLong -import it.niedermann.owncloud.notes.shared.util.extensions.toExpirationDateString import org.json.JSONObject -import java.util.Date class ShareRepository(private val applicationContext: Context, private val account: SingleSignOnAccount) { diff --git a/app/src/main/res/drawable/ic_file_request.xml b/app/src/main/res/drawable/ic_file_request.xml deleted file mode 100644 index 58194805b..000000000 --- a/app/src/main/res/drawable/ic_file_request.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - From 102c95da725419f7b5228820819151f5e2598410 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Feb 2026 16:11:56 +0100 Subject: [PATCH 15/24] remove unexisting share types Signed-off-by: alperozturk96 --- .../owncloud/notes/share/model/QuickPermissionType.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt index 7706e0398..d96c3b4ce 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/QuickPermissionType.kt @@ -7,8 +7,6 @@ package it.niedermann.owncloud.notes.share.model import android.content.Context -import android.graphics.drawable.Drawable -import androidx.core.content.ContextCompat import com.owncloud.android.lib.resources.shares.OCShare import it.niedermann.owncloud.notes.R @@ -19,8 +17,6 @@ enum class QuickPermissionType(val iconId: Int, val textId: Int) { fun getText(context: Context): String = context.getString(textId) - fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, iconId) - fun getPermissionFlag(): Int = when (this) { NONE -> OCShare.NO_PERMISSION VIEW_ONLY -> OCShare.READ_PERMISSION_FLAG From a5d018bfa1ce5ceba713ad37eda10b06b39b5b9b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 11 Feb 2026 15:09:35 +0100 Subject: [PATCH 16/24] fix send email Signed-off-by: alperozturk96 --- .../notes/persistence/sync/ShareAPI.kt | 3 - .../notes/share/NoteShareActivity.java | 7 ++- .../notes/share/NoteShareDetailActivity.kt | 62 +++++++++++-------- ...ivityShareItemActionBottomSheetDialog.java | 4 +- .../notes/share/repository/ShareRepository.kt | 19 ------ 5 files changed, 43 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt index 34d20fd86..c6a15e80e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ShareAPI.kt @@ -46,9 +46,6 @@ interface ShareAPI { @POST("shares?format=json") fun addShare(@Body request: CreateShareRequest): Call> - @POST("shares/{shareId}/send-email?format=json") - fun sendEmail(@Path("shareId") shareId: Long, @Body password: SharePasswordRequest?): Call - @PUT("shares/{shareId}?format=json") fun updateShare(@Path("shareId") shareId: Long, @Body request: UpdateShareRequest): Call> diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index 47a5a8ba4..b3e77b43d 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -644,13 +644,13 @@ public void search(String query) { @Override public void advancedPermissions(OCShare share) { - modifyExistingShare(share, NoteShareDetailActivity.SCREEN_TYPE_PERMISSION); + modifyExistingShare(share, NoteShareDetailActivity.SCREEN_TYPE_PERMISSION, false); } @Override public void sendNewEmail(OCShare share) { - modifyExistingShare(share, NoteShareDetailActivity.SCREEN_TYPE_NOTE); + modifyExistingShare(share, NoteShareDetailActivity.SCREEN_TYPE_NOTE, true); } @Override @@ -683,13 +683,14 @@ public void addAnotherLink(OCShare share) { createPublicShareLink(); } - private void modifyExistingShare(OCShare share, int screenTypePermission) { + private void modifyExistingShare(OCShare share, int screenTypePermission, boolean sendEmail) { Bundle bundle = new Bundle(); bundle.putSerializable(NoteShareDetailActivity.ARG_OCSHARE, share); bundle.putInt(NoteShareDetailActivity.ARG_SCREEN_TYPE, screenTypePermission); bundle.putBoolean(NoteShareDetailActivity.ARG_RESHARE_SHOWN, !isReshareForbidden(share)); bundle.putBoolean(NoteShareDetailActivity.ARG_EXP_DATE_SHOWN, getExpDateShown()); + bundle.putBoolean(NoteShareDetailActivity.ARG_SEND_EMAIL, sendEmail); Intent intent = new Intent(this, NoteShareDetailActivity.class); intent.putExtras(bundle); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 10006e39f..f0b039778 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -63,6 +63,7 @@ class NoteShareDetailActivity : const val ARG_SCREEN_TYPE = "arg_screen_type" const val ARG_RESHARE_SHOWN = "arg_reshare_shown" const val ARG_EXP_DATE_SHOWN = "arg_exp_date_shown" + const val ARG_SEND_EMAIL = "ard_send_email" private const val ARG_SECURE_SHARE = "secure_share" // types of screens to be displayed @@ -82,9 +83,11 @@ class NoteShareDetailActivity : 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 sendEmail: Boolean = false private var expirationDatePickerFragment: ExpirationDatePickerDialogFragment? = null private lateinit var repository: ShareRepository + private val passwordMask = "••••••" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -110,6 +113,7 @@ class NoteShareDetailActivity : isReShareShown = it.getBoolean(ARG_RESHARE_SHOWN, true) isExpDateShown = it.getBoolean(ARG_EXP_DATE_SHOWN, true) isSecureShare = it.getBoolean(ARG_SECURE_SHARE, false) + sendEmail = it.getBoolean(ARG_SEND_EMAIL, shareType == ShareType.EMAIL) } lifecycleScope.launch(Dispatchers.IO) { @@ -240,7 +244,7 @@ class NoteShareDetailActivity : } binding.shareProcessEnterPassword.run { - setText("••••••") + setText(passwordMask) setOnFocusChangeListener { _, hasFocus -> if (hasFocus) { text?.clear() @@ -525,7 +529,7 @@ class NoteShareDetailActivity : val noteText = binding.noteText.text.toString().trim() val password = binding.shareProcessEnterPassword.text.toString().trim() val label = binding.shareProcessChangeName.text.toString() - updateShare(noteText, label, password, false) + updateShare(noteText, label, password) } } else { // else show step 2 (note screen) @@ -552,47 +556,53 @@ class NoteShareDetailActivity : lifecycleScope.launch(Dispatchers.IO) { if (share != null && share?.note != noteText) { val label = binding.shareProcessChangeName.text.toString() - updateShare(noteText, label, password, true) + updateShare(noteText, label, password) } else { createShare(noteText, password) } } } - private suspend fun updateShare(noteText: String, label: String, password: String, sendEmail: Boolean) { - val hideDownload = binding.shareProcessHideDownloadCheckbox.isChecked - - val requestBody = UpdateShareRequest( - permissions = if (permission == -1) null else permission, - password = password, + private suspend fun updateShare( + noteText: String, + label: String, + password: String + ) { + val request = UpdateShareRequest( + permissions = permission.takeIf { it != -1 }, + password = if (password != passwordMask) { + password + } else { + null + }, expireDate = DateUtil.getExpirationDate(chosenExpDateInMills), label = label, note = noteText, attributes = "[]", - hideDownload = hideDownload.toString() + hideDownload = binding.shareProcessHideDownloadCheckbox.isChecked.toString() ) - val updateShareResult = repository.updateShare(share!!.id, requestBody) + val result = repository.updateShare(share?.id ?: return, request) - if (updateShareResult.isSuccess() && sendEmail) { - val sendEmailResult = repository.sendEmail(share!!.id, SharePasswordRequest(password)) - handleResult(sendEmailResult) - } else { - val errorResult = updateShareResult as ApiResult.Error - var errorMessage: String? = null - if (errorResult.message.contains("password")) { - errorMessage = getString(R.string.note_share_detail_activity_password_error_message) - } - handleResult(false, errorMessage = errorMessage) + if (!result.isSuccess()) { + val errorMessage = (result as? ApiResult.Error) + ?.message + ?.takeIf { it.contains("password", ignoreCase = true) } + ?.let { getString(R.string.note_share_detail_activity_password_error_message) } + + handleResult(false, errorMessage) + return } - if (updateShareResult.isSuccess() && !sendEmail) { - withContext(Dispatchers.Main) { - if (!TextUtils.isEmpty(share?.shareLink)) { - ClipboardUtil.copyToClipboard(this@NoteShareDetailActivity, share?.shareLink) + handleResult(true) + + share?.shareLink + ?.takeIf { it.isNotEmpty() } + ?.let { + withContext(Dispatchers.Main) { + ClipboardUtil.copyToClipboard(this@NoteShareDetailActivity, it) } } - } } private suspend fun createShare(noteText: String, password: String) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java index b9e9418db..4cfb84e42 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java @@ -56,7 +56,9 @@ protected void onCreate(Bundle savedInstanceState) { private void updateUI() { if (ocShare.getShareType() != null && ocShare.getShareType() == ShareType.PUBLIC_LINK) { binding.menuShareAddAnotherLink.setVisibility(View.VISIBLE); - binding.menuShareSendLink.setVisibility(View.VISIBLE); + + // Not implemented yet + binding.menuShareSendLink.setVisibility(View.GONE); } else { binding.menuShareAddAnotherLink.setVisibility(View.GONE); binding.menuShareSendLink.setVisibility(View.GONE); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index 0f33ba7f0..655899a1b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -21,7 +21,6 @@ import it.niedermann.owncloud.notes.persistence.entity.Note import it.niedermann.owncloud.notes.persistence.entity.ShareEntity import it.niedermann.owncloud.notes.share.model.CreateShareRequest import it.niedermann.owncloud.notes.share.model.CreateShareResponse -import it.niedermann.owncloud.notes.share.model.SharePasswordRequest import it.niedermann.owncloud.notes.share.model.UpdateSharePermissionRequest import it.niedermann.owncloud.notes.share.model.UpdateShareRequest import it.niedermann.owncloud.notes.share.model.toOCShareList @@ -187,24 +186,6 @@ class ShareRepository(private val applicationContext: Context, private val accou } } - fun sendEmail(shareId: Long, requestBody: SharePasswordRequest): Boolean { - val shareAPI = apiProvider.getShareAPI(applicationContext, account) - val call = shareAPI.sendEmail(shareId, requestBody) - val response = call.execute() - - return try { - if (response.isSuccessful) { - true - } else { - Log_OC.d(tag, "Failed to send-email: ${response.errorBody()?.string()}") - false - } - } catch (e: Exception) { - Log_OC.d(tag, "Exception while send-email: $e") - false - } - } - fun fetchSharesFromNote(note: Note): List { val sharesWithMe = fetchShares(note, sharedWithMe = true) val sharesWithOthers = fetchShares(note, sharedWithMe = false) From 1fc647cd7759f3a617291b4c0e3db906f01ad25f Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 11 Feb 2026 15:28:45 +0100 Subject: [PATCH 17/24] fix email address appearance in suggestion adapter Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 1 - .../notes/share/adapter/SuggestionAdapter.kt | 14 +++++- .../res/layout/item_internal_share_link.xml | 2 +- app/src/main/res/layout/item_note_share.xml | 49 ++++++++++--------- .../main/res/layout/item_share_link_share.xml | 37 +++++++------- app/src/main/res/layout/item_share_share.xml | 7 ++- .../res/layout/item_suggestion_adapter.xml | 8 ++- 7 files changed, 66 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index f0b039778..74529c708 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -27,7 +27,6 @@ import it.niedermann.owncloud.notes.persistence.isSuccess import it.niedermann.owncloud.notes.share.dialog.ExpirationDatePickerDialogFragment import it.niedermann.owncloud.notes.share.helper.SharePermissionManager import it.niedermann.owncloud.notes.share.model.QuickPermissionType -import it.niedermann.owncloud.notes.share.model.SharePasswordRequest import it.niedermann.owncloud.notes.share.model.UpdateShareRequest import it.niedermann.owncloud.notes.share.repository.ShareRepository import it.niedermann.owncloud.notes.shared.util.DisplayUtils diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/SuggestionAdapter.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/SuggestionAdapter.kt index 6348ae489..08d10bd5b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/SuggestionAdapter.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/adapter/SuggestionAdapter.kt @@ -46,7 +46,19 @@ class SuggestionAdapter(context: Context, cursor: Cursor?, private val account: override fun bindView(view: View, context: Context, cursor: Cursor) { val suggestion = cursor.getString(cursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1)) - view.findViewById(R.id.suggestion_text).text = suggestion + val suggestionTextView = view.findViewById(R.id.suggestion_text) + suggestionTextView.text = suggestion + + val sublineColumn = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2) + if (sublineColumn != -1 && suggestionTextView.text.isEmpty()) { + val subline = cursor.getStringOrNull(sublineColumn) + if (!subline.isNullOrEmpty()) { + suggestionTextView.visibility = View.VISIBLE + suggestionTextView.text = subline + } else { + suggestionTextView.visibility = View.GONE + } + } val icon = view.findViewById(R.id.suggestion_icon) val iconColumn = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1) diff --git a/app/src/main/res/layout/item_internal_share_link.xml b/app/src/main/res/layout/item_internal_share_link.xml index c6ee206a7..a56402d18 100644 --- a/app/src/main/res/layout/item_internal_share_link.xml +++ b/app/src/main/res/layout/item_internal_share_link.xml @@ -21,7 +21,7 @@ android:id="@+id/copy_internal_link_icon" android:layout_width="@dimen/default_icon_size" android:layout_height="@dimen/default_icon_size" - android:layout_gravity="top" + android:layout_gravity="center" android:layout_marginStart="@dimen/spacer_2x" android:layout_marginEnd="@dimen/spacer_2x" android:background="@drawable/round_bgnd" diff --git a/app/src/main/res/layout/item_note_share.xml b/app/src/main/res/layout/item_note_share.xml index 83927a827..c8137ab45 100644 --- a/app/src/main/res/layout/item_note_share.xml +++ b/app/src/main/res/layout/item_note_share.xml @@ -1,13 +1,12 @@ - - + android:textSize="@dimen/note_font_size_small" + android:visibility="gone" + tools:text="5 downloads remaining" + tools:visibility="visible" /> + app:drawableTint="@color/defaultBrand" + tools:text="View only" /> - + app:icon="@drawable/ic_content_copy" + app:iconSize="@dimen/iconized_single_line_item_icon_size" + app:iconTint="@color/icon_color_default" /> - + android:minHeight="@dimen/minimum_size_for_touchable_area" + app:icon="@drawable/ic_dots_vertical" + app:iconSize="@dimen/iconized_single_line_item_icon_size" + app:iconTint="@color/icon_color_default" /> diff --git a/app/src/main/res/layout/item_share_link_share.xml b/app/src/main/res/layout/item_share_link_share.xml index d5d6daa1b..6536a799b 100644 --- a/app/src/main/res/layout/item_share_link_share.xml +++ b/app/src/main/res/layout/item_share_link_share.xml @@ -1,13 +1,12 @@ - - + app:tint="@color/text_color" /> + tools:text="Share label" + tools:visibility="visible" /> + android:textSize="@dimen/note_font_size_minimum" + android:visibility="gone" + tools:text="5 downloads remaining" + tools:visibility="visible" /> + app:drawableTint="@color/defaultBrand" + tools:text="View only" /> - This password looks a bit weak. For better security, try using a longer password with a mix of letters, numbers, and symbols. Hide download + Allow download and sync Note to recipient Note Next From d0fc3aa1ba1e4685d1c057aad2aa0b07758c01a8 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 11 Feb 2026 16:35:06 +0100 Subject: [PATCH 20/24] implement allow download and sync Signed-off-by: alperozturk96 --- .../owncloud/notes/share/NoteShareActivity.java | 10 +++++++++- .../notes/share/NoteShareDetailActivity.kt | 15 +-------------- .../notes/share/model/UpdateShareRequest.kt | 4 ++-- .../notes/share/repository/ShareRepository.kt | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index 02f2bade4..4549c29df 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -859,6 +859,14 @@ public void setPasswordToShare(@NotNull OCShare share, @Nullable String password executorService.submit(() -> { { + boolean isDownloadAndAllowsSyncEnabled = repository.isAllowDownloadAndSync(share); + + String attributes = UpdateShareRequest.Companion.createAttributes( + repository.getCapabilities(), + isDownloadAndAllowsSyncEnabled, + share.getShareType() + ); + final var requestBody = new UpdateShareRequest( share.getPermissions(), password, @@ -866,7 +874,7 @@ public void setPasswordToShare(@NotNull OCShare share, @Nullable String password share.getLabel(), DateUtil.INSTANCE.getExpirationDate(share.getExpirationDate()), Boolean.toString(share.isHideFileDownload()), - "" + attributes ); final var result = repository.updateShare(share.getId(), requestBody); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index d92fc816d..c03c663e7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -27,8 +27,6 @@ import it.niedermann.owncloud.notes.persistence.isSuccess import it.niedermann.owncloud.notes.share.dialog.ExpirationDatePickerDialogFragment import it.niedermann.owncloud.notes.share.helper.SharePermissionManager import it.niedermann.owncloud.notes.share.model.QuickPermissionType -import it.niedermann.owncloud.notes.share.model.ShareAttributesV1 -import it.niedermann.owncloud.notes.share.model.ShareAttributesV2 import it.niedermann.owncloud.notes.share.model.UpdateShareRequest import it.niedermann.owncloud.notes.share.repository.ShareRepository import it.niedermann.owncloud.notes.shared.util.DisplayUtils @@ -332,18 +330,7 @@ class NoteShareDetailActivity : allowDownloadAndSync.visibility = View.VISIBLE share?.let { - val entity = repository.getShareByPathAndDisplayName(it) - val attributes = entity?.attributes ?: return - share?.attributes = attributes - - val capabilities = repository.getCapabilities() - val shouldUseShareAttributesV2 = (capabilities.nextcloudMajorVersion?.toInt() ?: 0) >= 30 - val isDownloadAndAllowsSyncEnabled = if (shouldUseShareAttributesV2) { - ShareAttributesV2.getAttributes(attributes).first().value - } else { - ShareAttributesV1.getAttributes(attributes).first().enabled - } - + val isDownloadAndAllowsSyncEnabled = repository.isAllowDownloadAndSync(it) binding.allowDownloadAndSync.isChecked = isDownloadAndAllowsSyncEnabled } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt index b615ee1bf..ec9f8c10f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/UpdateShareRequest.kt @@ -43,8 +43,8 @@ data class UpdateShareRequest( val attributes: String? = null ) { companion object { - fun createAttributes(capabilities: Capabilities, allowDownloadAndSync: Boolean, type: ShareType): String { - if (type != ShareType.INTERNAL && type != ShareType.USER) { + fun createAttributes(capabilities: Capabilities, allowDownloadAndSync: Boolean, type: ShareType?): String { + if (type == null || (type != ShareType.INTERNAL && type != ShareType.USER)) { return "[]" } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index 262b3b706..8fd5e965e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -21,6 +21,8 @@ import it.niedermann.owncloud.notes.persistence.entity.Note import it.niedermann.owncloud.notes.persistence.entity.ShareEntity import it.niedermann.owncloud.notes.share.model.CreateShareRequest import it.niedermann.owncloud.notes.share.model.CreateShareResponse +import it.niedermann.owncloud.notes.share.model.ShareAttributesV1 +import it.niedermann.owncloud.notes.share.model.ShareAttributesV2 import it.niedermann.owncloud.notes.share.model.UpdateSharePermissionRequest import it.niedermann.owncloud.notes.share.model.UpdateShareRequest import it.niedermann.owncloud.notes.share.model.toOCShareList @@ -129,6 +131,18 @@ class ShareRepository(private val applicationContext: Context, private val accou return notesRepository.getShareByPathAndDisplayName(share) } + fun isAllowDownloadAndSync(share: OCShare): Boolean { + val entity = getShareByPathAndDisplayName(share) + val attributes = entity?.attributes ?: return false + val capabilities = notesRepository.capabilities + val shouldUseShareAttributesV2 = (capabilities.nextcloudMajorVersion?.toInt() ?: 0) >= 30 + return if (shouldUseShareAttributesV2) { + ShareAttributesV2.getAttributes(attributes).first().value + } else { + ShareAttributesV1.getAttributes(attributes).first().enabled + } + } + private fun LinkedTreeMap<*, *>.getList(key: String): ArrayList<*>? = this[key] as? ArrayList<*> /** From 7deb29343bddb9818ffb61aab571d778a718a810 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 11 Feb 2026 16:42:33 +0100 Subject: [PATCH 21/24] fix allowDownloadAndSync during create Signed-off-by: alperozturk96 --- .../niedermann/owncloud/notes/share/NoteShareActivity.java | 5 ++--- .../owncloud/notes/share/NoteShareDetailActivity.kt | 7 ++++++- .../owncloud/notes/share/model/CreateShareRequest.kt | 5 ++++- .../owncloud/notes/share/repository/ShareRepository.kt | 7 +++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java index 4549c29df..f7336dd38 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java @@ -398,7 +398,7 @@ public void createPublicShareLink() { requestPasswordForShareViaLink(true, capabilities.getAskForOptionalPassword()); } else { executorService.submit(() -> { - final var result = repository.addShare(note, ShareType.PUBLIC_LINK, "", "false", "", 0, ""); + final var result = repository.addShare(note, ShareType.PUBLIC_LINK, ""); runOnUiThread(() -> { if (result instanceof ApiResult.Success> successResponse && binding.sharesList.getAdapter() instanceof ShareeListAdapter adapter) { DisplayUtils.showSnackMessage(NoteShareActivity.this, successResponse.getMessage()); @@ -835,8 +835,7 @@ public void shareFileViaPublicShare(@Nullable Note note, @Nullable String passwo "", "false", password, - repository.getCapabilities().getDefaultPermission(), - "" + repository.getCapabilities().getDefaultPermission() ); runOnUiThread(() -> { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index c03c663e7..92214dbd9 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -628,7 +628,12 @@ class NoteShareDetailActivity : "false", // TODO: Check how to determine it password, permission, - noteText + noteText, + UpdateShareRequest.createAttributes( + repository.getCapabilities(), + binding.allowDownloadAndSync.isChecked, + shareType + ) ) if (result.isSuccess()) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/model/CreateShareRequest.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/model/CreateShareRequest.kt index 1f3c9843d..12a378df6 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/model/CreateShareRequest.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/model/CreateShareRequest.kt @@ -28,5 +28,8 @@ data class CreateShareRequest( val permissions: Int?, @Expose - val note: String? + val note: String?, + + @Expose + val attributes: String? ) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt index 8fd5e965e..442fd8b5e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/repository/ShareRepository.kt @@ -291,6 +291,7 @@ class ShareRepository(private val applicationContext: Context, private val accou fun updateNote(note: Note) = notesRepository.updateNote(note) + @JvmOverloads fun addShare( note: Note, shareType: ShareType, @@ -298,7 +299,8 @@ class ShareRepository(private val applicationContext: Context, private val accou publicUpload: String = "false", password: String = "", permissions: Int = 0, - shareNote: String = "" + shareNote: String = "", + attributes: String = "[]" ): ApiResult?> { val defaultErrorMessage = applicationContext.getString(R.string.note_share_activity_cannot_created) @@ -316,7 +318,8 @@ class ShareRepository(private val applicationContext: Context, private val accou publicUpload = publicUpload, password = password, permissions = permissions, - note = shareNote + note = shareNote, + attributes = attributes ) val shareAPI = apiProvider.getShareAPI(applicationContext, account) From be2f633934d73ecc9f85687f42713de3094dc9bb Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 12 Feb 2026 08:53:39 +0100 Subject: [PATCH 22/24] change unshare text for user share type Signed-off-by: alperozturk96 --- ...ShareActivityShareItemActionBottomSheetDialog.java | 11 ++++++++++- app/src/main/res/layout/item_note_share_action.xml | 1 + app/src/main/res/values/strings.xml | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java index 4cfb84e42..f6c2001b1 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java @@ -16,6 +16,7 @@ import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; +import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.branding.BrandedBottomSheetDialog; import it.niedermann.owncloud.notes.branding.BrandingUtil; import it.niedermann.owncloud.notes.databinding.ItemNoteShareActionBinding; @@ -54,7 +55,9 @@ protected void onCreate(Bundle savedInstanceState) { } private void updateUI() { - if (ocShare.getShareType() != null && ocShare.getShareType() == ShareType.PUBLIC_LINK) { + final var shareType = ocShare.getShareType(); + + if (shareType == ShareType.PUBLIC_LINK) { binding.menuShareAddAnotherLink.setVisibility(View.VISIBLE); // Not implemented yet @@ -63,6 +66,12 @@ private void updateUI() { binding.menuShareAddAnotherLink.setVisibility(View.GONE); binding.menuShareSendLink.setVisibility(View.GONE); } + + int menuUnshareTextId = R.string.delete_link; + if (shareType == ShareType.USER) { + menuUnshareTextId = R.string.delete_share; + } + binding.menuUnshareText.setText(getContext().getString(menuUnshareTextId)); } private void setupClickListener() { diff --git a/app/src/main/res/layout/item_note_share_action.xml b/app/src/main/res/layout/item_note_share_action.xml index b222c2653..b514a3cb6 100644 --- a/app/src/main/res/layout/item_note_share_action.xml +++ b/app/src/main/res/layout/item_note_share_action.xml @@ -140,6 +140,7 @@ app:tint="@color/defaultBrand" /> Internal share link only works for users with access to this file Share internal link Delete Link + Delete share Settings Send new email Sharing From d96b0fe2b83bc2a3878fa407ca3cd77d61cbda74 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 12 Feb 2026 08:58:32 +0100 Subject: [PATCH 23/24] change unshare text for user share type Signed-off-by: alperozturk96 --- .../NoteShareActivityShareItemActionBottomSheetDialog.java | 2 +- app/src/main/res/layout/item_note_share_action.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java index f6c2001b1..ad20a756c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/dialog/NoteShareActivityShareItemActionBottomSheetDialog.java @@ -67,7 +67,7 @@ private void updateUI() { binding.menuShareSendLink.setVisibility(View.GONE); } - int menuUnshareTextId = R.string.delete_link; + int menuUnshareTextId = R.string.share_delete_link; if (shareType == ShareType.USER) { menuUnshareTextId = R.string.delete_share; } diff --git a/app/src/main/res/layout/item_note_share_action.xml b/app/src/main/res/layout/item_note_share_action.xml index b514a3cb6..581038942 100644 --- a/app/src/main/res/layout/item_note_share_action.xml +++ b/app/src/main/res/layout/item_note_share_action.xml @@ -145,7 +145,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginStart="@dimen/bottom_sheet_text_start_margin" - android:text="@string/delete_link" + android:text="@string/share_delete_link" android:textColor="@color/text_color" android:textSize="@dimen/bottom_sheet_text_size" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2f53928bd..6f4bd215d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -110,7 +110,7 @@ Internal share link only works for users with access to this folder Internal share link only works for users with access to this file Share internal link - Delete Link + Delete link Delete share Settings Send new email From 66d3eb90f7e7ea9331ea5701a9597bd140f0ae4c Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 12 Feb 2026 09:37:33 +0100 Subject: [PATCH 24/24] fix note enter for share create Signed-off-by: alperozturk96 --- .../notes/share/NoteShareDetailActivity.kt | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt index 92214dbd9..3e5a6ceb2 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareDetailActivity.kt @@ -9,7 +9,9 @@ package it.niedermann.owncloud.notes.share import android.content.Intent import android.content.res.Configuration import android.os.Bundle +import android.text.Editable import android.text.TextUtils +import android.text.TextWatcher import android.view.View import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.theme.utils.ColorRole @@ -87,6 +89,7 @@ class NoteShareDetailActivity : private var expirationDatePickerFragment: ExpirationDatePickerDialogFragment? = null private lateinit var repository: ShareRepository private val passwordMask = "••••••" + private var enteredNoteText = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -201,6 +204,7 @@ class NoteShareDetailActivity : } binding.noteText.setText(share?.note) + enteredNoteText = share?.note ?: "" shareProcessStep = SCREEN_TYPE_PERMISSION } @@ -383,10 +387,10 @@ class NoteShareDetailActivity : shareProcessBtnNext.text = getString(R.string.note_share_detail_activity_set_note) noteText.setText(share?.note) + enteredNoteText = share?.note ?: "" } else { shareProcessBtnNext.text = getString(R.string.note_share_detail_activity_send_share) - noteText.setText(R.string.empty) } shareProcessStep = SCREEN_TYPE_NOTE shareProcessBtnNext.performClick() @@ -396,6 +400,16 @@ class NoteShareDetailActivity : @Suppress("LongMethod") private fun implementClickEvents() { binding.run { + noteText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + enteredNoteText = s.toString() + } + + override fun afterTextChanged(s: Editable) = Unit + }) + shareProcessBtnCancel.setOnClickListener { onCancelClick() } @@ -532,10 +546,9 @@ class NoteShareDetailActivity : // if modifying existing share information then execute the process if (share != null) { lifecycleScope.launch(Dispatchers.IO) { - val noteText = binding.noteText.text.toString().trim() val password = binding.shareProcessEnterPassword.text.toString().trim() val label = binding.shareProcessChangeName.text.toString() - updateShare(noteText, label, password) + updateShare(label, password) } } else { // else show step 2 (note screen) @@ -556,21 +569,19 @@ class NoteShareDetailActivity : * method to validate step 2 (note screen) information */ private fun createOrUpdateShare() { - val noteText = binding.noteText.text.toString().trim() val password = binding.shareProcessEnterPassword.text.toString().trim() lifecycleScope.launch(Dispatchers.IO) { - if (share != null && share?.note != noteText) { + if (share != null && share?.note != enteredNoteText) { val label = binding.shareProcessChangeName.text.toString() - updateShare(noteText, label, password) + updateShare(label, password) } else { - createShare(noteText, password) + createShare(password) } } } private suspend fun updateShare( - noteText: String, label: String, password: String ) { @@ -583,7 +594,7 @@ class NoteShareDetailActivity : }, expireDate = DateUtil.getExpirationDate(chosenExpDateInMills), label = label, - note = noteText, + note = enteredNoteText.trim(), attributes = UpdateShareRequest.createAttributes( repository.getCapabilities(), binding.allowDownloadAndSync.isChecked, @@ -615,7 +626,7 @@ class NoteShareDetailActivity : } } - private suspend fun createShare(noteText: String, password: String) { + private suspend fun createShare(password: String) { if (note == null || shareeName == null) { Log_OC.d(TAG, "validateShareProcessSecond cancelled") return @@ -628,7 +639,7 @@ class NoteShareDetailActivity : "false", // TODO: Check how to determine it password, permission, - noteText, + enteredNoteText.trim(), UpdateShareRequest.createAttributes( repository.getCapabilities(), binding.allowDownloadAndSync.isChecked,