diff --git a/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityScreenshotIT.kt b/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityScreenshotIT.kt index ca13d25070e1..8108814ed68b 100644 --- a/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityScreenshotIT.kt +++ b/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityScreenshotIT.kt @@ -23,6 +23,7 @@ import com.owncloud.android.R import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.fragment.EmptyListState +import com.owncloud.android.ui.fragment.FabState import com.owncloud.android.utils.ScreenshotTest import org.junit.Assert import org.junit.Rule @@ -48,7 +49,7 @@ class FileDisplayActivityScreenshotIT : AbstractIT() { scenario.onActivity { sut -> sut.run { listOfFilesFragment?.let { - it.setFabEnabled(false) + it.setFabState(FabState.DISABLED) resetScrolling(true) it.setEmptyListMessage(EmptyListState.LOADING) it.isLoading = false @@ -78,7 +79,7 @@ class FileDisplayActivityScreenshotIT : AbstractIT() { activity = sut val fragment = sut.listOfFilesFragment Assert.assertNotNull(fragment) - fragment!!.setFabEnabled(false) + fragment!!.setFabState(FabState.DISABLED) fragment.setEmptyListMessage(EmptyListState.LOADING) fragment.isLoading = false } @@ -91,7 +92,7 @@ class FileDisplayActivityScreenshotIT : AbstractIT() { .perform(NavigationViewActions.navigateTo(R.id.nav_all_files)) val fragment = activity!!.listOfFilesFragment - fragment!!.setFabEnabled(false) + fragment!!.setFabState(FabState.DISABLED) fragment.setEmptyListMessage(EmptyListState.LOADING) fragment.isLoading = false @@ -117,7 +118,7 @@ class FileDisplayActivityScreenshotIT : AbstractIT() { resetScrolling(true) listOfFilesFragment?.let { - it.setFabEnabled(false) + it.setFabState(FabState.DISABLED) it.setEmptyListMessage(EmptyListState.LOADING) it.isLoading = false } 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 1e1584ffb0f4..aa382cbe63e6 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 @@ -1097,7 +1097,7 @@ class FileDisplayActivity : file = currentFile currentFile?.let { - listOfFiles.setFabVisible(it.canCreateFileAndFolder()) + listOfFiles.updateFabState() listOfFiles.registerFabListener() } 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 5132ef93c67c..3326e134990f 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 @@ -199,7 +199,7 @@ open class ExtendedListFragment : if (activity is FileDisplayActivity) { val fragment = activity.leftFragment if (fragment is OCFileListFragment) { - fragment.setFabVisible(!hasFocus) + if (hasFocus) fragment.setFabState(FabState.HIDDEN) else fragment.updateFabState() } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FabState.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FabState.kt new file mode 100644 index 000000000000..ae85c629478f --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FabState.kt @@ -0,0 +1,38 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.owncloud.android.ui.fragment + +import com.google.android.material.floatingactionbutton.FloatingActionButton +import com.nextcloud.utils.extensions.slideHideBottomBehavior +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.utils.theme.ViewThemeUtils + +enum class FabState { + HIDDEN, + DISABLED, + ENABLED; + + fun applyTo(fab: FloatingActionButton, viewThemeUtils: ViewThemeUtils) { + val visible = this != HIDDEN + if (visible) fab.show() else fab.hide() + fab.isEnabled = this == ENABLED + viewThemeUtils.material.themeFAB(fab) + fab.slideHideBottomBehavior(visible) + } + + companion object { + fun from(folder: OCFile?, storageManager: FileDataStorageManager?, hiddenByScreen: Boolean): FabState = when { + hiddenByScreen || folder.isReadOnly(storageManager) -> HIDDEN + folder != null && (folder.canCreateFileAndFolder() || folder.isOfflineOperation) -> ENABLED + else -> DISABLED + } + + private fun OCFile?.isReadOnly(storageManager: FileDataStorageManager?): Boolean = + this != null && storageManager?.isReadOnly(this) == true + } +} 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 df6cacb57753..a17adade1de7 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 @@ -281,7 +281,7 @@ class GalleryFragment : // always show first stored items showAllGalleryItems() - setFabVisible(false) + setFabState(FabState.HIDDEN) searchAndDisplay() } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt index 01f945d5f4bb..8dc253f99bd3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt @@ -379,10 +379,8 @@ open class OCFileListFragment : setAdapter(args) hideFab = args?.getBoolean(ARG_HIDE_FAB, false) == true - if (hideFab) { - setFabVisible(false) - } else { - setFabVisible(currentFile?.let { canCreateInside(it) } ?: true) + updateFabState() + if (!hideFab) { registerFabListener() } @@ -477,50 +475,23 @@ open class OCFileListFragment : } } - fun setFabVisible(visible: Boolean) { - val fab = fabMain ?: return - + fun updateFabState() { val fileDisplayActivity = activity as? FileDisplayActivity - if (fileDisplayActivity != null && - (fileDisplayActivity.isAlbumsFragment || fileDisplayActivity.isAlbumItemsFragment) - ) { - fab.hide() - return - } - - val activity = activity ?: return - activity.runOnUiThread { - if (visible) { - fab.show() - viewThemeUtils.material.themeFAB(fab) - } else { - fab.hide() - } - fab.slideHideBottomBehavior(visible) - } + val isAlbumScreen = fileDisplayActivity?.isAlbumsFragment == true || + fileDisplayActivity?.isAlbumItemsFragment == true + val hiddenByScreen = hideFab || isSearchFragment || isAlbumScreen + setFabState(FabState.from(currentFile, containerActivity?.storageManager, hiddenByScreen)) } - fun setFabEnabled(enabled: Boolean) { + fun setFabState(state: FabState) { val fab = fabMain ?: return - val activity = activity ?: return - activity.runOnUiThread { - fab.isEnabled = enabled - viewThemeUtils.material.themeFAB(fab) - } + activity?.runOnUiThread { state.applyTo(fab, viewThemeUtils) } } private fun setBottomNavigationVisible(visible: Boolean) { val drawerActivity = activity as? DrawerActivity ?: return drawerActivity.bottomNavigationView.slideHideBottomBehavior(visible) } - - private fun isReadOnlyFolder(folder: OCFile?): Boolean { - folder ?: return false - val storageManager = containerActivity?.storageManager ?: return false - return storageManager.isReadOnly(folder) - } - - private fun canCreateInside(folder: OCFile): Boolean = folder.canCreateFileAndFolder() && !isReadOnlyFolder(folder) //endregion //region Create and upload actions @@ -801,7 +772,9 @@ open class OCFileListFragment : fileDisplayActivity.previewFile( file, object : CompletionCallback { - override fun onComplete(value: Boolean) = setFabVisible(value) + override fun onComplete(value: Boolean) { + if (value) updateFabState() else setFabState(FabState.HIDDEN) + } } ) @@ -833,7 +806,7 @@ open class OCFileListFragment : when { !file.isEncrypted && fileDisplayActivity != null && fileDisplayActivity.canPreviewInAudioPlayer(file) -> { - setFabVisible(false) + setFabState(FabState.HIDDEN) fileDisplayActivity.startAudioPreview(file, true, true) } @@ -1192,7 +1165,7 @@ open class OCFileListFragment : fun refreshDirectory() { isSearchFragment = false val folder = currentFile ?: return - setFabVisible(canCreateInside(folder)) + updateFabState() listDirectory(folder, MainApp.isOnlyOnDevice()) } @@ -1210,12 +1183,8 @@ open class OCFileListFragment : fileListLayoutManager?.setLayoutViewMode() updateSortButtonLabel() setLayoutSwitchButton() - - val folder = currentFile - val readOnly = isReadOnlyFolder(folder) - setFabVisible(!hideFab && !readOnly) + updateFabState() setBottomNavigationVisible(!hideFab) - setFabEnabled(folder != null && !readOnly && (folder.canCreateFileAndFolder() || folder.isOfflineOperation)) activeActionMode?.invalidate() } @@ -1349,7 +1318,7 @@ open class OCFileListFragment : applySearchEvent(event) isSearchFragment = true - setFabVisible(false) + setFabState(FabState.HIDDEN) mainHandler.post { updateSortButtonLabel() @@ -1446,7 +1415,7 @@ open class OCFileListFragment : updateActionBarTitleAndHomeButton(null) } - currentFile?.let { setFabVisible(canCreateInside(it)) } + updateFabState() setBottomNavigationVisible(true) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListMultiChoiceModeListener.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListMultiChoiceModeListener.kt index df00d14c251b..fb8947c2d9f2 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListMultiChoiceModeListener.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListMultiChoiceModeListener.kt @@ -93,7 +93,7 @@ internal class OCFileListMultiChoiceModeListener(private val fragment: OCFileLis mode?.invalidate() colorStatusBar(activity) - fragment.setFabVisible(false) + fragment.setFabState(FabState.HIDDEN) if (fragment is GalleryFragment && activity is AlbumsPickerActivity) { placeholderItem.isVisible = false @@ -139,9 +139,7 @@ internal class OCFileListMultiChoiceModeListener(private val fragment: OCFileLis Log_OC.d(TAG, "Selection mode finished") activeActionMode = null - if (!fragment.hideFab && !fragment.isSearchFragment) { - fragment.currentFile?.let { fragment.setFabVisible(it.canCreateFileAndFolder()) } - } + fragment.updateFabState() fragment.activity?.let { fragment.viewThemeUtils.platform.resetStatusBar(it)