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 d1055ec234b9..51a47f0c0c48 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 @@ -81,7 +81,6 @@ import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.isActive import com.nextcloud.utils.extensions.isDialogFragmentReady import com.nextcloud.utils.extensions.lastFragment -import com.nextcloud.utils.extensions.logFileSize import com.nextcloud.utils.extensions.navigateToAllFiles import com.nextcloud.utils.extensions.observeWorker import com.nextcloud.utils.extensions.setVisibleIf @@ -210,10 +209,10 @@ class FileDisplayActivity : private var mWaitingToPreview: OCFile? = null - private var mSyncInProgress: Boolean = false + private var syncState: Parcelable = EmptyListState.LOADING set(value) { field = value - setEmptyListState() + listOfFilesFragment?.setEmptyListMessage(value) } private var pendingSyncFolderOperation: Runnable? = null @@ -327,13 +326,14 @@ class FileDisplayActivity : if (savedInstanceState != null) { mWaitingToPreview = savedInstanceState.getParcelableArgument(KEY_WAITING_TO_PREVIEW, OCFile::class.java) - mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS) + syncState = savedInstanceState.getParcelableArgument(KEY_SYNC_STATE, Parcelable::class.java) + ?: EmptyListState.LOADING mWaitingToSend = savedInstanceState.getParcelableArgument(KEY_WAITING_TO_SEND, OCFile::class.java) searchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY) searchOpen = savedInstanceState.getBoolean(KEY_IS_SEARCH_OPEN, false) } else { mWaitingToPreview = null - mSyncInProgress = false + syncState = EmptyListState.LOADING mWaitingToSend = null } } @@ -1362,21 +1362,17 @@ class FileDisplayActivity : } override fun onSaveInstanceState(outState: Bundle) { - // responsibility of restore is preferred in onCreate() before than in - // onRestoreInstanceState when there are Fragments involved super.onSaveInstanceState(outState) - mWaitingToPreview.logFileSize(TAG) - outState.putParcelable(KEY_WAITING_TO_PREVIEW, mWaitingToPreview) - outState.putBoolean(KEY_SYNC_IN_PROGRESS, mSyncInProgress) - // outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, - // mRefreshSharesInProgress); - outState.putParcelable(KEY_WAITING_TO_SEND, mWaitingToSend) - if (searchView != null) { - outState.putBoolean(KEY_IS_SEARCH_OPEN, searchView?.isIconified == false) + outState.run { + putParcelable(KEY_WAITING_TO_PREVIEW, mWaitingToPreview) + putParcelable(KEY_SYNC_STATE, syncState) + putParcelable(KEY_WAITING_TO_SEND, mWaitingToSend) + if (searchView != null) { + putBoolean(KEY_IS_SEARCH_OPEN, searchView?.isIconified == false) + } + putString(KEY_SEARCH_QUERY, searchQuery) + putBoolean(KEY_IS_SORT_GROUP_VISIBLE, sortListGroupVisibility()) } - outState.putString(KEY_SEARCH_QUERY, searchQuery) - outState.putBoolean(KEY_IS_SORT_GROUP_VISIBLE, sortListGroupVisibility()) - Log_OC.v(TAG, "onSaveInstanceState() end") } override fun onResume() { @@ -1546,7 +1542,7 @@ class FileDisplayActivity : } catch (_: java.lang.RuntimeException) { safelyDeleteResult(intent) } finally { - mSyncInProgress = false + onSyncFinished() } } } @@ -1633,7 +1629,7 @@ class FileDisplayActivity : return } - if (mSyncInProgress || ocFileListFragment.isLoading) { + if (syncState == EmptyListState.LOADING || ocFileListFragment.isLoading) { return } @@ -1677,6 +1673,7 @@ class FileDisplayActivity : RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION -> showInfoBox(R.string.offline_mode) RemoteOperationResult.ResultCode.HOST_NOT_AVAILABLE -> showInfoBox(R.string.host_not_available) RemoteOperationResult.ResultCode.SIGNING_TOS_NEEDED -> showTermsOfServiceDialog() + RemoteOperationResult.ResultCode.OUT_OF_MEMORY -> syncState = EmptyListState.OUT_OF_MEMORY else -> {} } } @@ -1696,23 +1693,18 @@ class FileDisplayActivity : (syncResult.isException && syncResult.exception is AuthenticatorException) } - private fun setEmptyListState() { - listOfFilesFragment?.let { - when { - mSyncInProgress -> { - it.setEmptyListMessage(EmptyListState.LOADING) - } + private fun onSyncFinished() { + if (syncState != EmptyListState.LOADING) { + return + } - MainApp.isOnlyOnDevice() -> { - it.setEmptyListMessage(EmptyListState.ONLY_ON_DEVICE) - } + syncState = when { + MainApp.isOnlyOnDevice() -> EmptyListState.ONLY_ON_DEVICE - it.searchEvent?.searchType == SearchRemoteOperation.SearchType.FAVORITE_SEARCH -> { - it.setEmptyListMessage(SearchType.FAVORITE_SEARCH) - } + listOfFilesFragment?.searchEvent?.searchType == SearchRemoteOperation.SearchType.FAVORITE_SEARCH -> + SearchType.FAVORITE_SEARCH - else -> it.setEmptyListMessage(SearchType.NO_SEARCH) - } + else -> SearchType.NO_SEARCH } } @@ -2552,7 +2544,7 @@ class FileDisplayActivity : fun startSyncFolderOperation(folder: OCFile?, ignoreETag: Boolean, ignoreFocus: Boolean = false) { Log_OC.d(TAG, "startSyncFolderOperation called, ignoreEtag: $ignoreETag, ignoreFocus: $ignoreFocus") - if (!TextUtils.isEmpty(searchQuery) || !user.isPresent) { + if (!searchQuery.isNullOrEmpty() || !user.isPresent) { return } @@ -2583,30 +2575,29 @@ class FileDisplayActivity : } private fun executeSyncFolderOperation(folder: OCFile?, ignoreETag: Boolean) { - val user = getUser() - if (!user.isPresent) { - return - } - - mSyncInProgress = true - - RefreshFolderOperation( - folder, - System.currentTimeMillis(), - false, - ignoreETag, - storageManager, - user.get(), - applicationContext - ).execute( - account, - MainApp.getAppContext(), - this@FileDisplayActivity, - null, - null - ) + val folder = folder ?: return + + user.ifPresent { user -> + syncState = EmptyListState.LOADING + + RefreshFolderOperation( + folder, + System.currentTimeMillis(), + false, + ignoreETag, + storageManager, + user, + applicationContext + ).execute( + account, + this, + { _, _ -> onSyncFinished() }, + handler, + null + ) - fetchRecommendedFilesIfNeeded(ignoreETag, folder) + fetchRecommendedFilesIfNeeded(ignoreETag, folder) + } } private fun fetchRecommendedFilesIfNeeded(ignoreETag: Boolean, folder: OCFile?) { @@ -2619,8 +2610,8 @@ class FileDisplayActivity : return } - if (user.isPresent) { - val accountName = user.get().accountName + user.ifPresent { user -> + val accountName = user.accountName val fragment = this.listOfFilesFragment lifecycleScope.launch(Dispatchers.IO) { val recommendedFiles = filesRepository.fetchRecommendedFiles(accountName, ignoreETag, storageManager) @@ -3309,7 +3300,7 @@ class FileDisplayActivity : const val KEY_IS_SORT_GROUP_VISIBLE: String = "KEY_IS_SORT_GROUP_VISIBLE" private const val KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW" - private const val KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS" + private const val KEY_SYNC_STATE = "SYNC_STATE" private const val KEY_WAITING_TO_SEND = "WAITING_TO_SEND" private const val DIALOG_TAG_SHOW_TOS = "DIALOG_TAG_SHOW_TOS" 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 aed634b43167..6d1d20947653 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 @@ -555,6 +555,8 @@ open class FolderPickerActivity : "Detekt.LongMethod" ) // legacy code override fun onReceive(context: Context, intent: Intent) { + var emptyListState = EmptyListState.LOCAL_FILE_LIST_EMPTY_FILE + try { val event = intent.action Log_OC.d(TAG, "Received broadcast $event") @@ -569,6 +571,10 @@ open class FolderPickerActivity : return } + if (ResultCode.OUT_OF_MEMORY == syncResult.code) { + emptyListState = EmptyListState.OUT_OF_MEMORY + } + if (FileSyncAdapter.EVENT_FULL_SYNC_START != event) { // EVENT_SINGLE_FOLDER_CONTENTS_SYNCED fires only when the folder's content actually // changed, and EVENT_SINGLE_FOLDER_SHARES_SYNCED only when a sharee actually changed - @@ -598,7 +604,7 @@ open class FolderPickerActivity : // in owncloud library with broadcast notifications pending to process DataHolderUtil.getInstance().delete(intent.getStringExtra(FileSyncAdapter.EXTRA_RESULT)) } finally { - listOfFilesFragment?.setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FILE) + listOfFilesFragment?.setEmptyListMessage(emptyListState) } } diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.kt b/app/src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.kt index b75f9374dc47..d43085d6ac99 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.kt @@ -47,7 +47,7 @@ class GallerySearchTask( val result = performSearch(context) withContext(Dispatchers.Main) { - fragment.searchCompleted(result.emptySearch, result.lastTimestamp) + fragment.searchCompleted(result) } } @@ -62,7 +62,7 @@ class GallerySearchTask( return if (operationResult.isSuccess) { handleSuccess(operationResult) } else { - Result(false, false, NO_TIMESTAMP) + Result(operationResult.code, false, NO_TIMESTAMP) } } @@ -90,7 +90,7 @@ class GallerySearchTask( val remoteFiles = operationResult.data.filterIsInstance() val lastTimestamp = findLastTimestamp(remoteFiles) val emptySearch = parseMedia(lastTimestamp, endDate, remoteFiles) - return Result(true, emptySearch, lastTimestamp) + return Result(operationResult.code, emptySearch, lastTimestamp) } private fun findLastTimestamp(remoteFiles: List): Long = @@ -186,5 +186,9 @@ class GallerySearchTask( ) } - data class Result(val success: Boolean, val emptySearch: Boolean, val lastTimestamp: Long) + data class Result( + val resultCode: RemoteOperationResult.ResultCode, + val emptySearch: Boolean, + val lastTimestamp: Long + ) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt index aed275f33c5c..45f9063369b3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt @@ -728,6 +728,15 @@ open class ExtendedListFragment : ) } + EmptyListState.OUT_OF_MEMORY -> { + setMessageForEmptyList( + R.string.common_error_out_memory, + R.string.file_list_out_of_memory_description, + R.drawable.ic_list_empty_error, + false + ) + } + else -> { setMessageForEmptyList( R.string.file_list_empty_headline, diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt index 3b12ee6bf401..d0c071c22651 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt @@ -39,6 +39,7 @@ import com.owncloud.android.BuildConfig import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.ThumbnailsCacheManager +import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.EmptyRecyclerView import com.owncloud.android.ui.activity.FileDisplayActivity @@ -264,20 +265,25 @@ class GalleryFragment : } } - fun searchCompleted(emptySearch: Boolean, lastTimeStamp: Long) { + fun searchCompleted(result: GallerySearchTask.Result) { if (!isAdded) return this.isPhotoSearchQueryRunning = false - if (lastTimeStamp > -1) { - endDate = lastTimeStamp + if (result.resultCode == RemoteOperationResult.ResultCode.OUT_OF_MEMORY) { + setEmptyListMessage(EmptyListState.OUT_OF_MEMORY) + return + } + + if (result.lastTimestamp > -1) { + endDate = result.lastTimestamp } if (adapter?.isEmpty() == true) { setEmptyListMessage(SearchType.GALLERY_SEARCH) } - if (!emptySearch) { + if (!result.emptySearch) { showAllGalleryItems() } 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 e63a6188fd72..3e54e20630e9 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 @@ -73,8 +73,9 @@ class OCFileListSearchTask( updateAdapterData(fragment, cachedFiles) } - val result = fetchRemoteResults()?.takeIf { it.isSuccess } ?: run { - showSnackbarError(fragment) + val result = fetchRemoteResults() + if (result == null || !result.isSuccess) { + showError(fragment, result) return@launch } @@ -89,6 +90,15 @@ class OCFileListSearchTask( } } + private suspend fun showError(fragment: OCFileListFragment, result: RemoteOperationResult>?) { + if (result?.code == RemoteOperationResult.ResultCode.OUT_OF_MEMORY) { + withContext(Dispatchers.Main) { fragment.setEmptyListMessage(EmptyListState.OUT_OF_MEMORY) } + return + } + + showSnackbarError(fragment) + } + private suspend fun showSnackbarError(fragment: OCFileListFragment) { withContext(Dispatchers.Main) { fragment.activity?.let { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt index 8ccf5bf5c9b7..b829c597880e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/SearchType.kt @@ -45,5 +45,6 @@ enum class EmptyListState : Parcelable { ONLY_ON_DEVICE, LOCAL_FILE_LIST_EMPTY_FILE, LOCAL_FILE_LIST_EMPTY_FOLDER, - ERROR + ERROR, + OUT_OF_MEMORY } diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/RemoteTrashbinRepository.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/RemoteTrashbinRepository.kt index d05391bc1122..1eec774f3d39 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/RemoteTrashbinRepository.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/RemoteTrashbinRepository.kt @@ -13,10 +13,12 @@ package com.owncloud.android.ui.trashbin import android.os.AsyncTask +import androidx.annotation.StringRes import com.nextcloud.client.account.User import com.nextcloud.client.network.ClientFactory import com.nextcloud.client.network.ClientFactory.CreationException import com.owncloud.android.R +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.trashbin.EmptyTrashbinRemoteOperation import com.owncloud.android.lib.resources.trashbin.ReadTrashbinFolderRemoteOperation @@ -131,6 +133,9 @@ class RemoteTrashbinRepository internal constructor(private val user: User, priv ) : AsyncTask() { private var trashbinFiles: List? = null + @StringRes + private var errorMessage: Int = R.string.trashbin_loading_failed + @Deprecated("Deprecated in Java") override fun doInBackground(vararg voids: Void?): Boolean = try { val client = clientFactory.create(user) @@ -139,6 +144,9 @@ class RemoteTrashbinRepository internal constructor(private val user: User, priv trashbinFiles = result.resultData true } else { + if (result.code == ResultCode.OUT_OF_MEMORY) { + errorMessage = R.string.file_list_out_of_memory_description + } false } } catch (e: CreationException) { @@ -152,7 +160,7 @@ class RemoteTrashbinRepository internal constructor(private val user: User, priv if (success) { callback.onSuccess(trashbinFiles) } else { - callback.onError(R.string.trashbin_loading_failed) + callback.onError(errorMessage) } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b13cd0e8014f..3b6cb7d99a11 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,6 +15,7 @@ Media Poor connection Check your internet connection or try again later + Could not load content %1$s Android app version %1$s version %1$s, build #%2$s diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eb1cf70c6852..7a2b76c85ac1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ androidCommonLibraryVersion = "0.33.2" androidGifDrawableVersion = "1.2.32" androidImageCropperVersion = "4.7.0" -androidLibraryVersion ="c35b5190c54222e9e7b42cc03ab833d904b04c63" +androidLibraryVersion ="33037ef2b152372a165f17342875e991c75b86e6" androidOpensslVersion = "3.5.6" androidPluginVersion = "9.3.1" androidsvgVersion = "1.4" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 8cd3d87131c8..fcc2b808b97c 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -62,8 +62,8 @@ - + @@ -237,7 +237,10 @@ - + + + + @@ -21236,6 +21239,14 @@ + + + + + + + + @@ -21916,6 +21927,14 @@ + + + + + + + + @@ -22361,6 +22380,14 @@ + + + + + + + +