From c324ca638f265e204f1b303c9dbb8094a66c4ed8 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 09:35:15 +0100 Subject: [PATCH 1/9] Rename .java to .kt Signed-off-by: alperozturk96 --- ...istBottomSheetActions.java => OCFileListBottomSheetActions.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/owncloud/android/ui/fragment/{OCFileListBottomSheetActions.java => OCFileListBottomSheetActions.kt} (100%) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.kt similarity index 100% rename from app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java rename to app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.kt From d1feb68299758c1ff929151f22254582380221ff Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 09:35:16 +0100 Subject: [PATCH 2/9] feat(file-list-action): create an encrypted folder Signed-off-by: alperozturk96 --- .../ui/dialog/CreateFolderDialogFragment.kt | 9 +++- .../fragment/OCFileListBottomSheetActions.kt | 53 ++++++------------- .../fragment/OCFileListBottomSheetDialog.kt | 9 +++- .../ui/fragment/OCFileListFragment.java | 12 +++-- .../ui/helpers/FileOperationsHelper.java | 4 +- .../ic_action_create_encrypted_dir.xml | 15 ++++++ ...ile_list_actions_bottom_sheet_fragment.xml | 19 ++++++- app/src/main/res/values/strings.xml | 1 + 8 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 app/src/main/res/drawable/ic_action_create_encrypted_dir.xml diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt index f3078dce73cb..b74f2a4378b4 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt @@ -70,6 +70,7 @@ class CreateFolderDialogFragment : private var parentFolder: OCFile? = null private var positiveButton: MaterialButton? = null + private var encrypted: Boolean = false private lateinit var binding: EditBoxDialogBinding @@ -112,6 +113,7 @@ class CreateFolderDialogFragment : viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer) val parentFolder = requireArguments().getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java) + encrypted = requireArguments().getBoolean(ARG_ENCRYPTED, false) val folderContent = fileDataStorageManager.getFolderContent(parentFolder, false) val fileNames: MutableSet = Sets.newHashSetWithExpectedSize(folderContent.size) @@ -190,7 +192,7 @@ class CreateFolderDialogFragment : val path = parentFolder?.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR connectivityService.isNetworkAndServerAvailable { result -> if (result) { - typedActivity()?.fileOperationsHelper?.createFolder(path) + typedActivity()?.fileOperationsHelper?.createFolder(path, encrypted) } else { Log_OC.d(TAG, "Network not available, creating offline operation") fileDataStorageManager.addCreateFolderOfflineOperation( @@ -208,6 +210,8 @@ class CreateFolderDialogFragment : companion object { private const val TAG = "CreateFolderDialogFragment" private const val ARG_PARENT_FOLDER = "PARENT_FOLDER" + private const val ARG_ENCRYPTED = "ENCRYPTED" + const val CREATE_FOLDER_FRAGMENT = "CREATE_FOLDER_FRAGMENT" /** @@ -217,8 +221,9 @@ class CreateFolderDialogFragment : * @return Dialog ready to show. */ @JvmStatic - fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment { + fun newInstance(parentFolder: OCFile?, encrypted: Boolean): CreateFolderDialogFragment { val bundle = Bundle().apply { + putBoolean(ARG_ENCRYPTED, encrypted) putParcelable(ARG_PARENT_FOLDER, parentFolder) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.kt index 0343cb17a292..5f8a7df59994 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.kt @@ -4,72 +4,51 @@ * SPDX-FileCopyrightText: 2018 Andy Scherzinger * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only */ -package com.owncloud.android.ui.fragment; +package com.owncloud.android.ui.fragment -import com.owncloud.android.lib.common.Creator; +import com.owncloud.android.lib.common.Creator -/** - * Actions interface to be implemented by any class that makes use of - * {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}. - */ -public interface OCFileListBottomSheetActions { - /** - * creates a folder within the actual folder. - */ - void createFolder(); +interface OCFileListBottomSheetActions { + fun createFolder(encrypted: Boolean) /** * offers a file upload with the Android OS file picker to the current folder. */ - void uploadFromApp(); + fun uploadFromApp() /** * offers a file upload with the app file picker to the current folder. */ - void uploadFiles(); + fun uploadFiles() /** * opens template selection for documents */ - void newDocument(); + fun newDocument() /** * opens template selection for spreadsheets */ - void newSpreadsheet(); + fun newSpreadsheet() - /** - * opens template selection for presentations - */ - void newPresentation(); - - /** - * offers direct camera upload to the current folder. - */ - void directCameraUpload(); - - /** - * offers scanning document upload to the current folder. - */ - void scanDocUpload(); + fun newPresentation() + fun directCameraUpload() + fun scanDocUpload() /** * Offers scanning a document in a supported external app and then upload to the current folder. */ - void scanDocUploadFromApp(); + fun scanDocUploadFromApp() /** - * @return true, if a supported external app is available for {@link #scanDocUploadFromApp()} + * @return true, if a supported external app is available for [.scanDocUploadFromApp] */ - boolean isScanDocUploadFromAppAvailable(); + val isScanDocUploadFromAppAvailable: Boolean /** * open template selection for creator @link Creator */ - void showTemplate(Creator creator, String headline); + fun showTemplate(creator: Creator?, headline: String?) - /** - * open editor for rich workspace - */ - void createRichWorkspace(); + fun createRichWorkspace() } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt index 4600176b9608..042f179538e6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt @@ -98,6 +98,7 @@ class OCFileListBottomSheetDialog( colorMaterialButtonContent(menuDirectCameraUpload, ColorRole.PRIMARY) colorMaterialButtonContent(menuScanDocUpload, ColorRole.PRIMARY) colorMaterialButtonContent(menuMkdir, ColorRole.PRIMARY) + colorMaterialButtonContent(menuEncryptedMkdir, ColorRole.PRIMARY) colorMaterialButtonContent(menuCreateRichWorkspace, ColorRole.PRIMARY) } } @@ -112,6 +113,7 @@ class OCFileListBottomSheetDialog( menuDirectCameraUpload.setTextColor(textColor) menuScanDocUpload.setTextColor(textColor) menuMkdir.setTextColor(textColor) + menuEncryptedMkdir.setTextColor(textColor) menuCreateRichWorkspace.setTextColor(textColor) } } @@ -226,7 +228,12 @@ class OCFileListBottomSheetDialog( } menuMkdir.setOnClickListener { - actions.createFolder() + actions.createFolder(encrypted = false) + dismiss() + } + + menuEncryptedMkdir.setOnClickListener { + actions.createFolder(encrypted = true) dismiss() } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 698209fa1348..e2350be2e682 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -529,9 +529,15 @@ public void registerFabListener() { } @Override - public void createFolder() { - CreateFolderDialogFragment.newInstance(mFile) - .show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER); + public void createFolder(boolean encrypted) { + final var activity = getActivity(); + if (activity == null) { + Log_OC.e(TAG, "activity is null, cannot create a folder"); + return; + } + + CreateFolderDialogFragment.newInstance(mFile, encrypted) + .show(activity.getSupportFragmentManager(), DIALOG_CREATE_FOLDER); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index b071a92a9eff..f6b1a0eeb8de 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -982,12 +982,12 @@ public void removeFile(OCFile file, boolean onlyLocalCopy, boolean inBackground) mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service); } - public void createFolder(String remotePath) { - // Create Folder + public void createFolder(String remotePath, boolean encrypted) { Intent service = new Intent(fileActivity, OperationsService.class); service.setAction(OperationsService.ACTION_CREATE_FOLDER); service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath); + service.putExtra(OperationsService.EXTRA_ENCRYPTED, encrypted); mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service); fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment)); diff --git a/app/src/main/res/drawable/ic_action_create_encrypted_dir.xml b/app/src/main/res/drawable/ic_action_create_encrypted_dir.xml new file mode 100644 index 000000000000..b6c7f3b81b31 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_create_encrypted_dir.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml b/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml index 2ef322443115..233d98c179a7 100644 --- a/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml +++ b/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml @@ -113,7 +113,6 @@ app:iconSize="@dimen/iconized_single_line_item_icon_size" app:iconTint="@color/primary" /> - + + Scan document from camera Upload content from other apps New folder + New encrypted folder Virus detected. Upload cannot be completed! Tags Unable to fetch sharees. From e02d63f791e8d11a0ccc0c43c24cac848e269333 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 09:52:07 +0100 Subject: [PATCH 3/9] feat(file-list-action): create an encrypted folder Signed-off-by: alperozturk96 --- .../operations/CreateFolderOperation.java | 29 +++++++++++++++---- .../android/services/OperationsService.java | 12 +++++--- .../ui/activity/FileDisplayActivity.kt | 10 +++++++ .../ui/activity/FolderPickerActivity.kt | 2 +- .../ReceiveExternalFilesActivity.java | 2 +- .../fragment/OCFileListBottomSheetDialog.kt | 6 ++++ .../ui/fragment/OCFileListFragment.java | 16 ++++++++++ 7 files changed, 65 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index a426ee2359e0..c94e76be1a3f 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -59,8 +59,9 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper protected String remotePath; private RemoteFile createdRemoteFolder; - private User user; - private Context context; + private boolean encrypt = false; + private final User user; + private final Context context; /** * Constructor @@ -73,6 +74,14 @@ public CreateFolderOperation(String remotePath, User user, Context context, File this.context = context; } + public void setEncrypt(boolean value) { + encrypt = value; + } + + public boolean shouldEncrypt() { + return encrypt; + } + @Override protected RemoteOperationResult run(OwnCloudClient client) { String remoteParentPath = new File(getRemotePath()).getParent(); @@ -490,15 +499,23 @@ private String createRandomFileName(DecryptedFolderMetadataFileV1 metadata) { return encryptedFileName; } - private RemoteOperationResult normalCreate(OwnCloudClient client) { - RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client); + private RemoteOperationResult normalCreate(OwnCloudClient client) { + final var result = new CreateFolderRemoteOperation(remotePath, true).execute(client); if (result.isSuccess()) { - RemoteOperationResult remoteFolderOperationResult = new ReadFolderRemoteOperation(remotePath) + final var remoteFolderOperationResult = new ReadFolderRemoteOperation(remotePath) .execute(client); - createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0); + if (remoteFolderOperationResult.isSuccess() && + remoteFolderOperationResult.getData().get(0) instanceof RemoteFile remoteFile) { + createdRemoteFolder = remoteFile; + } + saveFolderInDB(); + + if (encrypt) { + + } } else { Log_OC.e(TAG, remotePath + " hasn't been created"); } diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 6923606819af..d8a645f6d98e 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -81,6 +81,7 @@ public class OperationsService extends Service { private static final String TAG = OperationsService.class.getSimpleName(); + public static final String EXTRA_ENCRYPTED = "ENCRYPTED"; public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_POST_DIALOG_EVENT = "EXTRA_POST_DIALOG_EVENT"; public static final String EXTRA_SERVER_URL = "SERVER_URL"; @@ -708,10 +709,13 @@ private Pair newOperation(Intent operationIntent) { case ACTION_CREATE_FOLDER: remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); - operation = new CreateFolderOperation(remotePath, - user, - getApplicationContext(), - fileDataStorageManager); + boolean encrypt = operationIntent.getBooleanExtra(EXTRA_ENCRYPTED, false); + final var createFolderOperation = new CreateFolderOperation(remotePath, + user, + getApplicationContext(), + fileDataStorageManager); + createFolderOperation.setEncrypt(encrypt); + operation = createFolderOperation; break; case ACTION_SYNC_FILE: diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 21a74acb64bf..211483d572d0 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2310,6 +2310,16 @@ class FileDisplayActivity : private fun onCreateFolderOperationFinish(operation: CreateFolderOperation, result: RemoteOperationResult<*>) { if (result.isSuccess) { val fileListFragment = this.listOfFilesFragment + if (operation.shouldEncrypt()) { + val file = storageManager.getFileByDecryptedRemotePath(operation.remotePath) + if (file == null) { + Log_OC.e(TAG, "onCreateFolderOperationFinish(): file not saved after create folder operation, cannot encrypt") + return + } + fileOperationsHelper.toggleEncryption(file, true) + return + } + fileListFragment?.onItemClicked(storageManager.getFileByDecryptedRemotePath(operation.getRemotePath())) } else { try { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt index 63f82db8cdff..24e3160fe585 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt @@ -323,7 +323,7 @@ open class FolderPickerActivity : val itemId = item.itemId if (itemId == R.id.action_create_dir) { - val dialog = CreateFolderDialogFragment.newInstance(currentFolder) + val dialog = CreateFolderDialogFragment.newInstance(currentFolder, false) dialog.show(supportFragmentManager, CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT) } else if (itemId == android.R.id.home) { val currentDir = currentFolder diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 41c557e61023..4054a7725542 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -1163,7 +1163,7 @@ public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.action_create_dir) { - CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile); + CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile, false); dialog.show(getSupportFragmentManager(), CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT); } else if (itemId == android.R.id.home) { if (mParents.size() > SINGLE_PARENT) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt index 042f179538e6..6678980fb9df 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt @@ -24,6 +24,7 @@ import com.nextcloud.client.di.Injectable import com.nextcloud.client.documentscan.AppScanOptionalFeature import com.nextcloud.utils.BuildHelper.isFlavourGPlay import com.nextcloud.utils.EditorUtils +import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.FileListActionsBottomSheetFragmentBinding @@ -74,6 +75,7 @@ class OCFileListBottomSheetDialog( createRichWorkspace() setupClickListener() filterActionsForOfflineOperations() + checkCreateEncryptedFolderVisibility() if (MainApp.isClientBranded() && isFlavourGPlay()) { // this way we can have branded clients with that permission @@ -90,6 +92,10 @@ class OCFileListBottomSheetDialog( } } + private fun checkCreateEncryptedFolderVisibility() { + binding.menuEncryptedMkdir.setVisibleIf(file.isRootDirectory) + } + private fun applyBranding() { viewThemeUtils.material.run { binding.run { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index e2350be2e682..3e172322ee95 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -536,6 +536,22 @@ public void createFolder(boolean encrypted) { return; } + if (encrypted) { + User user = accountManager.getUser(); + String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY); + String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY); + + if (publicKey.isEmpty() || privateKey.isEmpty()) { + Log_OC.w(TAG,"cannot create encrypted folder directly, needs to setup encryption first"); + + requireActivity().runOnUiThread(() -> { + final var dialog = SetupEncryptionDialogFragment.newInstance(user, mFile.getRemotePath()); + dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG); + }); + return; + } + } + CreateFolderDialogFragment.newInstance(mFile, encrypted) .show(activity.getSupportFragmentManager(), DIALOG_CREATE_FOLDER); } From b917b48d41ba68a0f84dfc011f33e402dbbeee5b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 09:53:12 +0100 Subject: [PATCH 4/9] fix codacy Signed-off-by: alperozturk96 --- .../com/owncloud/android/ui/activity/FileDisplayActivity.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 211483d572d0..0f734cdc6477 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2313,7 +2313,10 @@ class FileDisplayActivity : if (operation.shouldEncrypt()) { val file = storageManager.getFileByDecryptedRemotePath(operation.remotePath) if (file == null) { - Log_OC.e(TAG, "onCreateFolderOperationFinish(): file not saved after create folder operation, cannot encrypt") + Log_OC.e( + TAG, + "onCreateFolderOperationFinish(): file not saved after create folder operation, cannot encrypt" + ) return } fileOperationsHelper.toggleEncryption(file, true) From ede19df3b4b1bc3ee4386248ae729038e629f23a Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 10:11:50 +0100 Subject: [PATCH 5/9] fix crash for toggling encryption for root directory Signed-off-by: alperozturk96 --- .../com/owncloud/android/ui/helpers/FileOperationsHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index f6b1a0eeb8de..b346d7b41929 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -931,7 +931,7 @@ public void toggleFavoriteFile(ServerFileInterface file, boolean shouldBeFavorit } public void toggleEncryption(OCFile file, boolean shouldBeEncrypted) { - if (file.isEncrypted() != shouldBeEncrypted) { + if (file.isEncrypted() != shouldBeEncrypted && !file.isRootDirectory()) { EventBus.getDefault().post(new EncryptionEvent(file.getLocalId(), file.getRemoteId(), file.getRemotePath(), From ec1eee615c8e40458f47b1cd1188ed22da6c6d2f Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 10:34:49 +0100 Subject: [PATCH 6/9] fix toggleEncryption calls for all cases Signed-off-by: alperozturk96 --- .../ui/helpers/FileOperationsHelper.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index b346d7b41929..e5a3824db421 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -68,6 +68,7 @@ import com.owncloud.android.ui.events.FavoriteEvent; import com.owncloud.android.ui.events.FileLockEvent; import com.owncloud.android.ui.events.SyncEventFinished; +import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.EncryptionUtils; import com.owncloud.android.utils.FileStorageUtils; @@ -931,12 +932,34 @@ public void toggleFavoriteFile(ServerFileInterface file, boolean shouldBeFavorit } public void toggleEncryption(OCFile file, boolean shouldBeEncrypted) { - if (file.isEncrypted() != shouldBeEncrypted && !file.isRootDirectory()) { - EventBus.getDefault().post(new EncryptionEvent(file.getLocalId(), - file.getRemoteId(), - file.getRemotePath(), - shouldBeEncrypted)); + if (file.isEncrypted() == shouldBeEncrypted) { + Log_OC.d(TAG, "file already in wanted encryption state. " + + "isEncrypted: " + file.isEncrypted() + " should be encrypted: "+ shouldBeEncrypted); + return; } + + if (file.isRootDirectory()) { + Log_OC.d(TAG, "toggle encryption triggered in root directory, this call is for creating encrypted folder"); + if (!(fileActivity instanceof FileDisplayActivity fda)) { + Log_OC.e(TAG, "file display activity is not active, cannot show create folder dialog"); + return; + } + + OCFileListFragment fragment = fda.getListOfFilesFragment(); + if (fragment == null) { + Log_OC.e(TAG, "file list fragment is null, cannot show create folder dialog"); + return; + } + + fragment.createFolder(true); + return; + } + + Log_OC.d(TAG, "toggling encryption for: " + file.getRemotePath()); + EventBus.getDefault().post(new EncryptionEvent(file.getLocalId(), + file.getRemoteId(), + file.getRemotePath(), + shouldBeEncrypted)); } public void toggleFileLock(OCFile file, boolean shouldBeLocked) { From 6f9b1a77558bad97721e08758633e108b603d224 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 10:42:25 +0100 Subject: [PATCH 7/9] fix and improve updateFileEncryptionById calls Signed-off-by: alperozturk96 --- .../android/ui/adapter/OCFileListAdapter.java | 24 +++++++------------ .../ui/fragment/OCFileListFragment.java | 4 ++-- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 81eba055c99e..2b6ea998ba2c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -289,25 +289,17 @@ public void refreshCommentsCount(String fileId) { new Handler(Looper.getMainLooper()).post(this::notifyDataSetChanged); } - public void setEncryptionAttributeForItemID(String fileId, boolean encrypted) { - for (OCFile file : mFiles) { - if (file.getRemoteId().equals(fileId)) { + public void updateFileEncryptionById(String fileId, boolean encrypted) { + mFilesAll.stream() + .filter(f -> fileId.equals(f.getRemoteId())) + .findFirst() + .ifPresent(file -> { file.setEncrypted(encrypted); file.setE2eCounter(0L); mStorageManager.saveFile(file); - - break; - } - } - - for (OCFile file : mFilesAll) { - if (file.getRemoteId().equals(fileId)) { - file.setEncrypted(encrypted); - file.setE2eCounter(0L); - } - } - - new Handler(Looper.getMainLooper()).post(this::notifyDataSetChanged); + int position = getItemPosition(file); + notifyItemChanged(position); + }); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 3e172322ee95..f25a4107f8de 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1327,7 +1327,7 @@ private void listenSetupEncryptionDialogResult() { } mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true); - mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true); + mAdapter.updateFileEncryptionById(file.getRemoteId(), true); searchFragment = false; setFileDepth(file); listDirectory(file, MainApp.isOnlyOnDevice()); @@ -2056,7 +2056,7 @@ private void encryptFolder(OCFile folder, throw new IllegalArgumentException("Unknown E2E version"); } - requireActivity().runOnUiThread(() -> mAdapter.setEncryptionAttributeForItemID(remoteId, shouldBeEncrypted)); + requireActivity().runOnUiThread(() -> mAdapter.updateFileEncryptionById(remoteId, shouldBeEncrypted)); } else if (remoteOperationResult.getHttpCode() == HttpStatus.SC_FORBIDDEN && getRecyclerView() != null) { requireActivity().runOnUiThread(() -> Snackbar.make(getRecyclerView(), R.string.end_to_end_encryption_folder_not_empty, From f3832fd563f24203644e638afb4fd5dda197985b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 11:11:37 +0100 Subject: [PATCH 8/9] fix oc adapter calls Signed-off-by: alperozturk96 --- .../android/ui/adapter/OCFileListAdapter.java | 29 ++++++++++++++++++- .../ui/fragment/OCFileListFragment.java | 19 ++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 2b6ea998ba2c..6ecfdcbaa495 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -290,6 +290,8 @@ public void refreshCommentsCount(String fileId) { } public void updateFileEncryptionById(String fileId, boolean encrypted) { + if (fileId == null) return; + mFilesAll.stream() .filter(f -> fileId.equals(f.getRemoteId())) .findFirst() @@ -297,8 +299,11 @@ public void updateFileEncryptionById(String fileId, boolean encrypted) { file.setEncrypted(encrypted); file.setE2eCounter(0L); mStorageManager.saveFile(file); + int position = getItemPosition(file); - notifyItemChanged(position); + if (position != -1) { + notifyItemChanged(position); + } }); } @@ -960,6 +965,28 @@ public List getFiles() { return mFiles; } + @Nullable + public OCFile getFileByRemoteId(@Nullable String fileId) { + return mFilesAll.stream() + .filter(f -> java.util.Objects.equals(fileId, f.getRemoteId())) + .findFirst() + .orElse(null); + } + + public void insertFile(@Nullable OCFile file) { + if (file == null) return; + + if (mFilesAll.contains(file)) return; + + mFilesAll.add(file); + mFiles.add(file); + + int position = getItemPosition(file); + if (position != -1) { + notifyItemInserted(position); + } + } + public void addVirtualFile(@NonNull OCFile file) { if (mFiles.isEmpty() || !mFiles.contains(file)) { mFiles.add(file); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index f25a4107f8de..07768afc4b2a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1326,6 +1326,13 @@ private void listenSetupEncryptionDialogResult() { return; } + if (file.isRootDirectory()) { + Log_OC.d(TAG, "result of setup encryption triggered in root directory, this call is for " + + "creating encrypted folder"); + createFolder(true); + return; + } + mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true); mAdapter.updateFileEncryptionById(file.getRemoteId(), true); searchFragment = false; @@ -2012,7 +2019,7 @@ private void encryptFolder(OCFile folder, Log_OC.d(TAG, "encrypt folder " + folder.getRemoteId()); User user = accountManager.getUser(); OwnCloudClient client = clientFactory.create(user); - RemoteOperationResult remoteOperationResult = new ToggleEncryptionRemoteOperation(localId, + final var remoteOperationResult = new ToggleEncryptionRemoteOperation(localId, remotePath, shouldBeEncrypted) .execute(client); @@ -2056,7 +2063,15 @@ private void encryptFolder(OCFile folder, throw new IllegalArgumentException("Unknown E2E version"); } - requireActivity().runOnUiThread(() -> mAdapter.updateFileEncryptionById(remoteId, shouldBeEncrypted)); + requireActivity().runOnUiThread(() -> { + boolean isFileExists = (mAdapter.getFileByRemoteId(remoteId) != null); + if (!isFileExists) { + OCFile newFile = storageManager.getFileByRemoteId(remoteId); + mAdapter.insertFile(newFile); + } + + mAdapter.updateFileEncryptionById(remoteId, shouldBeEncrypted); + }); } else if (remoteOperationResult.getHttpCode() == HttpStatus.SC_FORBIDDEN && getRecyclerView() != null) { requireActivity().runOnUiThread(() -> Snackbar.make(getRecyclerView(), R.string.end_to_end_encryption_folder_not_empty, From cc6a76525edecc8d27dbbda71c1edb3c4ffdebca Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Mar 2026 12:10:43 +0100 Subject: [PATCH 9/9] fix lint Signed-off-by: alperozturk96 --- .../owncloud/android/operations/CreateFolderOperation.java | 6 +----- .../com/owncloud/android/ui/activity/StorageMigration.java | 2 +- .../owncloud/android/ui/fragment/OCFileListFragment.java | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index c94e76be1a3f..795331f6c1d1 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -59,7 +59,7 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper protected String remotePath; private RemoteFile createdRemoteFolder; - private boolean encrypt = false; + private volatile boolean encrypt = false; private final User user; private final Context context; @@ -512,10 +512,6 @@ private RemoteOperationResult normalCreate(OwnCloudClient client) { } saveFolderInDB(); - - if (encrypt) { - - } } else { Log_OC.e(TAG, remotePath + " hasn't been created"); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java index 7992adb1585d..02a1fb67b4d8 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java @@ -329,7 +329,7 @@ protected Integer doInBackground(Void... voids) { } static private class FileMigrationTask extends FileMigrationTaskBase { - private class MigrationException extends Exception { + private static class MigrationException extends Exception { private static final long serialVersionUID = -4575848188034992066L; private int mResId; diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 07768afc4b2a..5d51068db926 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -544,7 +544,7 @@ public void createFolder(boolean encrypted) { if (publicKey.isEmpty() || privateKey.isEmpty()) { Log_OC.w(TAG,"cannot create encrypted folder directly, needs to setup encryption first"); - requireActivity().runOnUiThread(() -> { + activity.runOnUiThread(() -> { final var dialog = SetupEncryptionDialogFragment.newInstance(user, mFile.getRemotePath()); dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG); }); @@ -1131,10 +1131,10 @@ public boolean onLongItemClicked(OCFile file) { } private void folderOnItemClick(OCFile file, int position) { - if (requireActivity() instanceof FolderPickerActivity) { + if (requireActivity() instanceof FolderPickerActivity fpa) { String filenameErrorMessage = FileNameValidator.INSTANCE.checkFileName(file.getFileName(), getCapabilities(), requireContext(), null); if (filenameErrorMessage != null) { - DisplayUtils.showSnackMessage(requireActivity(), filenameErrorMessage); + DisplayUtils.showSnackMessage(fpa, filenameErrorMessage); return; } }