diff --git a/opencloudApp/src/main/java/eu/opencloud/android/extensions/FileMenuOptionExt.kt b/opencloudApp/src/main/java/eu/opencloud/android/extensions/FileMenuOptionExt.kt index 57491071e2..a3669ca26a 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/extensions/FileMenuOptionExt.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/extensions/FileMenuOptionExt.kt @@ -40,6 +40,7 @@ fun FileMenuOption.toResId() = FileMenuOption.SEND -> R.id.action_send_file FileMenuOption.SET_AV_OFFLINE -> R.id.action_set_available_offline FileMenuOption.UNSET_AV_OFFLINE -> R.id.action_unset_available_offline + FileMenuOption.ADD_TO_HOME_SCREEN -> R.id.action_add_to_home } fun FileMenuOption.toStringResId() = @@ -59,6 +60,7 @@ fun FileMenuOption.toStringResId() = FileMenuOption.SEND -> R.string.actionbar_send_file FileMenuOption.SET_AV_OFFLINE -> R.string.set_available_offline FileMenuOption.UNSET_AV_OFFLINE -> R.string.unset_available_offline + FileMenuOption.ADD_TO_HOME_SCREEN -> R.string.add_to_home_screen } fun FileMenuOption.toDrawableResId() = @@ -78,4 +80,5 @@ fun FileMenuOption.toDrawableResId() = FileMenuOption.SEND -> R.drawable.ic_send_white FileMenuOption.SET_AV_OFFLINE -> R.drawable.ic_action_set_available_offline FileMenuOption.UNSET_AV_OFFLINE -> R.drawable.ic_action_unset_available_offline + FileMenuOption.ADD_TO_HOME_SCREEN -> R.drawable.ic_action_add_to_home } diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/addtohomescreen/AddToHomeScreenDialogFragment.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/addtohomescreen/AddToHomeScreenDialogFragment.kt new file mode 100644 index 0000000000..d718637692 --- /dev/null +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/addtohomescreen/AddToHomeScreenDialogFragment.kt @@ -0,0 +1,132 @@ +package eu.opencloud.android.presentation.files.addtohomescreen + +import android.app.Dialog +import android.os.Bundle +import android.view.WindowManager +import android.widget.EditText +import androidx.appcompat.app.AlertDialog +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.widget.doOnTextChanged +import androidx.fragment.app.DialogFragment +import com.google.android.material.textfield.TextInputLayout +import eu.opencloud.android.R +import eu.opencloud.android.domain.files.model.OCFile +import eu.opencloud.android.presentation.files.filelist.MainFileListFragment.Companion.MAX_FILENAME_LENGTH +import eu.opencloud.android.presentation.files.filelist.MainFileListFragment.Companion.forbiddenChars +import eu.opencloud.android.utils.PreferenceUtils + +class AddToHomeScreenDialogFragment : DialogFragment() { + + private lateinit var folder: OCFile + private lateinit var listener: AddToHomeScreenListener + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + folder = requireArguments().getParcelable(ARG_FOLDER)!! + listener = parentFragment as AddToHomeScreenListener + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val inflater = requireActivity().layoutInflater + val view = inflater.inflate(R.layout.edit_box_dialog, null) + + view.filterTouchesWhenObscured = + PreferenceUtils.shouldDisallowTouchesWithOtherVisibleWindows(context) + + val coordinatorLayout: CoordinatorLayout = requireActivity().findViewById(R.id.coordinator_layout) + coordinatorLayout.filterTouchesWhenObscured = + PreferenceUtils.shouldDisallowTouchesWithOtherVisibleWindows(context) + + val inputText: EditText = view.findViewById(R.id.user_input) + val inputLayout: TextInputLayout = view.findViewById(R.id.edit_box_input_text_layout) + + inputText.setText(folder.fileName) + inputText.selectAll() + inputText.requestFocus() + + val builder = AlertDialog.Builder(requireActivity()) + builder.setView(view) + .setPositiveButton(R.string.add_to_home_screen_dialog_add_button) { dialog, _ -> + val name = inputText.text.toString().trim() + if (name.isNotBlank()) { + listener.onAddToHomeScreen(name, folder) + } + dialog.dismiss() + } + .setNegativeButton(android.R.string.cancel, null) + .setTitle(R.string.add_to_home_screen_dialog_title) + + val alertDialog = builder.create() + + alertDialog.setOnShowListener { + val okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) + okButton.isEnabled = inputText.text.isNullOrBlank().not() + + okButton.setOnClickListener { + val name = inputText.text.toString().trim() + val error = when { + name.isBlank() -> getString(R.string.add_to_home_screen_dialog_error_empty) + name.length > MAX_FILENAME_LENGTH -> String.format( + getString(R.string.uploader_upload_text_dialog_filename_error_length_max), + MAX_FILENAME_LENGTH + ) + forbiddenChars.any { name.contains(it) } -> getString(R.string.filename_forbidden_characters) + else -> null + } + + if (error == null) { + listener.onAddToHomeScreen(name, folder) + alertDialog.dismiss() + } else { + inputLayout.error = error + } + } + } + + inputText.doOnTextChanged { text, _, _, _ -> + val okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) + var error: String? = null + + if (text.isNullOrBlank()) { + okButton.isEnabled = false + error = getString(R.string.add_to_home_screen_dialog_error_empty) + } else if (text.length > MAX_FILENAME_LENGTH) { + error = String.format( + getString(R.string.uploader_upload_text_dialog_filename_error_length_max), + MAX_FILENAME_LENGTH + ) + } else if (forbiddenChars.any { text.contains(it) }) { + error = getString(R.string.filename_forbidden_characters) + } else { + okButton.isEnabled = true + } + + if (error != null) { + okButton.isEnabled = false + inputLayout.error = error + } else { + inputLayout.error = null + } + } + + alertDialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) + return alertDialog + } + + interface AddToHomeScreenListener { + fun onAddToHomeScreen(shortcutName: String, folder: OCFile) + } + + companion object { + const val TAG = "ADD_TO_HOME_SCREEN_DIALOG" + private const val ARG_FOLDER = "ARG_FOLDER" + + @JvmStatic + fun newInstance(folder: OCFile): AddToHomeScreenDialogFragment = + AddToHomeScreenDialogFragment().apply { + arguments = Bundle().apply { + putParcelable(ARG_FOLDER, folder) + } + } + } +} diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/addtohomescreen/FolderShortcutHelper.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/addtohomescreen/FolderShortcutHelper.kt new file mode 100644 index 0000000000..d5478012b9 --- /dev/null +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/addtohomescreen/FolderShortcutHelper.kt @@ -0,0 +1,60 @@ +package eu.opencloud.android.presentation.files.addtohomescreen + +import android.content.Context +import android.content.Intent +import android.content.pm.ShortcutInfo +import android.content.pm.ShortcutManager +import android.graphics.drawable.Icon +import android.os.Build +import android.widget.Toast +import androidx.annotation.RequiresApi +import eu.opencloud.android.R +import eu.opencloud.android.domain.files.model.OCFile +import eu.opencloud.android.ui.activity.FileDisplayActivity + +object FolderShortcutHelper { + + const val EXTRA_SHORTCUT_FOLDER_REMOTE_ID = "SHORTCUT_FOLDER_REMOTE_ID" + const val EXTRA_SHORTCUT_FOLDER_REMOTE_PATH = "SHORTCUT_FOLDER_REMOTE_PATH" + const val EXTRA_SHORTCUT_FOLDER_SPACE_ID = "SHORTCUT_FOLDER_SPACE_ID" + const val ACTION_OPEN_SHORTCUT = + "eu.opencloud.android.ui.activity.action.OPEN_SHORTCUT" + + fun createPinnedShortcut(context: Context, folder: OCFile, shortcutName: String) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createPinnedShortcutApi26(context, folder, shortcutName) + } else { + Toast.makeText(context, context.getString(R.string.add_to_home_screen_shortcut_added), Toast.LENGTH_SHORT).show() + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun createPinnedShortcutApi26(context: Context, folder: OCFile, shortcutName: String) { + val shortcutManager = context.getSystemService(ShortcutManager::class.java) + + if (shortcutManager?.isRequestPinShortcutSupported != true) { + Toast.makeText(context, context.getString(R.string.add_to_home_screen_shortcut_added), Toast.LENGTH_SHORT).show() + return + } + + val shortcutId = "folder_${folder.id}" + + val shortcutIntent = Intent(context, FileDisplayActivity::class.java).apply { + action = ACTION_OPEN_SHORTCUT + putExtra(EXTRA_SHORTCUT_FOLDER_REMOTE_ID, folder.remoteId) + putExtra(EXTRA_SHORTCUT_FOLDER_REMOTE_PATH, folder.remotePath) + putExtra(EXTRA_SHORTCUT_FOLDER_SPACE_ID, folder.spaceId) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + } + + val shortcut = ShortcutInfo.Builder(context, shortcutId) + .setShortLabel(shortcutName) + .setLongLabel(shortcutName) + .setIcon(Icon.createWithResource(context, R.mipmap.icon)) + .setIntent(shortcutIntent) + .build() + + shortcutManager.requestPinShortcut(shortcut, null) + Toast.makeText(context, context.getString(R.string.add_to_home_screen_shortcut_added), Toast.LENGTH_SHORT).show() + } +} diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt index 21acbf63bb..a0994b69af 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt @@ -107,6 +107,8 @@ import eu.opencloud.android.presentation.files.SortType import eu.opencloud.android.presentation.files.ViewType import eu.opencloud.android.presentation.files.createfolder.CreateFolderDialogFragment import eu.opencloud.android.presentation.files.createshortcut.CreateShortcutDialogFragment +import eu.opencloud.android.presentation.files.addtohomescreen.AddToHomeScreenDialogFragment +import eu.opencloud.android.presentation.files.addtohomescreen.FolderShortcutHelper import eu.opencloud.android.presentation.files.operations.FileOperation import eu.opencloud.android.presentation.files.operations.FileOperationsViewModel import eu.opencloud.android.presentation.files.removefile.RemoveFilesDialogFragment @@ -138,7 +140,8 @@ class MainFileListFragment : Fragment(), SortDialogListener, SortOptionsView.CreateFolderListener, SortOptionsView.SortOptionsListener, - CreateShortcutDialogFragment.CreateShortcutListener { + CreateShortcutDialogFragment.CreateShortcutListener, + AddToHomeScreenDialogFragment.AddToHomeScreenListener { private val mainFileListViewModel by viewModel { parametersOf( @@ -737,6 +740,13 @@ class MainFileListFragment : Fragment(), FileMenuOption.UNSET_AV_OFFLINE -> { fileOperationsViewModel.performOperation(FileOperation.UnsetFilesAsAvailableOffline(listOf(file))) } + + FileMenuOption.ADD_TO_HOME_SCREEN -> { + if (file.isFolder) { + val dialog = AddToHomeScreenDialogFragment.newInstance(file) + dialog.show(childFragmentManager, DIALOG_ADD_TO_HOME_SCREEN) + } + } } dialog.hide() dialog.dismiss() @@ -1276,6 +1286,10 @@ class MainFileListFragment : Fragment(), uploadActions?.uploadShortcutFileFromApp(arrayOf(shortcutFilePath)) } + override fun onAddToHomeScreen(shortcutName: String, folder: OCFile) { + FolderShortcutHelper.createPinnedShortcut(requireContext(), folder, shortcutName) + } + override fun onFolderNameSet(newFolderName: String, parentFolder: OCFile) { fileOperationsViewModel.performOperation(FileOperation.CreateFolder(newFolderName, parentFolder)) fileOperationsViewModel.createFolder.observe(viewLifecycleOwner, Event.EventObserver { uiResult: UIResult -> @@ -1633,6 +1647,7 @@ class MainFileListFragment : Fragment(), private const val DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER" private const val DIALOG_CREATE_SHORTCUT = "DIALOG_CREATE_SHORTCUT" + private const val DIALOG_ADD_TO_HOME_SCREEN = "DIALOG_ADD_TO_HOME_SCREEN" private const val FILE_DOCXF_EXTENSION = "docxf" diff --git a/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt b/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt index a4c9c95f16..d0524a568e 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt @@ -201,6 +201,7 @@ class FileDisplayActivity : FileActivity(), private var isLightUser = false private var isMultiPersonal = false + private var shortcutFolderToNavigate: OCFile? = null override fun onCreate(savedInstanceState: Bundle?) { Timber.v("onCreate() start") @@ -216,6 +217,7 @@ class FileDisplayActivity : FileActivity(), localBroadcastManager = LocalBroadcastManager.getInstance(this) handleDeepLink() + handleShortcutIntent() /// Load of saved instance state if (savedInstanceState != null) { @@ -348,7 +350,17 @@ class FileDisplayActivity : FileActivity(), }) isLightUser = manageAccountsViewModel.checkUserLight(account.name) isMultiPersonal = capabilitiesViewModel.checkMultiPersonal() - navigateTo(fileListOption, initialState = true) + + if (shortcutFolderToNavigate != null) { + fileListOption = FileListOption.ALL_FILES + setFile(shortcutFolderToNavigate) + initAndShowListOfFiles(fileListOption) + refreshListOfFilesFragment() + updateToolbar(shortcutFolderToNavigate) + shortcutFolderToNavigate = null + } else { + navigateTo(fileListOption, initialState = true) + } } @@ -1966,6 +1978,25 @@ class FileDisplayActivity : FileActivity(), } } + private fun handleShortcutIntent() { + val sc = eu.opencloud.android.presentation.files.addtohomescreen.FolderShortcutHelper + if (intent?.action != sc.ACTION_OPEN_SHORTCUT) return + + val shortcutRemotePath = intent?.getStringExtra(sc.EXTRA_SHORTCUT_FOLDER_REMOTE_PATH) + val shortcutSpaceId = intent?.getStringExtra(sc.EXTRA_SHORTCUT_FOLDER_SPACE_ID) + if (shortcutRemotePath != null) { + val file = storageManager.getFileByPath(shortcutRemotePath, shortcutSpaceId) + if (file != null) { + shortcutFolderToNavigate = file + } else { + showMessageInSnackbar(R.id.list_layout, getString(R.string.default_error_msg)) + } + } + intent?.removeExtra(sc.EXTRA_SHORTCUT_FOLDER_REMOTE_ID) + intent?.removeExtra(sc.EXTRA_SHORTCUT_FOLDER_REMOTE_PATH) + intent?.removeExtra(sc.EXTRA_SHORTCUT_FOLDER_SPACE_ID) + } + private fun onDeepLinkManaged() { collectLatestLifecycleFlow(fileOperationsViewModel.deepLinkFlow) { it?.getContentIfNotHandled()?.let { uiResult -> diff --git a/opencloudApp/src/main/java/eu/opencloud/android/usecases/files/FilterFileMenuOptionsUseCase.kt b/opencloudApp/src/main/java/eu/opencloud/android/usecases/files/FilterFileMenuOptionsUseCase.kt index 416e567b61..7554d853ff 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/usecases/files/FilterFileMenuOptionsUseCase.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/usecases/files/FilterFileMenuOptionsUseCase.kt @@ -37,27 +37,43 @@ class FilterFileMenuOptionsUseCase( private val getSpaceWithSpecialsByIdForAccountUseCase: GetSpaceWithSpecialsByIdForAccountUseCase, ) : BaseUseCase, FilterFileMenuOptionsUseCase.Params>() { override fun run(params: Params): MutableList { - val optionsToShow = mutableListOf() val files = params.files - if (files.isEmpty()) { return mutableListOf() } + val state = buildMenuState(params) + return buildMenuOptions(files, params, state) + } + private data class MenuState( + val isAnyFileSynchronizing: Boolean, + val isAnyFileVideoStreaming: Boolean, + val hasRenamePermission: Boolean, + val hasMovePermission: Boolean, + val hasRemovePermission: Boolean, + val hasResharePermission: Boolean, + val isPersonalSpace: Boolean, + val resharingAllowed: Boolean, + ) + + private fun buildMenuState(params: Params): MenuState { + val files = params.files val filesSyncInfo = params.filesSyncInfo val capability = capabilityRepository.getStoredCapabilities(params.accountName) - val space = getSpaceWithSpecialsByIdForAccountUseCase(GetSpaceWithSpecialsByIdForAccountUseCase.Params( - spaceId = files.first().spaceId, - accountName = params.accountName, - )) - + val space = getSpaceWithSpecialsByIdForAccountUseCase( + GetSpaceWithSpecialsByIdForAccountUseCase.Params( + spaceId = files.first().spaceId, + accountName = params.accountName, + ) + ) val isAnyFileSynchronizing: Boolean = if (filesSyncInfo.isEmpty()) { anyFileSynchronizingLookingIntoWorkers(files, params.accountName) } else { anyFileSynchronizingLookingIIntoFilesSyncInfo(filesSyncInfo) } val isAnyFileVideoPreviewing = params.isAnyFileVideoPreviewing - val isAnyFileVideoStreaming = isAnyFileVideoPreviewing && !anyFileDownloaded(files) + val isAnyFileVideoStreaming = + isAnyFileVideoPreviewing && !anyFileDownloaded(files) val hasRenamePermission: Boolean = if (isSingleSelection(files)) { files.first().hasRenamePermission } else { @@ -71,86 +87,110 @@ class FilterFileMenuOptionsUseCase( false } val isPersonalSpace = space?.isPersonal ?: true - val resharingAllowed = capability?.let { !anyFileSharedWithMe(files) || it.filesSharingResharing.isTrue } ?: false - val displaySelectAll = params.displaySelectAll - val displaySelectInverse = params.displaySelectInverse - val onlyAvailableOfflineFiles = params.onlyAvailableOfflineFiles - val onlySharedByLinkFiles = params.onlySharedByLinkFiles - val shareViaLinkAllowed = params.shareViaLinkAllowed - val shareWithUsersAllowed = params.shareWithUsersAllowed - val sendAllowed = params.sendAllowed - - val noSyncAndPreviewing = !isAnyFileSynchronizing && !isAnyFileVideoPreviewing - val noSyncAndStreaming = !isAnyFileSynchronizing && !isAnyFileVideoStreaming - val shareViaLinkOrWithUsersAllowed = shareViaLinkAllowed || shareWithUsersAllowed - val noFilesDownloadedOrIsSingleFile = allFilesDownloaded(files) || isSingleFile(files) - - // Select all - if (displaySelectAll) { + val resharingAllowed = capability?.let { + !anyFileSharedWithMe(files) || it.filesSharingResharing.isTrue + } ?: false + return MenuState( + isAnyFileSynchronizing = isAnyFileSynchronizing, + isAnyFileVideoStreaming = isAnyFileVideoStreaming, + hasRenamePermission = hasRenamePermission, + hasMovePermission = hasMovePermission, + hasRemovePermission = hasRemovePermission, + hasResharePermission = hasResharePermission, + isPersonalSpace = isPersonalSpace, + resharingAllowed = resharingAllowed, + ) + } + + private fun buildMenuOptions( + files: List, + params: Params, + state: MenuState, + ): MutableList { + val optionsToShow = mutableListOf() + val noSyncAndPreviewing = + !state.isAnyFileSynchronizing && !params.isAnyFileVideoPreviewing + val noSyncAndStreaming = + !state.isAnyFileSynchronizing && !state.isAnyFileVideoStreaming + val shareViaLinkOrWithUsersAllowed = + params.shareViaLinkAllowed || params.shareWithUsersAllowed + val noFilesDownloadedOrIsSingleFile = + allFilesDownloaded(files) || isSingleFile(files) + + if (params.displaySelectAll) { optionsToShow.add(FileMenuOption.SELECT_ALL) } - // Select inverse - if (displaySelectInverse) { + if (params.displaySelectInverse) { optionsToShow.add(FileMenuOption.SELECT_INVERSE) } - // Share - if (!onlyAvailableOfflineFiles && shareViaLinkOrWithUsersAllowed && resharingAllowed && - isPersonalSpace && hasResharePermission) { + if (!params.onlyAvailableOfflineFiles && shareViaLinkOrWithUsersAllowed && + state.resharingAllowed && state.isPersonalSpace && + state.hasResharePermission + ) { optionsToShow.add(FileMenuOption.SHARE) } - // Open with (different to preview!) - if (!isAnyFileSynchronizing && isSingleFile(files)) { + if (!state.isAnyFileSynchronizing && isSingleFile(files)) { optionsToShow.add(FileMenuOption.OPEN_WITH) } - // Download - if (noSyncAndPreviewing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles && - !anyFolder(files) && !anyFileDownloaded(files)) { + if (noSyncAndPreviewing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles && !anyFolder(files) && + !anyFileDownloaded(files) + ) { optionsToShow.add(FileMenuOption.DOWNLOAD) } - // Synchronize - if (!isAnyFileSynchronizing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles && - (anyFileDownloaded(files) || anyFolder(files))) { + if (!state.isAnyFileSynchronizing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles && + (anyFileDownloaded(files) || anyFolder(files)) + ) { optionsToShow.add(FileMenuOption.SYNC) } - // Cancel sync - if (isAnyFileSynchronizing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles && !anyAvailableOfflineFile(files)) { + if (state.isAnyFileSynchronizing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles && + !anyAvailableOfflineFile(files) + ) { optionsToShow.add(FileMenuOption.CANCEL_SYNC) } - // Rename - if (noSyncAndPreviewing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles && - hasRenamePermission) { + if (noSyncAndPreviewing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles && state.hasRenamePermission + ) { optionsToShow.add(FileMenuOption.RENAME) } - // Move - if (noSyncAndPreviewing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles && - hasMovePermission) { + if (noSyncAndPreviewing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles && state.hasMovePermission + ) { optionsToShow.add(FileMenuOption.MOVE) } - // Copy - if (noSyncAndPreviewing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles) { + if (noSyncAndPreviewing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles + ) { optionsToShow.add(FileMenuOption.COPY) } - // Send - if (noSyncAndStreaming && !onlyAvailableOfflineFiles && !anyFolder(files) && - noFilesDownloadedOrIsSingleFile && sendAllowed) { + if (noSyncAndStreaming && !params.onlyAvailableOfflineFiles && + !anyFolder(files) && noFilesDownloadedOrIsSingleFile && + params.sendAllowed + ) { optionsToShow.add(FileMenuOption.SEND) } - // Set as available offline - if (!isAnyFileSynchronizing && anyNotAvailableOfflineFile(files) && !isAnyFileVideoStreaming) { + if (!state.isAnyFileSynchronizing && + anyNotAvailableOfflineFile(files) && + !state.isAnyFileVideoStreaming + ) { optionsToShow.add(FileMenuOption.SET_AV_OFFLINE) } - // Unset as available offline - if (anyAvailableOfflineFile(files) && !isAnyFileVideoStreaming) { + if (anyAvailableOfflineFile(files) && !state.isAnyFileVideoStreaming) { optionsToShow.add(FileMenuOption.UNSET_AV_OFFLINE) } - // Details if (isSingleFile(files)) { optionsToShow.add(FileMenuOption.DETAILS) } - // Remove - if (!isAnyFileSynchronizing && !onlyAvailableOfflineFiles && !onlySharedByLinkFiles && hasRemovePermission) { + if (!state.isAnyFileSynchronizing && !params.onlyAvailableOfflineFiles && + !params.onlySharedByLinkFiles && state.hasRemovePermission + ) { optionsToShow.add(FileMenuOption.REMOVE) } + if (isSingleSelection(files) && anyFolder(files)) { + optionsToShow.add(FileMenuOption.ADD_TO_HOME_SCREEN) + } return optionsToShow } diff --git a/opencloudApp/src/main/res/drawable/ic_action_add_to_home.xml b/opencloudApp/src/main/res/drawable/ic_action_add_to_home.xml new file mode 100644 index 0000000000..45624f5f44 --- /dev/null +++ b/opencloudApp/src/main/res/drawable/ic_action_add_to_home.xml @@ -0,0 +1,9 @@ + + + diff --git a/opencloudApp/src/main/res/menu/file_actions_menu.xml b/opencloudApp/src/main/res/menu/file_actions_menu.xml index c5ad8eeeec..c9c0a625a4 100644 --- a/opencloudApp/src/main/res/menu/file_actions_menu.xml +++ b/opencloudApp/src/main/res/menu/file_actions_menu.xml @@ -110,5 +110,11 @@ android:icon="@drawable/ic_action_delete_white" app:showAsAction="ifRoom" android:orderInCategory="1" /> + diff --git a/opencloudApp/src/main/res/values/strings.xml b/opencloudApp/src/main/res/values/strings.xml index 0a4de8366d..ede9aeb7da 100644 --- a/opencloudApp/src/main/res/values/strings.xml +++ b/opencloudApp/src/main/res/values/strings.xml @@ -862,4 +862,10 @@ Added text labels on bottom bar Text labels were added and default active indicator is used to show which section is selected on the bottom bar + Add to Home screen + Add to Home screen + Add + The name cannot be empty + Shortcut added to Home screen + diff --git a/opencloudDomain/src/main/java/eu/opencloud/android/domain/files/model/FileMenuOption.kt b/opencloudDomain/src/main/java/eu/opencloud/android/domain/files/model/FileMenuOption.kt index 3ea6b6cd36..8983a045db 100644 --- a/opencloudDomain/src/main/java/eu/opencloud/android/domain/files/model/FileMenuOption.kt +++ b/opencloudDomain/src/main/java/eu/opencloud/android/domain/files/model/FileMenuOption.kt @@ -22,5 +22,6 @@ package eu.opencloud.android.domain.files.model enum class FileMenuOption { SELECT_ALL, SELECT_INVERSE, DOWNLOAD, RENAME, MOVE, COPY, REMOVE, OPEN_WITH, - SYNC, CANCEL_SYNC, SHARE, DETAILS, SEND, SET_AV_OFFLINE, UNSET_AV_OFFLINE; + SYNC, CANCEL_SYNC, SHARE, DETAILS, SEND, SET_AV_OFFLINE, UNSET_AV_OFFLINE, + ADD_TO_HOME_SCREEN; }