diff --git a/app/src/main/java/com/infomaniak/drive/data/api/ErrorCode.kt b/app/src/main/java/com/infomaniak/drive/data/api/ErrorCode.kt index 610fd648c0..b7e040c4ed 100644 --- a/app/src/main/java/com/infomaniak/drive/data/api/ErrorCode.kt +++ b/app/src/main/java/com/infomaniak/drive/data/api/ErrorCode.kt @@ -42,6 +42,7 @@ object ErrorCode { const val SHARE_LINK_ALREADY_EXISTS = "file_share_link_already_exists" const val STILL_UPLOADING_ERROR = "still_uploading_error" const val YOU_MUST_ADD_AT_LEAST_ONE_FILE = "you_must_add_at_least_one_file" + const val CONFLICT_PART_OF_THE_SAME_SUBTREE = "conflict_part_of_the_same_subtree_error" val apiErrorCodes = listOf( ApiErrorCode(CATEGORY_ALREADY_EXISTS, R.string.errorCategoryAlreadyExists), @@ -63,5 +64,6 @@ object ErrorCode { ApiErrorCode(SHARE_LINK_ALREADY_EXISTS, R.string.errorShareLink), ApiErrorCode(STILL_UPLOADING_ERROR, R.string.errorStillUploading), ApiErrorCode(YOU_MUST_ADD_AT_LEAST_ONE_FILE, R.string.errorDownloadPermission), + ApiErrorCode(CONFLICT_PART_OF_THE_SAME_SUBTREE, R.string.errorConflictPartOfTheSameSubtree) ) } diff --git a/app/src/main/java/com/infomaniak/drive/ui/MainViewModel.kt b/app/src/main/java/com/infomaniak/drive/ui/MainViewModel.kt index 2cf255b211..fbf1065a67 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/MainViewModel.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/MainViewModel.kt @@ -48,6 +48,7 @@ import com.infomaniak.drive.MatomoDrive.MatomoName import com.infomaniak.drive.MatomoDrive.trackNewElementEvent import com.infomaniak.drive.R import com.infomaniak.drive.data.api.ApiRepository +import com.infomaniak.drive.data.api.ErrorCode import com.infomaniak.drive.data.cache.DriveInfosController import com.infomaniak.drive.data.cache.FileController import com.infomaniak.drive.data.cache.FolderFilesProvider @@ -235,7 +236,7 @@ class MainViewModel( fun createMultiSelectMediator(): MediatorLiveData = MediatorLiveData().apply { - value = MultiSelectMediatorState(numberOfSuccessfulActions = 0, totalOfActions = 0, errorCode = null) + value = MultiSelectMediatorState(numberOfSuccessfulActions = 0, totalOfActions = 0, errorResId = null) } fun updateMultiSelectMediator(mediator: MediatorLiveData): (FileResult) -> Unit = { fileRequest -> @@ -243,11 +244,12 @@ class MainViewModel( if (fileRequest.isSuccess) numberOfSuccessfulActions++ val totalOfActions = mediator.value!!.totalOfActions + 1 + val currentErrorResId = mediator.value!!.errorResId mediator.value = MultiSelectMediatorState( numberOfSuccessfulActions, totalOfActions, - fileRequest.errorCode, + errorResId = currentErrorResId ?: fileRequest.errorResId.takeIf { !fileRequest.isSuccess }, ) } @@ -343,7 +345,17 @@ class MainViewModel( onSuccess?.invoke(file.id) } - emit(FileResult(isSuccess = apiResponse.isSuccess(), errorCode = apiResponse.error?.code)) + emit( + FileResult( + isSuccess = apiResponse.isSuccess(), + errorCode = apiResponse.error?.code, + errorResId = when { + apiResponse.isSuccess() -> null + apiResponse.error?.code == ErrorCode.LIMIT_EXCEEDED_ERROR -> R.string.errorFilesLimitExceeded + else -> apiResponse.translateError(defaultMessage = R.string.errorMove) + }, + ) + ) } fun renameFile(file: File, newName: String) = liveData(Dispatchers.IO) { @@ -479,7 +491,18 @@ class MainViewModel( ) = liveData(Dispatchers.IO) { ApiRepository.duplicateFile(file, destinationId ?: Utils.ROOT_ID).let { apiResponse -> if (apiResponse.isSuccess()) onSuccess?.invoke(apiResponse) - emit(FileResult(isSuccess = apiResponse.isSuccess(), data = apiResponse.data, errorCode = apiResponse.error?.code)) + emit( + FileResult( + isSuccess = apiResponse.isSuccess(), + data = apiResponse.data, + errorCode = apiResponse.error?.code, + errorResId = when { + apiResponse.isSuccess() -> null + apiResponse.error?.code == ErrorCode.LIMIT_EXCEEDED_ERROR -> R.string.errorFilesLimitExceeded + else -> apiResponse.translateError(defaultMessage = R.string.errorDuplicate) + }, + ) + ) } } @@ -731,7 +754,7 @@ class MainViewModel( data class MultiSelectMediatorState( var numberOfSuccessfulActions: Int, var totalOfActions: Int, - var errorCode: String?, + var errorResId: Int? = null, ) companion object { diff --git a/app/src/main/java/com/infomaniak/drive/ui/bottomSheetDialogs/FileInfoActionsBottomSheetDialog.kt b/app/src/main/java/com/infomaniak/drive/ui/bottomSheetDialogs/FileInfoActionsBottomSheetDialog.kt index 05c0d0eb85..b9bdc0561b 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/bottomSheetDialogs/FileInfoActionsBottomSheetDialog.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/bottomSheetDialogs/FileInfoActionsBottomSheetDialog.kt @@ -387,12 +387,7 @@ class FileInfoActionsBottomSheetDialog : EdgeToEdgeBottomSheetDialog(), FileInfo (fileRequest.data as? CancellableAction)?.setDriveAndReturn(currentFile.driveId) ) } else { - val resource = if (fileRequest.errorCode == LIMIT_EXCEEDED_ERROR_CODE) { - R.string.errorFilesLimitExceeded - } else { - R.string.errorMove - } - + val resource = fileRequest.errorResId ?: R.string.errorMove transmitActionAndPopBack(getString(resource)) } } diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/FavoritesFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/FavoritesFragment.kt index 49cd067a25..d9cc996640 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/FavoritesFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/FavoritesFragment.kt @@ -20,6 +20,7 @@ package com.infomaniak.drive.ui.fileList import android.os.Bundle import android.view.View import androidx.core.view.isGone +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.swiperefreshlayout.widget.SwipeRefreshLayout @@ -44,6 +45,7 @@ class FavoritesFragment : FileListFragment() { override val noItemsRootTitle = R.string.favoritesNoFile private val navigationArgs: FavoritesFragmentArgs by navArgs() + private val selectFolderViewModel: SelectFolderActivity.SelectFolderViewModel by activityViewModels() override val fileIdToPreview: Int get() = navigationArgs.previewFileId override fun initSwipeRefreshLayout(): SwipeRefreshLayout = binding.swipeRefreshLayout @@ -68,6 +70,9 @@ class FavoritesFragment : FileListFragment() { private fun setupAdapter() { fileAdapter.apply { isSelectingFolder = requireActivity() is SelectFolderActivity + disabledNavigationFolderIds = selectFolderViewModel.disabledNavigationFolderIds + disabledNavigationParentFolderId = selectFolderViewModel.disabledNavigationParentFolderId + exceptedNavigationFolderIds = selectFolderViewModel.exceptedNavigationFolderIds onEmptyList = { changeNoFilesLayoutVisibility(hideFileList = true, changeControlsVisibility = false) } onFileClicked = { file -> diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/FileAdapter.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/FileAdapter.kt index 439abec792..de6794d773 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/FileAdapter.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/FileAdapter.kt @@ -75,6 +75,9 @@ open class FileAdapter( var onStopUploadButtonClicked: ((fileName: String) -> Unit)? = null var isSelectingFolder = false + var disabledNavigationFolderIds: Set = emptySet() + var disabledNavigationParentFolderId: Int? = null + var exceptedNavigationFolderIds: Set = emptySet() var showShareFileButton = true var viewHolderType: DisplayType = DisplayType.LIST var uploadInProgress = false @@ -414,29 +417,36 @@ open class FileAdapter( fun contains(fileName: String) = fileList.any { it.name == fileName } - private fun FileItemViewHolder.checkIfEnableFile(file: File) = when { - uploadInProgress -> { - if (file.isPendingUploadFolder()) { - fileDate?.text = file.path - } else { - val enable = file.currentProgress > 0 && binding.context.isSyncActive() - val title = when { - enable -> R.string.uploadInProgressTitle - pendingWifiConnection -> R.string.uploadNetworkErrorWifiRequired - else -> R.string.uploadInProgressPending - } - fileDate?.setText(title) - } + private fun FileItemViewHolder.checkIfEnableFile(file: File) { + if (uploadInProgress) { + displayUploadStatus(file) + } else if (isSelectingFolder || offlineMode) { + enabledFile(file.isNavigableFolder() || (offlineMode && file.isOffline)) + } else { + enabledFile() } - else -> { - if (isSelectingFolder || offlineMode) { - enabledFile(file.isFolder() || (offlineMode && file.isOffline)) - } else { - enabledFile() + } + + private fun FileItemViewHolder.displayUploadStatus(file: File) { + if (file.isPendingUploadFolder()) { + fileDate?.text = file.path + } else { + val enable = file.currentProgress > 0 && binding.context.isSyncActive() + val title = when { + enable -> R.string.uploadInProgressTitle + pendingWifiConnection -> R.string.uploadNetworkErrorWifiRequired + else -> R.string.uploadInProgressPending } + fileDate?.setText(title) } } + private fun File.isNavigableFolder(): Boolean { + val isMovedChildOfSource = parentId == disabledNavigationParentFolderId + && id !in exceptedNavigationFolderIds + return isFolder() && id !in disabledNavigationFolderIds && !isMovedChildOfSource + } + private fun FileItemViewHolder.enabledFile(enable: Boolean = true) { disabledView.isGone = enable cardView.isEnabled = enable diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderActivity.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderActivity.kt index bad2bcf8b7..9dac1bd12c 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderActivity.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderActivity.kt @@ -63,7 +63,10 @@ class SelectFolderActivity : BaseActivity() { val driveId = navigationArgs.driveId val customArgs = navigationArgs.customArgs val currentFolderId = navigationArgs.folderId.getIntOrNull() - val disabledFolderId = navigationArgs.disabledFolderId.getIntOrNull() + val disabledDestinationFolderId = navigationArgs.disabledDestinationFolderId.getIntOrNull() + val disabledNavigationFolderIdsArg = navigationArgs.disabledNavigationFolderIds?.toSet() ?: emptySet() + val disabledNavigationParentFolderIdArg = navigationArgs.disabledNavigationParentFolderId.getIntOrNull() + val exceptedNavigationFolderIdsArg = navigationArgs.exceptedNavigationFolderIds?.toSet() ?: emptySet() // We're doing this in the mainthread because the FileListFragment rely on mainViewModel.selectFolderUserDrive. // Moving this call in a background thread we'll break everything @@ -75,7 +78,10 @@ class SelectFolderActivity : BaseActivity() { selectFolderViewModel.apply { userDrive = currentUserDrive currentDrive = DriveInfosController.getDrive(userId, driveId) - disableSelectedFolderId = disabledFolderId + disableSelectedFolderId = disabledDestinationFolderId + disabledNavigationFolderIds = disabledNavigationFolderIdsArg + disabledNavigationParentFolderId = disabledNavigationParentFolderIdArg + exceptedNavigationFolderIds = exceptedNavigationFolderIdsArg } navController.setGraph( @@ -187,6 +193,9 @@ class SelectFolderActivity : BaseActivity() { var userDrive: UserDrive? = null var currentDrive: Drive? = null var disableSelectedFolderId: Int? = null + var disabledNavigationFolderIds: Set = emptySet() + var disabledNavigationParentFolderId: Int? = null + var exceptedNavigationFolderIds: Set = emptySet() fun getFolderName(folderId: Int): String { val selectedFolderName = if (folderId == ROOT_ID) { diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderFragment.kt index de55f9234a..711cb99be1 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectFolderFragment.kt @@ -1,6 +1,6 @@ /* * Infomaniak kDrive - Android - * Copyright (C) 2022-2025 Infomaniak Network SA + * Copyright (C) 2022-2026 Infomaniak Network SA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +21,6 @@ import android.os.Bundle import android.view.View import androidx.activity.addCallback import androidx.fragment.app.activityViewModels -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.infomaniak.core.legacy.utils.safeNavigate @@ -30,7 +29,6 @@ import com.infomaniak.drive.MatomoDrive.MatomoName import com.infomaniak.drive.MatomoDrive.trackNewElementEvent import com.infomaniak.drive.R import com.infomaniak.drive.data.cache.FileController -import com.infomaniak.drive.data.models.Rights import com.infomaniak.drive.ui.fileList.SelectFolderActivity.SelectFolderViewModel import com.infomaniak.drive.utils.Utils import com.infomaniak.drive.utils.Utils.ROOT_ID @@ -79,6 +77,9 @@ class SelectFolderFragment : FileListFragment() { fileAdapter.apply { isSelectingFolder = true + disabledNavigationFolderIds = selectFolderViewModel.disabledNavigationFolderIds + disabledNavigationParentFolderId = selectFolderViewModel.disabledNavigationParentFolderId + exceptedNavigationFolderIds = selectFolderViewModel.exceptedNavigationFolderIds onFileClicked = { file -> if (file.isFolder() && !file.isDisabled()) { fileListViewModel.cancelDownloadFiles() @@ -93,15 +94,7 @@ class SelectFolderFragment : FileListFragment() { } } - lifecycleScope.launchWhenResumed { - with(requireActivity() as SelectFolderActivity) { - showSaveButton() - val currentFolderRights = FileController.getFileById(folderId, userDrive)?.rights ?: Rights() - val enable = folderId != selectFolderViewModel.disableSelectedFolderId - && (currentFolderRights.canMoveInto || currentFolderRights.canCreateFile) - enableSaveButton(enable) - } - } + setupSaveButton() } private fun onBackPressed() { diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectRootFolderFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectRootFolderFragment.kt index 1df72675ab..0cdaf74740 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectRootFolderFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/SelectRootFolderFragment.kt @@ -23,14 +23,17 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isGone import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.NavDirections import androidx.navigation.fragment.navArgs import com.infomaniak.core.fragmentnavigation.safelyNavigate import com.infomaniak.core.ui.view.extension.setMargins +import com.infomaniak.core.ui.view.utils.SnackbarUtils.showSnackbar import com.infomaniak.drive.R import com.infomaniak.drive.data.cache.DriveInfosController +import com.infomaniak.drive.data.cache.FileController import com.infomaniak.drive.data.models.File import com.infomaniak.drive.data.models.UiSettings import com.infomaniak.drive.databinding.CardviewFileListBinding @@ -42,8 +45,10 @@ import com.infomaniak.drive.ui.home.RootFilesFragment.FolderToOpen import com.infomaniak.drive.utils.TypeFolder import com.infomaniak.drive.utils.setFileItem import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class SelectRootFolderFragment : BaseRootFolderFragment() { @@ -52,6 +57,7 @@ class SelectRootFolderFragment : BaseRootFolderFragment() { override val fileListViewModel: FileListViewModel by viewModels() private val selectRootFolderViewModel: SelectRootFolderViewModel by viewModels() + private val selectFolderViewModel: SelectFolderActivity.SelectFolderViewModel by activityViewModels() private val navigationArgs: SelectRootFolderFragmentArgs by navArgs() @@ -144,6 +150,10 @@ class SelectRootFolderFragment : BaseRootFolderFragment() { private suspend fun CardviewFileListBinding.setupRecentFolderView(file: File) { root.isVisible = true + + val isForbiddenDestination = isInsideMovedFolder(file) + disabled.isVisible = isForbiddenDestination + root.setOnClickListener { safelyNavigate( SelectRootFolderFragmentDirections.selectRootFolderFragmentToSelectFolderFragment( @@ -153,9 +163,32 @@ class SelectRootFolderFragment : BaseRootFolderFragment() { ) ) } + disabled.setOnClickListener { showSnackbar(R.string.errorConflictPartOfTheSameSubtree) } + itemViewFile.setFileItem(file = file, typeFolder = TypeFolder.recentFolder) } + private suspend fun isInsideMovedFolder(file: File): Boolean = withContext(Dispatchers.IO) { + val movedFolderIds = selectFolderViewModel.disabledNavigationFolderIds + val movedParentFolderId = selectFolderViewModel.disabledNavigationParentFolderId + if (movedFolderIds.isEmpty() && movedParentFolderId == null) return@withContext false + + FileController.getRealmInstance(navigationArgs.userDrive).use { realm -> + val visitedIds = mutableSetOf() + var current: File? = file + + while (current != null && visitedIds.add(current.id)) { + val isMovedChildOfSource = current.parentId == movedParentFolderId + && current.id !in selectFolderViewModel.exceptedNavigationFolderIds + if (current.id in movedFolderIds || isMovedChildOfSource) return@use true + + current = FileController.getParentFileProxy(current.id, realm = realm) + } + + false + } + } + override fun fileListDirections( folderToOpen: FolderToOpen, ): NavDirections = SelectRootFolderFragmentDirections.selectRootFolderFragmentToSelectFolderFragment( diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/multiSelect/MultiSelectFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/multiSelect/MultiSelectFragment.kt index ca0afabdb5..95ce5e704d 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/multiSelect/MultiSelectFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/multiSelect/MultiSelectFragment.kt @@ -224,8 +224,15 @@ abstract class MultiSelectFragment(private val matomoCategory: MatomoCategory) : ).toBundle() } - fun moveFiles(disabledFolderId: Int?) { - requireContext().moveFileClicked(disabledFolderId, selectFolderResultLauncher, mainViewModel) + fun moveFiles(disabledDestinationFolderId: Int?) = with(multiSelectManager) { + requireContext().moveFileClicked( + disabledDestinationFolderId = disabledDestinationFolderId, + selectFolderResultLauncher = selectFolderResultLauncher, + mainViewModel = mainViewModel, + filesToMove = getValidSelectedItems(), + disabledNavigationParentFolderId = if (isSelectAllOn) currentFolder?.id else null, + exceptedNavigationFolderIds = if (isSelectAllOn) exceptedItemsIds.toIntArray() else null, + ) } fun deleteFiles(allSelectedFilesCount: Int? = null) { @@ -487,7 +494,7 @@ abstract class MultiSelectFragment(private val matomoCategory: MatomoCategory) : ) } else { mediator.value = mediator.value?.let { - MultiSelectMediatorState(it.numberOfSuccessfulActions, it.totalOfActions + 1, it.errorCode) + it.copy(totalOfActions = it.totalOfActions + 1) } } } @@ -549,22 +556,24 @@ abstract class MultiSelectFragment(private val matomoCategory: MatomoCategory) : destinationFolder: File?, dialog: Dialog? = null, ) { - mediator.observe(viewLifecycleOwner) { (success, total, error) -> - if (total == fileCount) { + mediator.observe(viewLifecycleOwner) { state -> + val success = state.numberOfSuccessfulActions + val errorResId = state.errorResId + if (state.totalOfActions == fileCount) { dialog?.dismiss() - handleIndividualActionsResult(success, error, type, destinationFolder) + handleIndividualActionsResult(success, errorResId, type, destinationFolder) } } } private fun handleIndividualActionsResult( success: Int, - errorCode: String?, + errorResId: Int?, type: BulkOperationType, destinationFolder: File?, ) { val title = when { - errorCode == LIMIT_EXCEEDED_ERROR_CODE -> getString(R.string.errorFilesLimitExceeded) + errorResId != null -> getString(errorResId) success == 0 -> getString(R.string.anErrorHasOccurred) type == BulkOperationType.COPY_TO_DRIVE -> getString(R.string.copyToDriveStarted, pendingCopyToDriveData?.fileName) else -> resources.getQuantityString(type.successMessage, success, success, destinationFolder?.name + "/") diff --git a/app/src/main/java/com/infomaniak/drive/ui/fileList/preview/PreviewSliderFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/fileList/preview/PreviewSliderFragment.kt index 95fa3ff7cc..d028b0d7d2 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/fileList/preview/PreviewSliderFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/fileList/preview/PreviewSliderFragment.kt @@ -330,12 +330,7 @@ class PreviewSliderFragment : BasePreviewSliderFragment(), FileInfoActionsView.O mainViewModel.refreshActivities.value = true showSnackbar(getString(R.string.allFileMove, currentFile.name, destinationFolder.name)) } else { - val messageRes = if (fileRequest.errorCode == LIMIT_EXCEEDED_ERROR_CODE) { - R.string.errorFilesLimitExceeded - } else { - R.string.errorMove - } - + val messageRes = fileRequest.errorResId ?: R.string.errorMove showSnackbar(messageRes) } } diff --git a/app/src/main/java/com/infomaniak/drive/ui/menu/GalleryFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/menu/GalleryFragment.kt index 6d86156553..3b8c18194e 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/menu/GalleryFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/menu/GalleryFragment.kt @@ -280,7 +280,7 @@ class GalleryFragment : MultiSelectFragment( override fun getAllSelectedFilesCount(): Int? = null fun onMoveButtonClicked() = with(multiSelectManager.selectedItems) { - moveFiles(disabledFolderId = if (count() == 1) first()?.parentId else null) + moveFiles(disabledDestinationFolderId = if (count() == 1) first()?.parentId else null) } override fun performBulkOperation( diff --git a/app/src/main/java/com/infomaniak/drive/ui/menu/MySharesFragment.kt b/app/src/main/java/com/infomaniak/drive/ui/menu/MySharesFragment.kt index 531d3cb1d6..0c55306e4c 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/menu/MySharesFragment.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/menu/MySharesFragment.kt @@ -19,6 +19,7 @@ package com.infomaniak.drive.ui.menu import android.os.Bundle import android.view.View +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.swiperefreshlayout.widget.SwipeRefreshLayout @@ -42,6 +43,7 @@ class MySharesFragment : FileSubTypeListFragment() { override val noItemsRootTitle = R.string.mySharesNoFile private val navigationArgs: MySharesFragmentArgs by navArgs() + private val selectFolderViewModel: SelectFolderActivity.SelectFolderViewModel by activityViewModels() override val fileIdToPreview: Int get() = navigationArgs.previewFileId override fun initSwipeRefreshLayout(): SwipeRefreshLayout = binding.swipeRefreshLayout @@ -76,6 +78,9 @@ class MySharesFragment : FileSubTypeListFragment() { } } fileAdapter.isSelectingFolder = requireActivity() is SelectFolderActivity + fileAdapter.disabledNavigationFolderIds = selectFolderViewModel.disabledNavigationFolderIds + fileAdapter.disabledNavigationParentFolderId = selectFolderViewModel.disabledNavigationParentFolderId + fileAdapter.exceptedNavigationFolderIds = selectFolderViewModel.exceptedNavigationFolderIds } override fun onMenuButtonClicked( diff --git a/app/src/main/java/com/infomaniak/drive/utils/Utils.kt b/app/src/main/java/com/infomaniak/drive/utils/Utils.kt index 7708329d55..67823a4cbb 100644 --- a/app/src/main/java/com/infomaniak/drive/utils/Utils.kt +++ b/app/src/main/java/com/infomaniak/drive/utils/Utils.kt @@ -22,7 +22,6 @@ import android.content.ActivityNotFoundException import android.content.ComponentName import android.content.Context import android.content.Intent -import android.content.res.Configuration import android.net.Uri import android.view.LayoutInflater import androidx.activity.result.ActivityResultLauncher @@ -229,18 +228,25 @@ object Utils { fun convertGigaByteToBytes(gigaBytes: Double) = (gigaBytes * 1024.0.pow(3)).toLong() fun Context.moveFileClicked( - disabledFolderId: Int?, + disabledDestinationFolderId: Int?, selectFolderResultLauncher: ActivityResultLauncher, mainViewModel: MainViewModel, + filesToMove: List = emptyList(), + disabledNavigationParentFolderId: Int? = null, + exceptedNavigationFolderIds: IntArray? = null, ) { mainViewModel.ignoreSyncOffline = true + val disabledNavigationFolderIds = filesToMove.filter { it.isFolder() }.map { it.id }.toIntArray() Intent(this, SelectFolderActivity::class.java).apply { putExtras( SelectFolderActivityArgs( userId = AccountUtils.currentUserId, driveId = AccountUtils.currentDriveId, - folderId = disabledFolderId ?: -1, - disabledFolderId = disabledFolderId ?: -1, + folderId = disabledDestinationFolderId ?: -1, + disabledDestinationFolderId = disabledDestinationFolderId ?: -1, + disabledNavigationFolderIds = disabledNavigationFolderIds, + disabledNavigationParentFolderId = disabledNavigationParentFolderId ?: -1, + exceptedNavigationFolderIds = exceptedNavigationFolderIds, customArgs = bundleOf( MultiSelectFragment.BULK_OPERATION_CUSTOM_TAG to BulkOperationType.MOVE, SINGLE_OPERATION_CUSTOM_TAG to SingleOperation.MOVE.name, diff --git a/app/src/main/java/com/infomaniak/drive/views/FileInfoActionsView.kt b/app/src/main/java/com/infomaniak/drive/views/FileInfoActionsView.kt index 70934df30d..6952ce539f 100644 --- a/app/src/main/java/com/infomaniak/drive/views/FileInfoActionsView.kt +++ b/app/src/main/java/com/infomaniak/drive/views/FileInfoActionsView.kt @@ -664,7 +664,12 @@ class FileInfoActionsView @JvmOverloads constructor( mainViewModel: MainViewModel ) { trackFileActionEvent(MatomoName.Move) - currentContext.moveFileClicked(folderId, selectFolderResultLauncher, mainViewModel) + currentContext.moveFileClicked( + disabledDestinationFolderId = folderId, + selectFolderResultLauncher = selectFolderResultLauncher, + mainViewModel = mainViewModel, + filesToMove = listOfNotNull(currentFile) + ) } @CallSuper diff --git a/app/src/main/res/navigation/main_navigation.xml b/app/src/main/res/navigation/main_navigation.xml index 875093e78a..5665723e4e 100644 --- a/app/src/main/res/navigation/main_navigation.xml +++ b/app/src/main/res/navigation/main_navigation.xml @@ -426,9 +426,23 @@ android:defaultValue="" app:argType="string" /> + + + Cache-fejl En kategori med samme navn findes allerede Der findes allerede et element med samme navn på dette sted + Flytning ikke mulig: destinationsmappen ligger inden i kildemappen Overførsel til et andet drev mislykkedes Sletningsfejl Utilstrækkelig enhedslagerplads diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 36e1cf192b..4e711eac70 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -263,6 +263,7 @@ Fehler bei der Zwischenspeicherung Eine Kategorie mit dem gleichen Namen existiert bereits An dieser Stelle existiert bereits ein Element mit demselben Namen + Verschieben nicht möglich: Der Zielordner befindet sich im Quellordner Übertragung auf ein anderes Laufwerk fehlgeschlagen Fehler beim Löschen Unzureichender Gerätespeicher diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 4aa4ed7c61..c690f81b1b 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -263,6 +263,7 @@ Σφάλμα προσωρινής αποθήκευσης Υπάρχει ήδη κατηγορία με το ίδιο όνομα Υπάρχει ήδη ένα στοιχείο με το ίδιο όνομα σε αυτήν την τοποθεσία + Η μετακίνηση δεν είναι δυνατή: ο φάκελος προορισμού βρίσκεται μέσα στον φάκελο προέλευσης Η μεταφορά σε άλλη μονάδα δίσκου απέτυχε Σφάλμα διαγραφής Ανεπαρκής αποθήκευση συσκευής diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 47ed96de4f..7f19f7c0f9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -263,6 +263,7 @@ Error al almacenar en caché Una categoría con el mismo nombre ya existe Ya existe un elemento con el mismo nombre en esta ubicación + No es posible mover: la carpeta de destino está dentro de la carpeta de origen La transferencia a otra unidad ha fallado Error al eliminar Almacenamiento insuficiente del dispositivo diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 23103c1606..4d53814a71 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -263,6 +263,7 @@ Välimuistivirhe Luokka samalla nimellä on jo olemassa Samanniminen elementti on jo olemassa tässä sijainnissa + Siirto ei ole käytettävissä: kohdekansio on lähdekansion sisällä Tiedonsiirto toiselle asemalle epäonnistui Poistovirhe Laitteen tallennustila ei riitä diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 38f5770a27..0035e3073f 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -263,6 +263,7 @@ Erreur lors de la mise en cache Une catégorie avec le même nom existe déjà Un élément du même nom existe déjà à cet emplacement + Déplacement impossible : le dossier ciblé se trouve dans le dossier source Le transfert vers un autre drive a échoué Erreur lors de la suppression Stockage de l’appareil insuffisant diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0b52f5328e..086efcb8d4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -263,6 +263,7 @@ Errore durante la memorizzazione nella cache Esiste già una categoria con lo stesso nome Un elemento con lo stesso nome esiste già in questa posizione + Spostamento non disponibile: la cartella di destinazione si trova all’interno della cartella di origine Trasferimento verso un’altra unità non riuscito Errore durante l’eliminazione Memoria del dispositivo insufficiente diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 55f50d7856..3157cda314 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -263,6 +263,7 @@ Feil ved mellomlagring En kategori med samme navn finnes allerede Et element med samme navn finnes allerede på denne plasseringen + Flytting ikke mulig: målmappen ligger inne i kildemappen Overføring til en annen stasjon mislyktes Feil ved sletting Manglende lagringsplass på enheten diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 5a42606585..b85bc06f74 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -263,6 +263,7 @@ Cachingfout Een categorie met dezelfde naam bestaat al Een element met dezelfde naam bestaat al op deze locatie + Verplaatsen niet beschikbaar: de doelmap bevindt zich in de bronmap Overdracht naar een ander station mislukt Verwijderfout Onvoldoende apparaatopslag diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index a7e1a6c545..e25f46b932 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -273,6 +273,7 @@ Błąd buforowania Kategoria o tej samej nazwie już istnieje Element o tej samej nazwie już istnieje w tym miejscu + Przenoszenie niedostępne: folder docelowy znajduje się wewnątrz folderu źródłowego Przesyłanie na inny dysk nie powiodło się Błąd usuwania Niewystarczająca pamięć urządzenia diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index f286b1a41a..43b6c8c769 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -263,6 +263,7 @@ Erro de cache Já existe uma categoria com o mesmo nome Já existe um elemento com o mesmo nome neste local + Não é possível mover: a pasta de destino encontra-se dentro da pasta de origem A transferência para outra unidade falhou Erro ao eliminar Armazenamento do dispositivo insuficiente diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 6996e61910..7c2e37e047 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -263,6 +263,7 @@ Cachningsfel En kategori med samma namn finns redan Ett element med samma namn finns redan på den här platsen + Flyttning inte möjlig: målmappen finns inuti källmappen Överföring till en annan enhet misslyckades Borttagningsfel Otillräcklig enhetslagring diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e82a85e813..c26dac9dbb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -263,6 +263,7 @@ Caching error A category with the same name already exists An element with the same name already exists in this location + Move not available: the target folder is inside the source folder Transfer to another drive failed Deletion error Insufficient device storage