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/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index c23fc17a52bc..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( @@ -2341,38 +2338,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 +2348,53 @@ class FileDisplayActivity : mLastSslUntrustedServerResult = result showUntrustedCertDialog(mLastSslUntrustedServerResult) } + return + } + + val currentUser = optionalUser.get() + val leftFragment = this.leftFragment + if (leftFragment is FileFragment) { + onRenameFileOperationFinishForFileFragment(leftFragment, renamedFile, currentUser) + } + + 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/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index a2c7616dda3c..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 @@ -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); @@ -1112,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(); + } + } } 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..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 @@ -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) + } } - } } } 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 } 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); 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..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 @@ -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,68 +68,68 @@ 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) - fragment.adapter.files - } - - val sortedNewList = sortSearchData(newList, searchType, null, setNewSortOrder = { - fragment.adapter.setSortOrder(it) - }) + val cachedFiles = loadSortedCachedDbFiles(event.searchType, searchType, fragment) + if (cachedFiles.isNotEmpty()) { + 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, fragment) + } - 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, fragment) + } @Suppress("DEPRECATION") private suspend fun fetchRemoteResults(): RemoteOperationResult>? { @@ -155,18 +156,11 @@ class OCFileListSearchTask( fragment.adapter.updateAdapter(newList, null) } - private suspend fun sortSearchData( - list: List, - searchType: SearchType, - folder: OCFile?, - setNewSortOrder: (FileSortOrder) -> Unit - ): List = withContext(Dispatchers.IO) { - var newList = list.toMutableList() - + private fun sortSearchData(list: List, searchType: SearchType, fragment: OCFileListFragment): List { if (searchType == SearchType.GALLERY_SEARCH || searchType == SearchType.RECENT_FILES_SEARCH ) { - return@withContext FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(newList) + return FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(list) } val foldersBeforeFiles = preferences.isSortFoldersBeforeFiles() @@ -182,20 +176,18 @@ class OCFileListSearchTask( } else -> { - preferences.getSortOrderByFolder(folder) + preferences.getSortOrderByFolder(null) } } - setNewSortOrder(sortOrder) - newList = sortOrder.sortCloudFiles(newList, foldersBeforeFiles, favoritesFirst) - - return@withContext newList + fragment.adapter.setSortOrder(sortOrder) + return sortOrder.sortCloudFiles(list.toMutableList(), foldersBeforeFiles, favoritesFirst) } @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,64 +197,60 @@ class OCFileListSearchTask( } val contentValuesList = ArrayList() + val resultFiles = ArrayList() + var cachedClient: Account? = null for (obj in data) { try { 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) + 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 - ).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 { - put(ProviderMeta.ProviderTableMeta.VIRTUAL_TYPE, virtualType.toString()) - put(ProviderMeta.ProviderTableMeta.VIRTUAL_OCFILE_ID, ocFile.fileId) - } - contentValuesList.add(cv) + 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) } } - // Save timestamp + virtual entries preferences.setPhotoSearchTimestamp(System.currentTimeMillis()) storageManager.saveVirtuals(contentValuesList) + + return@withContext resultFiles } @Suppress("DEPRECATION") 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, @@ -290,4 +278,16 @@ class OCFileListSearchTask( return fileDataStorage.saveFileWithParent(ocFile, activity) } + + private fun resolveLocalFileId(ocFile: OCFile) { + if (ocFile.fileId != -1L) return + val localFile = storageManager.getFileByLocalId(ocFile.localId) ?: return + ocFile.fileId = localFile.fileId + } + + // region public methods + fun cancel() = job?.cancel(null) + + fun isFinished(): Boolean = job?.isCompleted == true + // endregion }