From 7d48bcc18e62e7f36df489164fa3964006a816d2 Mon Sep 17 00:00:00 2001 From: Jan Guegel Date: Sat, 27 Sep 2025 22:06:08 +0200 Subject: [PATCH 1/6] fixed moving nested folders cleanup Signed-off-by: Jan Guegel --- .../filemanager/adapters/ItemsAdapter.kt | 144 ++++++------------ 1 file changed, 46 insertions(+), 98 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt index 67712316..08cc3adf 100644 --- a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt @@ -35,82 +35,19 @@ import net.lingala.zip4j.model.LocalFileHeader import net.lingala.zip4j.model.ZipParameters import net.lingala.zip4j.model.enums.EncryptionMethod import org.fossify.commons.adapters.MyRecyclerViewAdapter -import org.fossify.commons.dialogs.ConfirmationDialog -import org.fossify.commons.dialogs.FilePickerDialog -import org.fossify.commons.dialogs.PropertiesDialog -import org.fossify.commons.dialogs.RadioGroupDialog -import org.fossify.commons.dialogs.RenameDialog -import org.fossify.commons.dialogs.RenameItemDialog -import org.fossify.commons.dialogs.RenameItemsDialog -import org.fossify.commons.extensions.applyColorFilter -import org.fossify.commons.extensions.beGone -import org.fossify.commons.extensions.beVisible -import org.fossify.commons.extensions.beVisibleIf -import org.fossify.commons.extensions.convertToBitmap -import org.fossify.commons.extensions.copyToClipboard -import org.fossify.commons.extensions.createDirectorySync -import org.fossify.commons.extensions.deleteFile -import org.fossify.commons.extensions.deleteFileBg -import org.fossify.commons.extensions.deleteFolderBg -import org.fossify.commons.extensions.formatDate -import org.fossify.commons.extensions.formatSize -import org.fossify.commons.extensions.getAndroidSAFFileItems -import org.fossify.commons.extensions.getAndroidSAFUri -import org.fossify.commons.extensions.getColoredDrawableWithColor -import org.fossify.commons.extensions.getDefaultCopyDestinationPath -import org.fossify.commons.extensions.getDocumentFile -import org.fossify.commons.extensions.getDoesFilePathExist -import org.fossify.commons.extensions.getFileCount -import org.fossify.commons.extensions.getFileInputStreamSync -import org.fossify.commons.extensions.getFileOutputStreamSync -import org.fossify.commons.extensions.getFilenameFromPath -import org.fossify.commons.extensions.getIsPathDirectory -import org.fossify.commons.extensions.getMimeType -import org.fossify.commons.extensions.getParentPath -import org.fossify.commons.extensions.getProperSize -import org.fossify.commons.extensions.getTextSize -import org.fossify.commons.extensions.getTimeFormat -import org.fossify.commons.extensions.handleDeletePasswordProtection -import org.fossify.commons.extensions.hasOTGConnected -import org.fossify.commons.extensions.highlightTextPart -import org.fossify.commons.extensions.isPathOnOTG -import org.fossify.commons.extensions.isRestrictedSAFOnlyRoot -import org.fossify.commons.extensions.relativizeWith -import org.fossify.commons.extensions.setupViewBackground -import org.fossify.commons.extensions.showErrorToast -import org.fossify.commons.extensions.toFileDirItem -import org.fossify.commons.extensions.toast -import org.fossify.commons.helpers.CONFLICT_OVERWRITE -import org.fossify.commons.helpers.CONFLICT_SKIP -import org.fossify.commons.helpers.VIEW_TYPE_LIST -import org.fossify.commons.helpers.ensureBackgroundThread -import org.fossify.commons.helpers.getFilePlaceholderDrawables +import org.fossify.commons.dialogs.* +import org.fossify.commons.extensions.* +import org.fossify.commons.helpers.* import org.fossify.commons.models.FileDirItem import org.fossify.commons.models.RadioItem import org.fossify.commons.views.MyRecyclerView import org.fossify.filemanager.R import org.fossify.filemanager.activities.SimpleActivity import org.fossify.filemanager.activities.SplashActivity -import org.fossify.filemanager.databinding.ItemDirGridBinding -import org.fossify.filemanager.databinding.ItemEmptyBinding -import org.fossify.filemanager.databinding.ItemFileDirListBinding -import org.fossify.filemanager.databinding.ItemFileGridBinding -import org.fossify.filemanager.databinding.ItemSectionBinding +import org.fossify.filemanager.databinding.* import org.fossify.filemanager.dialogs.CompressAsDialog -import org.fossify.filemanager.extensions.config -import org.fossify.filemanager.extensions.isPathOnRoot -import org.fossify.filemanager.extensions.isZipFile -import org.fossify.filemanager.extensions.setAs -import org.fossify.filemanager.extensions.setLastModified -import org.fossify.filemanager.extensions.sharePaths -import org.fossify.filemanager.extensions.toggleItemVisibility -import org.fossify.filemanager.extensions.tryOpenPathIntent -import org.fossify.filemanager.helpers.OPEN_AS_AUDIO -import org.fossify.filemanager.helpers.OPEN_AS_IMAGE -import org.fossify.filemanager.helpers.OPEN_AS_OTHER -import org.fossify.filemanager.helpers.OPEN_AS_TEXT -import org.fossify.filemanager.helpers.OPEN_AS_VIDEO -import org.fossify.filemanager.helpers.RootHelpers +import org.fossify.filemanager.extensions.* +import org.fossify.filemanager.helpers.* import org.fossify.filemanager.interfaces.ItemOperationsListener import org.fossify.filemanager.models.ListItem import java.io.BufferedInputStream @@ -532,39 +469,30 @@ class ItemsAdapter( copyHidden = config.shouldShowHidden() ) { if (!isCopyOperation) { - files.forEach { sourceFileDir -> - val sourcePath = sourceFileDir.path - if ( - activity.isRestrictedSAFOnlyRoot(sourcePath) - && activity.getDoesFilePathExist(sourcePath) - ) { - activity.deleteFile(sourceFileDir, true) { - listener?.refreshFragment() - activity.runOnUiThread { - finishActMode() - } - } - } else { - val sourceFile = File(sourcePath) - if ( - activity.getDoesFilePathExist(source) - && activity.getIsPathDirectory(source) - && sourceFile.list()?.isEmpty() == true - && sourceFile.getProperSize(true) == 0L - && sourceFile.getFileCount(true) == 0 - ) { - val sourceFolder = sourceFile.toFileDirItem(activity) - activity.deleteFile(sourceFolder, true) { - listener?.refreshFragment() - activity.runOnUiThread { - finishActMode() + ensureBackgroundThread { + val sourceFoldersToCheck = HashSet() + + files.forEach { sourceFileDir -> + val sourcePath = sourceFileDir.path + + if (activity.getDoesFilePathExist(sourcePath)) { + activity.deleteFile(sourceFileDir, true) { + val parentPath = sourcePath.getParentPath() + if (parentPath.isNotEmpty()) { + sourceFoldersToCheck.add(parentPath) } } - } else { - listener?.refreshFragment() - finishActMode() } } + + sourceFoldersToCheck.forEach { folderPath -> + checkAndDeleteEmptyFolder(folderPath) + } + + activity.runOnUiThread { + listener?.refreshFragment() + finishActMode() + } } } else { listener?.refreshFragment() @@ -575,6 +503,26 @@ class ItemsAdapter( } } + private fun checkAndDeleteEmptyFolder(folderPath: String) { + if (!activity.getDoesFilePathExist(folderPath) || !activity.getIsPathDirectory(folderPath)) { + return + } + + val folder = File(folderPath) + val contents = folder.listFiles() + + if (contents == null || contents.isEmpty()) { + val parentPath = folderPath.getParentPath() + val folderItem = folder.toFileDirItem(activity) + + activity.deleteFile(folderItem, true) { + if (parentPath.isNotEmpty()) { + checkAndDeleteEmptyFolder(parentPath) + } + } + } + } + private fun copyMoveRootItems( files: ArrayList, destinationPath: String, From de09b945d65ef9377e6aa51a63a387ddf502d775 Mon Sep 17 00:00:00 2001 From: Jan Guegel Date: Sat, 27 Sep 2025 22:13:30 +0200 Subject: [PATCH 2/6] code improvement by using more functions Signed-off-by: Jan Guegel --- .../filemanager/adapters/ItemsAdapter.kt | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt index 08cc3adf..6938c245 100644 --- a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt @@ -455,74 +455,78 @@ class ItemsAdapter( showFAB = true, canAddShowHiddenButton = true, showFavoritesButton = true - ) { - config.lastCopyPath = it - if (activity.isPathOnRoot(it) || activity.isPathOnRoot(firstFile.path)) { - copyMoveRootItems(files, it, isCopyOperation) + ) { destination -> + config.lastCopyPath = destination + if (activity.isPathOnRoot(destination) || activity.isPathOnRoot(firstFile.path)) { + copyMoveRootItems(files, destination, isCopyOperation) } else { activity.copyMoveFilesTo( fileDirItems = files, source = source, - destination = it, + destination = destination, isCopyOperation = isCopyOperation, copyPhotoVideoOnly = false, copyHidden = config.shouldShowHidden() ) { if (!isCopyOperation) { - ensureBackgroundThread { - val sourceFoldersToCheck = HashSet() - - files.forEach { sourceFileDir -> - val sourcePath = sourceFileDir.path - - if (activity.getDoesFilePathExist(sourcePath)) { - activity.deleteFile(sourceFileDir, true) { - val parentPath = sourcePath.getParentPath() - if (parentPath.isNotEmpty()) { - sourceFoldersToCheck.add(parentPath) - } - } - } - } - - sourceFoldersToCheck.forEach { folderPath -> - checkAndDeleteEmptyFolder(folderPath) - } + cleanupAfterMove(files) + } else { + refreshUI() + } + } + } + } + } - activity.runOnUiThread { - listener?.refreshFragment() - finishActMode() - } + private fun cleanupAfterMove(files: List) { + ensureBackgroundThread { + val foldersToCheck = HashSet() + files.forEach { fileItem -> + val path = fileItem.path + if (activity.getDoesFilePathExist(path)) { + activity.deleteFile(fileItem, true) { + val parentPath = path.getParentPath() + if (parentPath.isNotEmpty()) { + foldersToCheck.add(parentPath) } - } else { - listener?.refreshFragment() - finishActMode() } } } + + foldersToCheck.forEach { folderPath -> + deleteEmptyFoldersRecursively(folderPath) + } + + refreshUI() } } - private fun checkAndDeleteEmptyFolder(folderPath: String) { + private fun deleteEmptyFoldersRecursively(folderPath: String) { if (!activity.getDoesFilePathExist(folderPath) || !activity.getIsPathDirectory(folderPath)) { return } val folder = File(folderPath) - val contents = folder.listFiles() - - if (contents == null || contents.isEmpty()) { + val contents = folder.listFiles() ?: return + if (contents.isEmpty()) { val parentPath = folderPath.getParentPath() val folderItem = folder.toFileDirItem(activity) activity.deleteFile(folderItem, true) { if (parentPath.isNotEmpty()) { - checkAndDeleteEmptyFolder(parentPath) + deleteEmptyFoldersRecursively(parentPath) } } } } + private fun refreshUI() { + activity.runOnUiThread { + listener?.refreshFragment() + finishActMode() + } + } + private fun copyMoveRootItems( files: ArrayList, destinationPath: String, From 0836f34bbcefd2648b23aab44ccbe18f4c4b52d5 Mon Sep 17 00:00:00 2001 From: Jan <4600407+jguegel@users.noreply.github.com> Date: Sat, 27 Sep 2025 22:15:11 +0200 Subject: [PATCH 3/6] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d48133b..c1fd3f89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed folders showing up incorrectly as files in copy/move dialog ([#267]) - Fixed error when saving files with unsupported characters ([#250]) - Fixed missing permission prompt on initial "Save as" launch ([#85]) +- Fixed cleanup after moving nested folders ([#102]) ## [1.2.3] - 2025-09-15 ### Fixed @@ -78,6 +79,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#267]: https://github.com/FossifyOrg/File-Manager/issues/267 [#250]: https://github.com/FossifyOrg/File-Manager/issues/250 [#85]: https://github.com/FossifyOrg/File-Manager/issues/85 +[#102]: https://github.com/FossifyOrg/File-Manager/issues/102 [Unreleased]: https://github.com/FossifyOrg/File-Manager/compare/1.2.3...HEAD [1.2.3]: https://github.com/FossifyOrg/File-Manager/compare/1.2.2...1.2.3 From 17f8b6cab17bc7a4d03af5c6781e724a2172923b Mon Sep 17 00:00:00 2001 From: Jan Guegel Date: Sat, 27 Sep 2025 22:17:46 +0200 Subject: [PATCH 4/6] undo auto import optimization Signed-off-by: Jan Guegel --- .../filemanager/adapters/ItemsAdapter.kt | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt index 6938c245..1bdee84a 100644 --- a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt @@ -35,19 +35,80 @@ import net.lingala.zip4j.model.LocalFileHeader import net.lingala.zip4j.model.ZipParameters import net.lingala.zip4j.model.enums.EncryptionMethod import org.fossify.commons.adapters.MyRecyclerViewAdapter -import org.fossify.commons.dialogs.* -import org.fossify.commons.extensions.* -import org.fossify.commons.helpers.* +import org.fossify.commons.dialogs.ConfirmationDialog +import org.fossify.commons.dialogs.FilePickerDialog +import org.fossify.commons.dialogs.PropertiesDialog +import org.fossify.commons.dialogs.RadioGroupDialog +import org.fossify.commons.dialogs.RenameDialog +import org.fossify.commons.dialogs.RenameItemDialog +import org.fossify.commons.dialogs.RenameItemsDialog +import org.fossify.commons.extensions.applyColorFilter +import org.fossify.commons.extensions.beGone +import org.fossify.commons.extensions.beVisible +import org.fossify.commons.extensions.beVisibleIf +import org.fossify.commons.extensions.convertToBitmap +import org.fossify.commons.extensions.copyToClipboard +import org.fossify.commons.extensions.createDirectorySync +import org.fossify.commons.extensions.deleteFile +import org.fossify.commons.extensions.deleteFileBg +import org.fossify.commons.extensions.deleteFolderBg +import org.fossify.commons.extensions.formatDate +import org.fossify.commons.extensions.formatSize +import org.fossify.commons.extensions.getAndroidSAFFileItems +import org.fossify.commons.extensions.getAndroidSAFUri +import org.fossify.commons.extensions.getColoredDrawableWithColor +import org.fossify.commons.extensions.getDefaultCopyDestinationPath +import org.fossify.commons.extensions.getDocumentFile +import org.fossify.commons.extensions.getDoesFilePathExist +import org.fossify.commons.extensions.getFileInputStreamSync +import org.fossify.commons.extensions.getFileOutputStreamSync +import org.fossify.commons.extensions.getFilenameFromPath +import org.fossify.commons.extensions.getIsPathDirectory +import org.fossify.commons.extensions.getMimeType +import org.fossify.commons.extensions.getParentPath +import org.fossify.commons.extensions.getTextSize +import org.fossify.commons.extensions.getTimeFormat +import org.fossify.commons.extensions.handleDeletePasswordProtection +import org.fossify.commons.extensions.hasOTGConnected +import org.fossify.commons.extensions.highlightTextPart +import org.fossify.commons.extensions.isPathOnOTG +import org.fossify.commons.extensions.isRestrictedSAFOnlyRoot +import org.fossify.commons.extensions.relativizeWith +import org.fossify.commons.extensions.setupViewBackground +import org.fossify.commons.extensions.showErrorToast +import org.fossify.commons.extensions.toFileDirItem +import org.fossify.commons.extensions.toast +import org.fossify.commons.helpers.CONFLICT_OVERWRITE +import org.fossify.commons.helpers.CONFLICT_SKIP +import org.fossify.commons.helpers.VIEW_TYPE_LIST +import org.fossify.commons.helpers.ensureBackgroundThread +import org.fossify.commons.helpers.getFilePlaceholderDrawables import org.fossify.commons.models.FileDirItem import org.fossify.commons.models.RadioItem import org.fossify.commons.views.MyRecyclerView import org.fossify.filemanager.R import org.fossify.filemanager.activities.SimpleActivity import org.fossify.filemanager.activities.SplashActivity -import org.fossify.filemanager.databinding.* +import org.fossify.filemanager.databinding.ItemDirGridBinding +import org.fossify.filemanager.databinding.ItemEmptyBinding +import org.fossify.filemanager.databinding.ItemFileDirListBinding +import org.fossify.filemanager.databinding.ItemFileGridBinding +import org.fossify.filemanager.databinding.ItemSectionBinding import org.fossify.filemanager.dialogs.CompressAsDialog -import org.fossify.filemanager.extensions.* -import org.fossify.filemanager.helpers.* +import org.fossify.filemanager.extensions.config +import org.fossify.filemanager.extensions.isPathOnRoot +import org.fossify.filemanager.extensions.isZipFile +import org.fossify.filemanager.extensions.setAs +import org.fossify.filemanager.extensions.setLastModified +import org.fossify.filemanager.extensions.sharePaths +import org.fossify.filemanager.extensions.toggleItemVisibility +import org.fossify.filemanager.extensions.tryOpenPathIntent +import org.fossify.filemanager.helpers.OPEN_AS_AUDIO +import org.fossify.filemanager.helpers.OPEN_AS_IMAGE +import org.fossify.filemanager.helpers.OPEN_AS_OTHER +import org.fossify.filemanager.helpers.OPEN_AS_TEXT +import org.fossify.filemanager.helpers.OPEN_AS_VIDEO +import org.fossify.filemanager.helpers.RootHelpers import org.fossify.filemanager.interfaces.ItemOperationsListener import org.fossify.filemanager.models.ListItem import java.io.BufferedInputStream From 488ee0c541193e904b276d0385b6e1afea7243c2 Mon Sep 17 00:00:00 2001 From: Jan <4600407+jguegel@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:00:22 +0200 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2978de9c..439ee7ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,9 +97,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#250]: https://github.com/FossifyOrg/File-Manager/issues/250 [#251]: https://github.com/FossifyOrg/File-Manager/issues/251 [#267]: https://github.com/FossifyOrg/File-Manager/issues/267 -[#250]: https://github.com/FossifyOrg/File-Manager/issues/250 -[#85]: https://github.com/FossifyOrg/File-Manager/issues/85 -[#104]: https://github.com/FossifyOrg/File-Manager/issues/104 [#102]: https://github.com/FossifyOrg/File-Manager/issues/102 [Unreleased]: https://github.com/FossifyOrg/File-Manager/compare/1.3.0...HEAD From 1a78dba5db53a49784647d0bf9d04efce426fa08 Mon Sep 17 00:00:00 2001 From: Jan <4600407+jguegel@users.noreply.github.com> Date: Mon, 22 Dec 2025 09:24:07 +0100 Subject: [PATCH 6/6] Remove extra blank line in CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3066531f..2276e0eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed files from hidden folders showing up in storage tab browser ([#217]) - Fixed an issue where existing files were overwritten when saving new files ([#131]) - ## [1.3.0] - 2025-09-30 ### Added - Added a separate "Save as" option in the text editor ([#224])