From c89d5e2cd23c11cf0cc7487b3086ee45e2887796 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 8 May 2026 15:59:05 +0200 Subject: [PATCH 01/10] fix(oc-file-list): favorite refresh Signed-off-by: alperozturk96 --- .../android/ui/adapter/OCFileListAdapter.java | 10 ++---- .../ui/fragment/OCFileListSearchTask.kt | 31 +++++++------------ 2 files changed, 14 insertions(+), 27 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 a2c7616dda3c..a23ee63ef570 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 @@ -875,7 +875,9 @@ public void swapDirectory( public void updateAdapter(List newFiles, OCFile directory) { Log_OC.d(TAG, "updating the adapter"); - mFiles = new ArrayList<>(newFiles); + mFiles.clear(); + mFiles.addAll(newFiles); + mFilesAll.clear(); mFilesAll.addAll(mFiles); @@ -982,12 +984,6 @@ public void insertFile(@Nullable OCFile file) { } } - public void addVirtualFile(@NonNull OCFile file) { - if (mFiles.isEmpty() || !mFiles.contains(file)) { - mFiles.add(file); - } - } - @Override public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { super.onViewRecycled(holder); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index 26a8943b311d..5c439f75741a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -97,7 +97,6 @@ class OCFileListSearchTask( ) } else { parseAndSaveVirtuals(result.resultData ?: listOf(), fragment) - fragment.adapter.files } val sortedNewList = sortSearchData(newList, searchType, null, setNewSortOrder = { @@ -193,9 +192,9 @@ class OCFileListSearchTask( } @Suppress("DEPRECATION") - private suspend fun parseAndSaveVirtuals(data: List, fragment: OCFileListFragment) = + private suspend fun parseAndSaveVirtuals(data: List, fragment: OCFileListFragment): List = withContext(Dispatchers.IO) { - val activity = fragment.activity ?: return@withContext + val activity = fragment.activity ?: return@withContext emptyList() val now = System.currentTimeMillis() val (virtualType, onlyMedia) = when (fragment.currentSearchType) { @@ -205,6 +204,7 @@ class OCFileListSearchTask( } val contentValuesList = ArrayList() + val resultFiles = ArrayList() for (obj in data) { try { @@ -215,37 +215,28 @@ class OCFileListSearchTask( ocFile = handleEncryptionIfNeeded(ocFile, storageManager, activity) if (fragment.currentSearchType != SearchType.GALLERY_SEARCH && ocFile.isFolder) { - RefreshFolderOperation( - ocFile, - now, - true, - false, - storageManager, - currentUser, - activity - ).execute(currentUser, activity) + RefreshFolderOperation(ocFile, now, true, false, storageManager, currentUser, activity) + .execute(currentUser, activity) } - val isMediaAllowed = - !onlyMedia || MimeTypeUtil.isImage(ocFile) || MimeTypeUtil.isVideo(ocFile) - + val isMediaAllowed = !onlyMedia || MimeTypeUtil.isImage(ocFile) || MimeTypeUtil.isVideo(ocFile) if (isMediaAllowed) { - fragment.adapter.addVirtualFile(ocFile) + resultFiles.add(ocFile) } - val cv = ContentValues().apply { + contentValuesList.add(ContentValues().apply { put(ProviderMeta.ProviderTableMeta.VIRTUAL_TYPE, virtualType.toString()) put(ProviderMeta.ProviderTableMeta.VIRTUAL_OCFILE_ID, ocFile.fileId) - } - contentValuesList.add(cv) + }) } catch (e: Exception) { Log_OC.e(TAG, "parseAndSaveVirtuals():", e) } } - // Save timestamp + virtual entries preferences.setPhotoSearchTimestamp(System.currentTimeMillis()) storageManager.saveVirtuals(contentValuesList) + + return@withContext resultFiles } @Suppress("DEPRECATION") From f5a595095cddeb791a14f65865cf42f89a543828 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 08:23:53 +0200 Subject: [PATCH 02/10] refresh directory to always use latest cached files to prevent duplicate item Signed-off-by: alperozturk96 --- .../ui/fragment/OCFileListSearchTask.kt | 122 +++++++++++------- 1 file changed, 74 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index 5c439f75741a..bc791180d6dd 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -67,67 +67,75 @@ class OCFileListSearchTask( job = fragment.lifecycleScope.launch(Dispatchers.IO) { val searchType = fragment.currentSearchType - // using cached data - val filesInDb = loadCachedDbFiles(event.searchType) - val sortedFilesInDb = sortSearchData(filesInDb, searchType, null, setNewSortOrder = { - fragment.adapter.setSortOrder(it) - }) - updateAdapterData(fragment, sortedFilesInDb) - - // updating cache and refreshing adapter - val result = fetchRemoteResults() - if (result?.isSuccess == true) { - if (result.resultData?.isEmpty() == true) { - withContext(Dispatchers.Main) { - fragment.setEmptyListMessage(fragment.currentSearchType) - return@withContext - } - - return@launch - } - - fragment.adapter.prepareForSearchData(storageManager, fragment.currentSearchType) - - val newList = if (searchType == SearchType.SHARED_FILTER) { - OCShareToOCFileConverter.parseAndSaveShares( - sortedFilesInDb, - result.resultData ?: listOf(), - storageManager, - currentUser.accountName - ) - } else { - parseAndSaveVirtuals(result.resultData ?: listOf(), fragment) - } + if (!refreshCurrentDir(fragment)) { + Log_OC.e(TAG, "folder refresh failed") + return@launch + } - val sortedNewList = sortSearchData(newList, searchType, null, setNewSortOrder = { - fragment.adapter.setSortOrder(it) - }) + val cachedFiles = loadSortedCachedDbFiles(event.searchType, searchType, fragment) + updateAdapterData(fragment, cachedFiles) - updateAdapterData(fragment, sortedNewList) + val result = fetchRemoteResults()?.takeIf { it.isSuccess } ?: run { + showSnackbarError(fragment) + return@launch + } + val resultData = result.resultData?.takeIf { it.isNotEmpty() } ?: run { + withContext(Dispatchers.Main) { fragment.setEmptyListMessage(fragment.currentSearchType) } return@launch } - withContext(Dispatchers.Main) { - fragment.activity?.let { - DisplayUtils.showSnackMessage(it, R.string.error_fetching_sharees) - } + fragment.adapter.prepareForSearchData(storageManager, fragment.currentSearchType) + val remoteFiles = fetchAndSortRemoteFiles(searchType, cachedFiles, resultData, fragment) + updateAdapterData(fragment, remoteFiles) + } + } + + private suspend fun showSnackbarError(fragment: OCFileListFragment) { + withContext(Dispatchers.Main) { + fragment.activity?.let { + DisplayUtils.showSnackMessage(it, R.string.error_fetching_sharees) } } } - fun cancel() = job?.cancel(null) + private suspend fun loadSortedCachedDbFiles( + searchType: SearchRemoteOperation.SearchType, + fragmentSearchType: SearchType, + fragment: OCFileListFragment + ): List { + val files = if (searchType == SearchRemoteOperation.SearchType.SHARED_FILTER) { + storageManager.fileDao.getSharedFiles(currentUser.accountName) + } else { + storageManager.fileDao.getFavoriteFiles(currentUser.accountName) + }.mapNotNull { storageManager.createFileInstance(it) } - fun isFinished(): Boolean = job?.isCompleted == true + return sortSearchData(files, fragmentSearchType, null, setNewSortOrder = { + fragment.adapter.setSortOrder(it) + }) + } - private suspend fun loadCachedDbFiles(searchType: SearchRemoteOperation.SearchType): List = - if (searchType == SearchRemoteOperation.SearchType.SHARED_FILTER) { - storageManager.fileDao - .getSharedFiles(currentUser.accountName) + private suspend fun fetchAndSortRemoteFiles( + searchType: SearchType, + sortedFilesInDb: List, + resultData: List, + fragment: OCFileListFragment + ): List { + val newList = if (searchType == SearchType.SHARED_FILTER) { + OCShareToOCFileConverter.parseAndSaveShares( + sortedFilesInDb, + resultData, + storageManager, + currentUser.accountName + ) } else { - storageManager.fileDao - .getFavoriteFiles(currentUser.accountName) - }.mapNotNull { storageManager.createFileInstance(it) } + parseAndSaveVirtuals(resultData, fragment) + } + + return sortSearchData(newList, searchType, null, setNewSortOrder = { + fragment.adapter.setSortOrder(it) + }) + } @Suppress("DEPRECATION") private suspend fun fetchRemoteResults(): RemoteOperationResult>? { @@ -281,4 +289,22 @@ class OCFileListSearchTask( return fileDataStorage.saveFileWithParent(ocFile, activity) } + + private fun refreshCurrentDir(fragment: OCFileListFragment): Boolean { + val folder = fragment.currentFile ?: storageManager.getFileByDecryptedRemotePath(OCFile.ROOT_PATH) + val operation = + RefreshFolderOperation( + folder, + storageManager, + currentUser, + fragment.context + ) + return operation.execute(currentUser, fragment.context).isSuccess + } + + // region public methods + fun cancel() = job?.cancel(null) + + fun isFinished(): Boolean = job?.isCompleted == true + // endregion } From 999ae346a8996bed0c5b274def0d10892cf51482 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 08:44:25 +0200 Subject: [PATCH 03/10] only show loading state first time if app doesn't have active search task Signed-off-by: alperozturk96 --- .../com/owncloud/android/ui/fragment/OCFileListFragment.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 d31dd21f5fba..3a146c7e5f9c 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 @@ -1818,7 +1818,9 @@ protected void handleSearchEvent(SearchEvent event) { } final var activity = getActivity(); - if (activity != null) { + + // only show loading state first time if app doesn't have active search task + if (activity != null && searchTask == null) { activity.runOnUiThread(() -> { getAdapter().removeAllFiles(); setEmptyListMessage(EmptyListState.LOADING); From cab8e86ddfc4ce8b749b20fb3c1bfe42221090f0 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 08:58:55 +0200 Subject: [PATCH 04/10] refresh current dir was not mandatory Signed-off-by: alperozturk96 --- .../ui/fragment/OCFileListSearchTask.kt | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index bc791180d6dd..e393c67ce088 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -10,6 +10,7 @@ package com.owncloud.android.ui.fragment import android.annotation.SuppressLint import android.app.Activity +import android.accounts.Account import android.content.ContentValues import androidx.lifecycle.lifecycleScope import com.nextcloud.client.account.User @@ -67,13 +68,12 @@ class OCFileListSearchTask( job = fragment.lifecycleScope.launch(Dispatchers.IO) { val searchType = fragment.currentSearchType - if (!refreshCurrentDir(fragment)) { - Log_OC.e(TAG, "folder refresh failed") - return@launch - } + refreshCurrentDir(fragment) val cachedFiles = loadSortedCachedDbFiles(event.searchType, searchType, fragment) - updateAdapterData(fragment, cachedFiles) + if (cachedFiles.isNotEmpty()) { + updateAdapterData(fragment, cachedFiles) + } val result = fetchRemoteResults()?.takeIf { it.isSuccess } ?: run { showSnackbarError(fragment) @@ -162,18 +162,16 @@ class OCFileListSearchTask( fragment.adapter.updateAdapter(newList, null) } - private suspend fun sortSearchData( + private fun sortSearchData( list: List, searchType: SearchType, folder: OCFile?, setNewSortOrder: (FileSortOrder) -> Unit - ): List = withContext(Dispatchers.IO) { - var newList = list.toMutableList() - + ): List { if (searchType == SearchType.GALLERY_SEARCH || searchType == SearchType.RECENT_FILES_SEARCH ) { - return@withContext FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(newList) + return FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(list) } val foldersBeforeFiles = preferences.isSortFoldersBeforeFiles() @@ -194,9 +192,7 @@ class OCFileListSearchTask( } setNewSortOrder(sortOrder) - newList = sortOrder.sortCloudFiles(newList, foldersBeforeFiles, favoritesFirst) - - return@withContext newList + return sortOrder.sortCloudFiles(list.toMutableList(), foldersBeforeFiles, favoritesFirst) } @Suppress("DEPRECATION") @@ -213,6 +209,7 @@ class OCFileListSearchTask( val contentValuesList = ArrayList() val resultFiles = ArrayList() + var cachedClient: Account? = null for (obj in data) { try { @@ -220,7 +217,9 @@ class OCFileListSearchTask( var ocFile = FileStorageUtils.fillOCFile(remoteFile) FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, currentUser.accountName) ocFile = storageManager.saveFileWithParent(ocFile, activity) - ocFile = handleEncryptionIfNeeded(ocFile, storageManager, activity) + ocFile = handleEncryptionIfNeeded(ocFile, storageManager, activity) { + cachedClient ?: currentUser.toPlatformAccount().also { cachedClient = it } + } if (fragment.currentSearchType != SearchType.GALLERY_SEARCH && ocFile.isFolder) { RefreshFolderOperation(ocFile, now, true, false, storageManager, currentUser, activity) @@ -251,17 +250,15 @@ class OCFileListSearchTask( private fun handleEncryptionIfNeeded( ocFile: OCFile, fileDataStorage: FileDataStorageManager, - activity: Activity + activity: Activity, + accountProvider: () -> Account ): OCFile { val parent = fileDataStorage.getFileById(ocFile.parentId) ?: return ocFile if (!ocFile.isEncrypted && !parent.isEncrypted) return ocFile - val client = OwnCloudClientFactory.createOwnCloudClient( - currentUser.toPlatformAccount(), - activity - ) + val client = OwnCloudClientFactory.createOwnCloudClient(accountProvider(), activity) val metadata = RefreshFolderOperation.getDecryptedFolderMetadata( true, From 37093385b638f6a7e60d02733036625f17b18512 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 09:20:57 +0200 Subject: [PATCH 05/10] resolveLocalFileId instead refresh whole directory Signed-off-by: alperozturk96 --- .../ui/fragment/OCFileListSearchTask.kt | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index e393c67ce088..4b5906e802fa 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -68,8 +68,6 @@ class OCFileListSearchTask( job = fragment.lifecycleScope.launch(Dispatchers.IO) { val searchType = fragment.currentSearchType - refreshCurrentDir(fragment) - val cachedFiles = loadSortedCachedDbFiles(event.searchType, searchType, fragment) if (cachedFiles.isNotEmpty()) { updateAdapterData(fragment, cachedFiles) @@ -110,9 +108,7 @@ class OCFileListSearchTask( storageManager.fileDao.getFavoriteFiles(currentUser.accountName) }.mapNotNull { storageManager.createFileInstance(it) } - return sortSearchData(files, fragmentSearchType, null, setNewSortOrder = { - fragment.adapter.setSortOrder(it) - }) + return sortSearchData(files, fragmentSearchType, fragment) } private suspend fun fetchAndSortRemoteFiles( @@ -132,9 +128,7 @@ class OCFileListSearchTask( parseAndSaveVirtuals(resultData, fragment) } - return sortSearchData(newList, searchType, null, setNewSortOrder = { - fragment.adapter.setSortOrder(it) - }) + return sortSearchData(newList, searchType, fragment) } @Suppress("DEPRECATION") @@ -165,8 +159,7 @@ class OCFileListSearchTask( private fun sortSearchData( list: List, searchType: SearchType, - folder: OCFile?, - setNewSortOrder: (FileSortOrder) -> Unit + fragment: OCFileListFragment ): List { if (searchType == SearchType.GALLERY_SEARCH || searchType == SearchType.RECENT_FILES_SEARCH @@ -187,11 +180,11 @@ class OCFileListSearchTask( } else -> { - preferences.getSortOrderByFolder(folder) + preferences.getSortOrderByFolder(null) } } - setNewSortOrder(sortOrder) + fragment.adapter.setSortOrder(sortOrder) return sortOrder.sortCloudFiles(list.toMutableList(), foldersBeforeFiles, favoritesFirst) } @@ -216,6 +209,7 @@ class OCFileListSearchTask( val remoteFile = obj as? RemoteFile ?: continue var ocFile = FileStorageUtils.fillOCFile(remoteFile) FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, currentUser.accountName) + resolveLocalFileId(ocFile) ocFile = storageManager.saveFileWithParent(ocFile, activity) ocFile = handleEncryptionIfNeeded(ocFile, storageManager, activity) { cachedClient ?: currentUser.toPlatformAccount().also { cachedClient = it } @@ -287,16 +281,10 @@ class OCFileListSearchTask( return fileDataStorage.saveFileWithParent(ocFile, activity) } - private fun refreshCurrentDir(fragment: OCFileListFragment): Boolean { - val folder = fragment.currentFile ?: storageManager.getFileByDecryptedRemotePath(OCFile.ROOT_PATH) - val operation = - RefreshFolderOperation( - folder, - storageManager, - currentUser, - fragment.context - ) - return operation.execute(currentUser, fragment.context).isSuccess + private fun resolveLocalFileId(ocFile: OCFile) { + if (ocFile.fileId != -1L) return + val localFile = storageManager.getFileByLocalId(ocFile.localId) ?: return + ocFile.fileId = localFile.fileId } // region public methods From 1895aec45a43ec15ce45899252f4dc73f7ffe202 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 09:30:08 +0200 Subject: [PATCH 06/10] simplify on rename logics Signed-off-by: alperozturk96 --- .../ui/activity/FileDisplayActivity.kt | 85 ++++++++++++------- .../ui/dialog/RenameFileDialogFragment.kt | 64 +++++++------- 2 files changed, 82 insertions(+), 67 deletions(-) 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 c23fc17a52bc..56dd41e2af7b 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 @@ -2341,38 +2341,7 @@ class FileDisplayActivity : private fun onRenameFileOperationFinish(operation: RenameFileOperation, result: RemoteOperationResult<*>) { val optionalUser = user val renamedFile = operation.file - if (result.isSuccess && optionalUser.isPresent) { - val currentUser = optionalUser.get() - val leftFragment = this.leftFragment - if (leftFragment is FileFragment) { - if (leftFragment is FileDetailFragment && renamedFile == leftFragment.file) { - leftFragment.updateFileDetails(renamedFile, currentUser) - showDetails(renamedFile) - } else if (leftFragment is PreviewMediaFragment && renamedFile == leftFragment.file) { - leftFragment.updateFile(renamedFile) - if (PreviewMediaFragment.canBePreviewed(renamedFile)) { - val position = leftFragment.position - startMediaPreview(renamedFile, position, true, true, true, false) - } else { - fileOperationsHelper.openFile(renamedFile) - } - } else if (leftFragment is PreviewTextFragment && renamedFile == leftFragment.file) { - (leftFragment as PreviewTextFileFragment).updateFile(renamedFile) - if (PreviewTextFileFragment.canBePreviewed(renamedFile)) { - startTextPreview(renamedFile, true) - } else { - fileOperationsHelper.openFile(renamedFile) - } - } - } - - val file = storageManager.getFileById(renamedFile.parentId) - if (file != null && file == getCurrentDir()) { - updateListOfFilesFragment() - } - refreshGalleryFragmentIfNeeded() - fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir) - } else { + if (!result.isSuccess || optionalUser.isEmpty) { DisplayUtils.showSnackMessage( this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()) @@ -2382,6 +2351,58 @@ class FileDisplayActivity : mLastSslUntrustedServerResult = result showUntrustedCertDialog(mLastSslUntrustedServerResult) } + return + } + + val currentUser = optionalUser.get() + val leftFragment = this.leftFragment + if (leftFragment is FileFragment) { + onRenameFileOperationFinishForFileFragment(leftFragment, renamedFile, currentUser) + } + + val file = storageManager.getFileById(renamedFile.parentId) + if (file != null && file == getCurrentDir()) { + updateListOfFilesFragment() + } + refreshGalleryFragmentIfNeeded() + fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir) + } + + private fun onRenameFileOperationFinishForFileFragment( + fragment: FileFragment, + ocFile: OCFile, + user: User + ) { + if (fragment.file != ocFile) return + + when (fragment) { + is FileDetailFragment -> { + fragment.updateFileDetails(ocFile, user) + showDetails(ocFile) + } + is PreviewMediaFragment -> { + fragment.updateFile(ocFile) + if (PreviewMediaFragment.canBePreviewed(ocFile)) { + startMediaPreview( + ocFile, + fragment.position, + true, + true, + true, + false + ) + } else { + fileOperationsHelper.openFile(ocFile) + } + } + is PreviewTextFileFragment -> { + fragment.updateFile(ocFile) + if (PreviewTextFileFragment.canBePreviewed(ocFile)) { + startTextPreview(ocFile, true) + } else { + fileOperationsHelper.openFile(ocFile) + } + } } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt index 4042629d7560..ffba3be824f4 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt @@ -37,10 +37,6 @@ import com.owncloud.android.utils.KeyboardUtils import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject -/** - * Dialog to input a new name for an [OCFile] being renamed. - * Triggers the rename operation. - */ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListener, @@ -58,7 +54,7 @@ class RenameFileDialogFragment : lateinit var currentAccount: CurrentAccountProvider private lateinit var binding: EditBoxDialogBinding - private var mTargetFile: OCFile? = null + private var targetFile: OCFile? = null private var positiveButton: MaterialButton? = null private var fileNames: MutableSet? = null @@ -73,15 +69,15 @@ class RenameFileDialogFragment : } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - mTargetFile = requireArguments().getParcelableArgument(ARG_TARGET_FILE, OCFile::class.java) + targetFile = requireArguments().getParcelableArgument(ARG_TARGET_FILE, OCFile::class.java) val inflater = requireActivity().layoutInflater binding = EditBoxDialogBinding.inflate(inflater, null, false) - val currentName = mTargetFile?.fileName + val currentName = targetFile?.fileName binding.userInput.setText(currentName) viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer) - val extensionStart = if (mTargetFile?.isFolder == true) -1 else currentName?.lastIndexOf('.') + val extensionStart = if (targetFile?.isFolder == true) -1 else currentName?.lastIndexOf('.') val selectionEnd = if ((extensionStart ?: -1) >= 0) extensionStart else currentName?.length if (selectionEnd != null) { binding.userInput.setSelection(0, selectionEnd) @@ -97,7 +93,7 @@ class RenameFileDialogFragment : binding.userInput.addTextChangedListener( FileNameTextWatcher( - previousFileName = mTargetFile?.fileName, + previousFileName = targetFile?.fileName, context = binding.userInputContainer.context, capabilitiesProvider = { oCCapability }, existingFileNamesProvider = { fileNames ?: setOf() }, @@ -168,17 +164,24 @@ class RenameFileDialogFragment : return } - if (mTargetFile?.isOfflineOperation == true) { - fileDataStorageManager.renameOfflineOperation(mTargetFile, newFileName) - typedActivity()?.refreshCurrentDirectory() - } else { - typedActivity()?.connectivityService?.isNetworkAndServerAvailable { result -> - if (result) { - typedActivity()?.fileOperationsHelper?.renameFile(mTargetFile, newFileName) - } else { - fileDataStorageManager.addRenameFileOfflineOperation(mTargetFile, newFileName) - typedActivity()?.refreshCurrentDirectory() - } + val fda = typedActivity() + + if (targetFile?.isOfflineOperation == true) { + fileDataStorageManager.renameOfflineOperation(targetFile, newFileName) + fda?.refreshCurrentDirectory() + return + } + + fda?.connectivityService?.isNetworkAndServerAvailable { result -> + if (result) { + /** + * result of it triggered by + * [com.owncloud.android.ui.activity.FileDisplayActivity.onRemoteOperationFinish] + */ + typedActivity()?.fileOperationsHelper?.renameFile(targetFile, newFileName) + } else { + fileDataStorageManager.addRenameFileOfflineOperation(targetFile, newFileName) + fda.refreshCurrentDirectory() } } } @@ -188,22 +191,13 @@ class RenameFileDialogFragment : private const val ARG_TARGET_FILE = "TARGET_FILE" private const val ARG_PARENT_FOLDER = "PARENT_FOLDER" - /** - * Public factory method to create new RenameFileDialogFragment instances. - * - * @param file File to rename. - * @return Dialog ready to show. - */ @JvmStatic - fun newInstance(file: OCFile?, parentFolder: OCFile?): RenameFileDialogFragment { - val bundle = Bundle().apply { - putParcelable(ARG_TARGET_FILE, file) - putParcelable(ARG_PARENT_FOLDER, parentFolder) - } - - return RenameFileDialogFragment().apply { - arguments = bundle + fun newInstance(file: OCFile?, parentFolder: OCFile?): RenameFileDialogFragment = + RenameFileDialogFragment().apply { + arguments = Bundle().apply { + putParcelable(ARG_TARGET_FILE, file) + putParcelable(ARG_PARENT_FOLDER, parentFolder) + } } - } } } From ad0cfb8ce602635712f172aca7fa8574cdf04cf2 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 09:41:05 +0200 Subject: [PATCH 07/10] fix refresh after rename Signed-off-by: alperozturk96 --- .../com/owncloud/android/ui/activity/FileDisplayActivity.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 56dd41e2af7b..f57b8a69b858 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 @@ -2360,10 +2360,7 @@ class FileDisplayActivity : onRenameFileOperationFinishForFileFragment(leftFragment, renamedFile, currentUser) } - val file = storageManager.getFileById(renamedFile.parentId) - if (file != null && file == getCurrentDir()) { - updateListOfFilesFragment() - } + updateListOfFilesFragment() refreshGalleryFragmentIfNeeded() fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir) } From 1d72739fb769f343790a8e1f1bd8c9f49b6f09eb Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 09:43:53 +0200 Subject: [PATCH 08/10] fix codacy Signed-off-by: alperozturk96 --- .../android/ui/activity/FileDisplayActivity.kt | 8 +++----- .../ui/dialog/RenameFileDialogFragment.kt | 2 +- .../android/ui/fragment/OCFileListSearchTask.kt | 16 +++++++--------- 3 files changed, 11 insertions(+), 15 deletions(-) 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 f57b8a69b858..4c43602c1eaa 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 @@ -2365,11 +2365,7 @@ class FileDisplayActivity : fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir) } - private fun onRenameFileOperationFinishForFileFragment( - fragment: FileFragment, - ocFile: OCFile, - user: User - ) { + private fun onRenameFileOperationFinishForFileFragment(fragment: FileFragment, ocFile: OCFile, user: User) { if (fragment.file != ocFile) return when (fragment) { @@ -2377,6 +2373,7 @@ class FileDisplayActivity : fragment.updateFileDetails(ocFile, user) showDetails(ocFile) } + is PreviewMediaFragment -> { fragment.updateFile(ocFile) if (PreviewMediaFragment.canBePreviewed(ocFile)) { @@ -2392,6 +2389,7 @@ class FileDisplayActivity : fileOperationsHelper.openFile(ocFile) } } + is PreviewTextFileFragment -> { fragment.updateFile(ocFile) if (PreviewTextFileFragment.canBePreviewed(ocFile)) { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt index ffba3be824f4..cc4de04cba0b 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt @@ -174,7 +174,7 @@ class RenameFileDialogFragment : fda?.connectivityService?.isNetworkAndServerAvailable { result -> if (result) { - /** + /* * result of it triggered by * [com.owncloud.android.ui.activity.FileDisplayActivity.onRemoteOperationFinish] */ diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt index 4b5906e802fa..6788110f67cf 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListSearchTask.kt @@ -156,11 +156,7 @@ class OCFileListSearchTask( fragment.adapter.updateAdapter(newList, null) } - private fun sortSearchData( - list: List, - searchType: SearchType, - fragment: OCFileListFragment - ): List { + private fun sortSearchData(list: List, searchType: SearchType, fragment: OCFileListFragment): List { if (searchType == SearchType.GALLERY_SEARCH || searchType == SearchType.RECENT_FILES_SEARCH ) { @@ -225,10 +221,12 @@ class OCFileListSearchTask( resultFiles.add(ocFile) } - contentValuesList.add(ContentValues().apply { - put(ProviderMeta.ProviderTableMeta.VIRTUAL_TYPE, virtualType.toString()) - put(ProviderMeta.ProviderTableMeta.VIRTUAL_OCFILE_ID, ocFile.fileId) - }) + contentValuesList.add( + ContentValues().apply { + put(ProviderMeta.ProviderTableMeta.VIRTUAL_TYPE, virtualType.toString()) + put(ProviderMeta.ProviderTableMeta.VIRTUAL_OCFILE_ID, ocFile.fileId) + } + ) } catch (e: Exception) { Log_OC.e(TAG, "parseAndSaveVirtuals():", e) } From cc97f6b1b4ddf26827ae3b7b71fe41c766a91679 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 12:15:42 +0200 Subject: [PATCH 09/10] fix delete file refresh Signed-off-by: alperozturk96 --- .../ui/activity/FileDisplayActivity.kt | 59 +++++++++---------- .../android/ui/adapter/OCFileListAdapter.java | 14 +++++ 2 files changed, 42 insertions(+), 31 deletions(-) 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 4c43602c1eaa..3841ca20ab2a 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 @@ -1680,6 +1680,10 @@ class FileDisplayActivity : it.setEmptyListMessage(EmptyListState.ONLY_ON_DEVICE) } + it.searchEvent?.searchType == SearchRemoteOperation.SearchType.FAVORITE_SEARCH -> { + it.setEmptyListMessage(SearchType.FAVORITE_SEARCH) + } + else -> it.setEmptyListMessage(SearchType.NO_SEARCH) } } @@ -2163,41 +2167,34 @@ class FileDisplayActivity : */ private fun onRemoveFileOperationFinish(operation: RemoveFileOperation, result: RemoteOperationResult<*>) { deleteBatchTracker.onSingleDeleteFinished() + if (!result.isSuccess && result.isSslRecoverableException) { + mLastSslUntrustedServerResult = result + showUntrustedCertDialog(mLastSslUntrustedServerResult) + return + } - if (result.isSuccess) { - val removedFile = operation.file - tryStopPlaying(removedFile) - val leftFragment = this.leftFragment + val removedFile = operation.file + tryStopPlaying(removedFile) + val leftFragment = this.leftFragment - // check if file is still available, if so do nothing - val fileAvailable = storageManager.fileExists(removedFile.fileId) - if (leftFragment is FileFragment && !fileAvailable && removedFile == leftFragment.file) { - file = storageManager.getFileById(removedFile.parentId) - resetScrollingAndUpdateActionBar() - } - val parentFile = storageManager.getFileById(removedFile.parentId) - if (parentFile != null && parentFile == getCurrentDir()) { - updateListOfFilesFragment() - } else if (leftFragment is OCFileListFragment && - SearchRemoteOperation.SearchType.FAVORITE_SEARCH == leftFragment.searchEvent?.searchType - ) { - leftFragment.adapter?.run { - val file = files.find { it.fileId == removedFile.fileId } - if (file != null) { - val pos = getItemPosition(file) - files.remove(file) - notifyItemRemoved(pos) - } - } - } - supportInvalidateOptionsMenu() - fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir) - } else { - if (result.isSslRecoverableException) { - mLastSslUntrustedServerResult = result - showUntrustedCertDialog(mLastSslUntrustedServerResult) + // check if file is still available, if so do nothing + val fileAvailable = storageManager.fileExists(removedFile.fileId) + if (leftFragment is FileFragment && !fileAvailable && removedFile == leftFragment.file) { + file = storageManager.getFileById(removedFile.parentId) + resetScrollingAndUpdateActionBar() + } + + if (leftFragment is OCFileListFragment) { + leftFragment.adapter?.removeFile(removedFile) + + if (leftFragment.adapter?.isEmpty == true) { + val emptyState = leftFragment.searchEvent?.toSearchType() ?: SearchType.NO_SEARCH + leftFragment.setEmptyListMessage(emptyState) } } + + supportInvalidateOptionsMenu() + fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir) } override fun onAutoUploadFolderRemoved( 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 a23ee63ef570..1a139f950da6 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 @@ -1108,4 +1108,18 @@ public void removeAllFiles() { mFilesAll.clear(); notifyDataSetChanged(); } + + @SuppressLint("NotifyDataSetChanged") + public void removeFile(@NonNull OCFile file) { + int position = getItemPosition(file); + + mFiles.remove(file); + mFilesAll.remove(file); + + if (position != -1) { + notifyItemRemoved(position); + } else { + notifyDataSetChanged(); + } + } } From a3b17e3ae8902048df0eae06233be36baf66bd53 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 11 May 2026 15:42:35 +0200 Subject: [PATCH 10/10] keep layout style after rename Signed-off-by: alperozturk96 --- .../client/preferences/AppPreferences.java | 2 +- .../client/preferences/AppPreferencesImpl.java | 4 ++-- .../android/ui/fragment/FileListLayoutManager.kt | 15 ++++++++++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java index b7d6818ea5a1..135d3fb364bd 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java @@ -135,7 +135,7 @@ default void onDarkThemeModeChanged(DarkMode mode) { * @return preference value, default is * {@link com.owncloud.android.ui.fragment.OCFileListFragment#FOLDER_LAYOUT_LIST} */ - String getFolderLayout(OCFile folder); + String getFolderLayout(OCFile folder, String defaultLayout); /** * Set preferred folder display type. diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java index a16beaeaaad9..59d4de7ccfd1 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java @@ -336,12 +336,12 @@ public String[] getPassCode() { } @Override - public String getFolderLayout(OCFile folder) { + public String getFolderLayout(OCFile folder, String defaultLayout) { return getFolderPreference(context, userAccountManager.getUser(), PREF__FOLDER_LAYOUT, folder, - FOLDER_LAYOUT_LIST); + defaultLayout); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileListLayoutManager.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileListLayoutManager.kt index 87070d218f14..7601aa881d22 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileListLayoutManager.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileListLayoutManager.kt @@ -22,6 +22,10 @@ import com.owncloud.android.utils.FileSortOrder class FileListLayoutManager(private val fragment: OCFileListFragment, private val preferences: AppPreferences) { + companion object { + private var lastLayout = OCFileListFragment.FOLDER_LAYOUT_LIST + } + fun sortFiles(sortOrder: FileSortOrder?) { fragment.mSortButton?.setText(DisplayUtils.getSortOrderStringId(sortOrder)) sortOrder?.let { fragment.mAdapter.setSortOrder(fragment.mFile, it) } @@ -40,9 +44,9 @@ class FileListLayoutManager(private val fragment: OCFileListFragment, private va */ fun isGridViewPreferred(folder: OCFile?): Boolean = if (fragment.searchEvent != null) { (fragment.searchEvent.toSearchType() != SearchType.SHARED_FILTER) && - (OCFileListFragment.FOLDER_LAYOUT_GRID == preferences.getFolderLayout(folder)) + (OCFileListFragment.FOLDER_LAYOUT_GRID == preferences.getFolderLayout(folder, lastLayout)) } else { - OCFileListFragment.FOLDER_LAYOUT_GRID == preferences.getFolderLayout(folder) + OCFileListFragment.FOLDER_LAYOUT_GRID == preferences.getFolderLayout(folder, lastLayout) } fun setLayoutViewMode() { @@ -65,6 +69,7 @@ class FileListLayoutManager(private val fragment: OCFileListFragment, private va fun switchToListView() { if (fragment.isGridEnabled) { switchLayoutManager(false) + lastLayout = OCFileListFragment.FOLDER_LAYOUT_LIST } } @@ -76,6 +81,7 @@ class FileListLayoutManager(private val fragment: OCFileListFragment, private va fun switchToGridView() { if (!fragment.isGridEnabled) { switchLayoutManager(true) + lastLayout = OCFileListFragment.FOLDER_LAYOUT_GRID } } @@ -100,12 +106,11 @@ class FileListLayoutManager(private val fragment: OCFileListFragment, private va val layoutManager: RecyclerView.LayoutManager? if (grid) { layoutManager = GridLayoutManager(context, fragment.columnsCount) - val gridLayoutManager = layoutManager - gridLayoutManager.spanSizeLookup = object : SpanSizeLookup() { + layoutManager.spanSizeLookup = object : SpanSizeLookup() { override fun getSpanSize(position: Int): Int = if (position == fragment.adapter.itemCount - 1 || (position == 0 && fragment.adapter.shouldShowHeader()) ) { - gridLayoutManager.spanCount + layoutManager.spanCount } else { 1 }