fix , show a conflict dialog when decompressing destination already exists

This commit is contained in:
tibbi 2018-02-17 17:08:09 +01:00
parent 803b30c59c
commit 055007a45d
5 changed files with 97 additions and 34 deletions
app
build.gradle
src/main/kotlin/com/simplemobiletools/filemanager

@ -45,7 +45,7 @@ ext {
} }
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:3.12.3' implementation 'com.simplemobiletools:commons:3.12.5'
implementation files('../libs/RootTools.jar') implementation files('../libs/RootTools.jar')

@ -18,6 +18,8 @@ import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.CONFLICT_OVERWRITE
import com.simplemobiletools.commons.helpers.CONFLICT_SKIP
import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.commons.models.FileDirItem
import com.simplemobiletools.commons.views.FastScroller import com.simplemobiletools.commons.views.FastScroller
import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.commons.views.MyRecyclerView
@ -235,7 +237,7 @@ class ItemsAdapter(activity: SimpleActivity, var fileDirItems: MutableList<FileD
activity.toast(R.string.compressing) activity.toast(R.string.compressing)
val paths = selectedPositions.map { fileDirItems[it].path } val paths = selectedPositions.map { fileDirItems[it].path }
Thread { Thread {
if (zipPaths(paths, it)) { if (compressPaths(paths, it)) {
activity.runOnUiThread { activity.runOnUiThread {
activity.toast(R.string.compression_successful) activity.toast(R.string.compression_successful)
listener?.refreshItems() listener?.refreshItems()
@ -257,10 +259,9 @@ class ItemsAdapter(activity: SimpleActivity, var fileDirItems: MutableList<FileD
} }
activity.handleSAFDialog(firstPath) { activity.handleSAFDialog(firstPath) {
activity.toast(R.string.decompressing)
val paths = selectedPositions.map { fileDirItems[it].path }.filter { it.isZipFile() } val paths = selectedPositions.map { fileDirItems[it].path }.filter { it.isZipFile() }
Thread { tryDecompressingPaths(paths) {
if (unzipPaths(paths)) { if (it) {
activity.toast(R.string.decompression_successful) activity.toast(R.string.decompression_successful)
activity.runOnUiThread { activity.runOnUiThread {
listener?.refreshItems() listener?.refreshItems()
@ -269,43 +270,105 @@ class ItemsAdapter(activity: SimpleActivity, var fileDirItems: MutableList<FileD
} else { } else {
activity.toast(R.string.decompressing_failed) activity.toast(R.string.decompressing_failed)
} }
}.start() }
} }
} }
private fun unzipPaths(sourcePaths: List<String>): Boolean { private fun tryDecompressingPaths(sourcePaths: List<String>, callback: (success: Boolean) -> Unit) {
sourcePaths.map { File(it) } sourcePaths.forEach {
.forEach { try {
try { val zipFile = ZipFile(it)
val zipFile = ZipFile(it) val entries = zipFile.entries()
val entries = zipFile.entries() val fileDirItems = ArrayList<FileDirItem>()
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
val entry = entries.nextElement() val entry = entries.nextElement()
val file = File(it.parent, entry.name) val currPath = if (entry.isDirectory) it else "${it.getParentPath()}${entry.name}"
if (entry.isDirectory) { val fileDirItem = FileDirItem(currPath, entry.name, entry.isDirectory, 0, entry.size)
if (!activity.createDirectorySync(file.absolutePath)) { fileDirItems.add(fileDirItem)
val error = String.format(activity.getString(R.string.could_not_create_file), file.absolutePath) }
activity.showErrorToast(error)
return false val destinationFileDirItem = FileDirItem(fileDirItems.first().getParentPath().trimEnd('/'))
activity.checkConflicts(fileDirItems, destinationFileDirItem, 0, LinkedHashMap()) {
Thread {
decompressPaths(sourcePaths, it, callback)
}.start()
}
} catch (exception: Exception) {
activity.showErrorToast(exception)
}
}
}
private fun decompressPaths(paths: List<String>, conflictResolutions: LinkedHashMap<String, Int>, callback: (success: Boolean) -> Unit) {
paths.forEach {
try {
val zipFile = ZipFile(it)
val entries = zipFile.entries()
while (entries.hasMoreElements()) {
val entry = entries.nextElement()
val newPath = "${it.getParentPath()}${entry.name}"
val resolution = getConflictResolution(conflictResolutions, newPath)
val doesPathExist = activity.getDoesFilePathExist(newPath)
if (doesPathExist && resolution == CONFLICT_OVERWRITE) {
val fileDirItem = FileDirItem(newPath, newPath.getFilenameFromPath(), entry.isDirectory)
if (activity.getIsPathDirectory(it)) {
activity.deleteFolderBg(fileDirItem, false) {
if (it) {
extractEntry(newPath, entry, zipFile)
} else {
callback(false)
} }
} else { }
val ins = zipFile.getInputStream(entry) } else {
ins.use { activity.deleteFileBg(fileDirItem, false) {
val fos = activity.getFileOutputStreamSync(file.absolutePath, file.getMimeType()) if (it) {
if (fos != null) extractEntry(newPath, entry, zipFile)
ins.copyTo(fos) } else {
callback(false)
} }
} }
} }
} catch (exception: Exception) { } else if (!doesPathExist) {
activity.showErrorToast(exception) extractEntry(newPath, entry, zipFile)
return false
} }
} }
return true callback(true)
} catch (e: Exception) {
activity.showErrorToast(e)
callback(false)
}
}
} }
private fun zipPaths(sourcePaths: List<String>, targetPath: String): Boolean { private fun extractEntry(newPath: String, entry: ZipEntry, zipFile: ZipFile) {
if (entry.isDirectory) {
if (!activity.createDirectorySync(newPath)) {
val error = String.format(activity.getString(R.string.could_not_create_file), newPath)
activity.showErrorToast(error)
}
} else {
val ins = zipFile.getInputStream(entry)
ins.use {
val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType())
if (fos != null) {
ins.copyTo(fos)
}
}
}
}
private fun getConflictResolution(conflictResolutions: LinkedHashMap<String, Int>, path: String): Int {
return if (conflictResolutions.size == 1 && conflictResolutions.containsKey("")) {
conflictResolutions[""]!!
} else if (conflictResolutions.containsKey(path)) {
conflictResolutions[path]!!
} else {
CONFLICT_SKIP
}
}
private fun compressPaths(sourcePaths: List<String>, targetPath: String): Boolean {
val queue = LinkedList<File>() val queue = LinkedList<File>()
val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false

@ -43,7 +43,7 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c
name.isEmpty() -> activity.toast(R.string.empty_name) name.isEmpty() -> activity.toast(R.string.empty_name)
name.isAValidFilename() -> { name.isAValidFilename() -> {
val newPath = "$realPath/$name.zip" val newPath = "$realPath/$name.zip"
if (activity.doesFilePathExist(newPath)) { if (activity.getDoesFilePathExist(newPath)) {
activity.toast(R.string.name_taken) activity.toast(R.string.name_taken)
return@OnClickListener return@OnClickListener
} }

@ -26,7 +26,7 @@ class CreateNewItemDialog(val activity: BaseSimpleActivity, val path: String, va
activity.toast(R.string.empty_name) activity.toast(R.string.empty_name)
} else if (name.isAValidFilename()) { } else if (name.isAValidFilename()) {
val newPath = "$path/$name" val newPath = "$path/$name"
if (activity.doesFilePathExist(newPath)) { if (activity.getDoesFilePathExist(newPath)) {
activity.toast(R.string.name_taken) activity.toast(R.string.name_taken)
return@OnClickListener return@OnClickListener
} }

@ -66,7 +66,7 @@ class SaveAsDialog(val activity: BaseSimpleActivity, var path: String, val callb
return@setOnClickListener return@setOnClickListener
} }
if (activity.doesFilePathExist(newPath)) { if (activity.getDoesFilePathExist(newPath)) {
val title = String.format(activity.getString(R.string.file_already_exists_overwrite), newFilename) val title = String.format(activity.getString(R.string.file_already_exists_overwrite), newFilename)
ConfirmationDialog(activity, title) { ConfirmationDialog(activity, title) {
callback(newPath) callback(newPath)