diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt index eb69869263bb..e5310f9129f2 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt @@ -73,6 +73,12 @@ enum class FileAction( constructor(id: Int, title: Int) : this(id, title, null) + fun toggledFavorite(): FileAction? = when (this) { + FAVORITE -> UNSET_FAVORITE + UNSET_FAVORITE -> FAVORITE + else -> null + } + companion object { /** * All file actions, in the order they should be displayed @@ -209,6 +215,20 @@ enum class FileAction( return result.toList() } + fun getCurrentFolderActionsToHide(folder: OCFile): List { + val currentFolderActions = setOf( + R.id.action_send_share_file, + R.id.action_favorite, + R.id.action_unset_favorite, + R.id.action_see_details, + R.id.action_sync_file, + R.id.action_encrypted + ) + + return getFileListActionsToHide(setOf(folder)) + + entries.map { it.id }.filterNot { it in currentFolderActions } + } + fun getActionsToHide(files: Set): List { if (files.isEmpty()) return emptyList() diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index 771ce411b314..9ea47476ce89 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -23,7 +23,6 @@ import androidx.core.os.bundleOf import androidx.core.view.isNotEmpty import androidx.core.view.isVisible import androidx.fragment.app.FragmentManager -import androidx.fragment.app.setFragmentResult import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModelProvider import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -320,27 +319,33 @@ class FileActionsBottomSheet : val itemBinding = FileActionsBottomSheetItemBinding.inflate(layoutInflater, binding.fileActionsList, false) .apply { root.setOnClickListener { + action.toggledFavorite()?.let { showAction(it, viewThemeUtils) } viewModel.onClick(action) } - text.setText(action.title) - if (action.icon != null) { - val drawable = - viewThemeUtils.platform.tintDrawable( - requireContext(), - AppCompatResources.getDrawable(requireContext(), action.icon)!! - ) - icon.setImageDrawable(drawable) - } + showAction(action, viewThemeUtils) } return itemBinding.root } private fun dispatchActionClick(id: Int?) { - if (id != null) { - setFragmentResult(REQUEST_KEY, bundleOf(RESULT_KEY_ACTION_ID to id)) - parentFragmentManager.clearFragmentResultListener(REQUEST_KEY) + if (id == null) { + return + } + + // get the manager and dismiss before sending, as the result can replace the fragment hosting this sheet + val fragmentManager = parentFragmentManager + val isFavoriteToggle = id == R.id.action_favorite || id == R.id.action_unset_favorite + if (!isFavoriteToggle) { dismiss() } + + fragmentManager.setFragmentResult(REQUEST_KEY, bundleOf(RESULT_KEY_ACTION_ID to id)) + fragmentManager.clearFragmentResultListener(REQUEST_KEY) + + if (isFavoriteToggle) { + val delay = resources.getInteger(android.R.integer.config_mediumAnimTime).toLong() + binding.root.postDelayed({ dismissAllowingStateLoss() }, delay) + } } companion object { @@ -382,3 +387,15 @@ class FileActionsBottomSheet : } } } + +private fun FileActionsBottomSheetItemBinding.showAction(action: FileAction, viewThemeUtils: ViewThemeUtils) { + text.setText(action.title) + if (action.icon != null) { + val context = root.context + val drawable = viewThemeUtils.platform.tintDrawable( + context, + AppCompatResources.getDrawable(context, action.icon)!! + ) + icon.setImageDrawable(drawable) + } +} 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 af7ac237f9d9..8fc39287dd64 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 @@ -369,6 +369,7 @@ class FileDisplayActivity : private fun initUI() { setupHomeSearchToolbarWithSortAndListButtons() mMenuButton.setOnClickListener { v: View? -> openDrawer() } + findViewById(R.id.toolbar).setOnClickListener { openCurrentFolderActions() } mSwitchAccountButton.setOnClickListener { v: View? -> showManageAccountsDialog() } mNotificationButton.setOnClickListener { pushFragment(NavigatorScreen.Notifications) @@ -950,9 +951,24 @@ class FileDisplayActivity : } } + menu?.findItem(R.id.action_current_folder_actions)?.isVisible = canShowCurrentFolderActions() + return super.onPrepareOptionsMenu(menu) } + private fun canShowCurrentFolderActions(): Boolean = leftFragment is OCFileListFragment && + !isDrawerOpen && + !isSearchOpen() && + !isRoot(getCurrentDir()) && + listOfFilesFragment?.isSearchFragment == false && + !isAlbumItemsFragment + + private fun openCurrentFolderActions() { + if (canShowCurrentFolderActions()) { + listOfFilesFragment?.openCurrentFolderActionsMenu() + } + } + override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.activity_file_display, menu) @@ -1355,6 +1371,11 @@ class FileDisplayActivity : true } + R.id.action_current_folder_actions -> { + openCurrentFolderActions() + true + } + else -> super.onOptionsItemSelected(item) } @@ -1886,6 +1907,10 @@ class FileDisplayActivity : Log_OC.d(TAG, "download worker finished") val folder = getFolderFromFolderDownloadWorker(intent) ?: return updateFileDownloadIndicator(FileDownloadIndicator.Downloaded, folder) + + if (folder.fileId == getCurrentDir()?.fileId) { + updateListOfFilesFragment() + } } } // endregion @@ -2038,6 +2063,8 @@ class FileDisplayActivity : val detailFragment: Fragment = FileDetailFragment.newInstance(file, currentUser, activeTab) setLeftFragment(detailFragment, false) + // swap now, so no frame shows the list without its sort row + supportFragmentManager.executePendingTransactions() configureToolbarForPreview(file) } @@ -2073,6 +2100,7 @@ class FileDisplayActivity : chosenFile = file // if no file is passed, current file decides } super.updateActionBarTitleAndHomeButton(chosenFile) + supportInvalidateOptionsMenu() } override fun isDrawerIndicatorAvailable(): Boolean = isRoot(getCurrentDir()) @@ -2291,7 +2319,9 @@ class FileDisplayActivity : resetScrollingAndUpdateActionBar() } - if (leftFragment is OCFileListFragment && !operation.onlyLocalCopy) { + if (leftFragment is OCFileListFragment && operation.onlyLocalCopy) { + leftFragment.adapter?.notifyItemChanged(removedFile) + } else if (leftFragment is OCFileListFragment) { leftFragment.adapter?.removeFile(removedFile) if (leftFragment.adapter?.isEmpty == true) { 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 4133be999632..a0d09f008656 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 @@ -268,6 +268,11 @@ public void setFavoriteAttributeForItemID(String remotePath, boolean favorite, b } } + if (currentDirectory != null && currentDirectory.getRemotePath().equals(remotePath)) { + currentDirectory.setFavorite(favorite); + mStorageManager.saveFile(currentDirectory); + } + final OCFile updatedFile = changedFile; new Handler(Looper.getMainLooper()).post(() -> { List sortedFiles = differ.sortForCurrentView(new ArrayList<>(differ.getLatestFiles()), 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 41f802839c49..3d6060dfb8fc 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 @@ -746,6 +746,27 @@ public void openActionsMenu(final int filesCount, final Set checkedFiles }); } + public void openCurrentFolderActionsMenu() { + final OCFile currentFolder = getCurrentFile(); + if (currentFolder == null || currentFolder.isRootDirectory()) { + return; + } + + final Set checkedFiles = new HashSet<>(); + checkedFiles.add(currentFolder); + + throttler.run("overflowClick", () -> { + final var actionsToHide = FileAction.Companion.getCurrentFolderActionsToHide(currentFolder); + final var childFragmentManager = getChildFragmentManager(); + final var actionBottomSheet = FileActionsBottomSheet.newInstance(currentFolder, true, actionsToHide) + .setResultListener(childFragmentManager, this, (id) -> onFileActionChosen(id, checkedFiles)); + + if (FragmentExtensionsKt.isDialogFragmentReady(this)) { + actionBottomSheet.show(childFragmentManager, "actions"); + } + }); + } + @Override public void newDocument() { ChooseRichDocumentsTemplateDialogFragment.newInstance(mFile, diff --git a/app/src/main/res/menu/activity_file_display.xml b/app/src/main/res/menu/activity_file_display.xml index 023f81739ca1..c81caf65f3ca 100644 --- a/app/src/main/res/menu/activity_file_display.xml +++ b/app/src/main/res/menu/activity_file_display.xml @@ -18,6 +18,13 @@ app:actionViewClass="androidx.appcompat.widget.SearchView" app:showAsAction="ifRoom" /> + +