@@ -183,6 +183,9 @@ class FileDisplayActivity : FileActivity(),
183183 private var waitingToOpen: OCFile ? = null
184184
185185 private var copyMoveTargetFolder: OCFile ? = null
186+ private var copyMoveItemsCount: Int = 1
187+ private var copyMoveFilesCount: Int = 0
188+ private var copyMoveFoldersCount: Int = 0
186189
187190 private var localBroadcastManager: LocalBroadcastManager ? = null
188191
@@ -711,6 +714,7 @@ class FileDisplayActivity : FileActivity(),
711714 val folderToMoveAt = data.getParcelableExtra<OCFile >(FolderPickerActivity .EXTRA_FOLDER ) ? : return
712715 val files = data.getParcelableArrayListExtra<OCFile >(FolderPickerActivity .EXTRA_FILES ) ? : return
713716 copyMoveTargetFolder = folderToMoveAt
717+ updateCopyMoveSelectionCounters(files)
714718 val moveOperation = FileOperation .MoveOperation (
715719 listOfFilesToMove = files.toList(),
716720 targetFolder = folderToMoveAt,
@@ -728,6 +732,7 @@ class FileDisplayActivity : FileActivity(),
728732 val folderToCopyAt = data.getParcelableExtra<OCFile >(FolderPickerActivity .EXTRA_FOLDER ) ? : return
729733 val files = data.getParcelableArrayListExtra<OCFile >(FolderPickerActivity .EXTRA_FILES ) ? : return
730734 copyMoveTargetFolder = folderToCopyAt
735+ updateCopyMoveSelectionCounters(files)
731736 val copyOperation = FileOperation .CopyOperation (
732737 listOfFilesToCopy = files.toList(),
733738 targetFolder = folderToCopyAt,
@@ -1086,7 +1091,7 @@ class FileDisplayActivity : FileActivity(),
10861091 spacesListViewModel.refreshSpacesFromServer()
10871092 }
10881093 if (uiResult.data.isNullOrEmpty()) {
1089- showCopyMoveSuccessSnackbar(isCopy = false )
1094+ showCopyMoveSuccessSnackbar(isCopy = false , itemsCount = copyMoveItemsCount )
10901095 }
10911096 }
10921097
@@ -1137,7 +1142,7 @@ class FileDisplayActivity : FileActivity(),
11371142 // Refresh the spaces and update the quota
11381143 spacesListViewModel.refreshSpacesFromServer()
11391144 if (uiResult.data.isNullOrEmpty()) {
1140- showCopyMoveSuccessSnackbar(isCopy = true )
1145+ showCopyMoveSuccessSnackbar(isCopy = true , itemsCount = copyMoveItemsCount )
11411146 }
11421147 }
11431148
@@ -1157,8 +1162,19 @@ class FileDisplayActivity : FileActivity(),
11571162 }
11581163 }
11591164
1160- private fun showCopyMoveSuccessSnackbar (isCopy : Boolean ) {
1161- val message = getString(if (isCopy) R .string.copy_file_correctly else R .string.move_file_correctly)
1165+ private fun showCopyMoveSuccessSnackbar (isCopy : Boolean , itemsCount : Int ) {
1166+ val safeItemsCount = itemsCount.coerceAtLeast(1 )
1167+ val pluralRes = when {
1168+ copyMoveFilesCount > 0 && copyMoveFoldersCount > 0 ->
1169+ if (isCopy) R .plurals.copy_items_correctly else R .plurals.move_items_correctly
1170+
1171+ copyMoveFoldersCount > 0 ->
1172+ if (isCopy) R .plurals.copy_folders_correctly else R .plurals.move_folders_correctly
1173+
1174+ else ->
1175+ if (isCopy) R .plurals.copy_files_correctly else R .plurals.move_files_correctly
1176+ }
1177+ val message = copyMoveSuccessQuantityString(pluralRes, safeItemsCount)
11621178 val targetFolderId = copyMoveTargetFolder?.id
11631179 if (targetFolderId != null ) {
11641180 showSnackbarWithAction(
@@ -1176,6 +1192,36 @@ class FileDisplayActivity : FileActivity(),
11761192 }
11771193 }
11781194
1195+ /* * Singular plural forms have no `%d`; avoid passing format args for quantity `one`. */
1196+ private fun copyMoveSuccessQuantityString (pluralRes : Int , count : Int ): String =
1197+ if (count == 1 ) {
1198+ resources.getQuantityString(pluralRes, 1 )
1199+ } else {
1200+ resources.getQuantityString(pluralRes, count, count)
1201+ }
1202+
1203+ /* * If [replace] is null, sets counters from [files]; otherwise subtracts skipped conflict entries. */
1204+ private fun updateCopyMoveSelectionCounters (files : List <OCFile >, replace : List <Boolean ?>? = null) {
1205+ if (replace == null ) {
1206+ copyMoveItemsCount = files.size
1207+ copyMoveFoldersCount = files.count { it.isFolder }
1208+ copyMoveFilesCount = copyMoveItemsCount - copyMoveFoldersCount
1209+ return
1210+ }
1211+ if (replace.isEmpty()) return
1212+
1213+ val conflictFiles = files.asReversed()
1214+ val skippedConflictFiles = conflictFiles.filterIndexed { index, _ -> replace.getOrNull(index) == null }
1215+ if (skippedConflictFiles.isEmpty()) return
1216+
1217+ val skippedFolders = skippedConflictFiles.count { it.isFolder }
1218+ val skippedFiles = skippedConflictFiles.size - skippedFolders
1219+
1220+ copyMoveItemsCount = (copyMoveItemsCount - skippedConflictFiles.size).coerceAtLeast(0 )
1221+ copyMoveFoldersCount = (copyMoveFoldersCount - skippedFolders).coerceAtLeast(0 )
1222+ copyMoveFilesCount = (copyMoveFilesCount - skippedFiles).coerceAtLeast(0 )
1223+ }
1224+
11791225 private fun showConflictDecisionDialog (
11801226 uiResult : UIResult .Success <List <OCFile >>,
11811227 data : List <OCFile >,
@@ -1317,6 +1363,7 @@ class FileDisplayActivity : FileActivity(),
13171363 }
13181364
13191365 private fun launchCopyFile (files : List <OCFile >, replace : List <Boolean ?>) {
1366+ updateCopyMoveSelectionCounters(files, replace)
13201367 fileOperationsViewModel.performOperation(
13211368 FileOperation .CopyOperation (
13221369 listOfFilesToCopy = files,
@@ -1328,6 +1375,7 @@ class FileDisplayActivity : FileActivity(),
13281375 }
13291376
13301377 private fun launchMoveFile (files : List <OCFile >, replace : List <Boolean ?>) {
1378+ updateCopyMoveSelectionCounters(files, replace)
13311379 fileOperationsViewModel.performOperation(
13321380 FileOperation .MoveOperation (
13331381 listOfFilesToMove = files,
0 commit comments