handle compress/decompress

This commit is contained in:
darthpaul
2021-11-02 21:49:21 +00:00
parent 6dbfdb0c24
commit 1e067e3614

View File

@ -41,6 +41,7 @@ import com.simplemobiletools.filemanager.pro.helpers.*
import com.simplemobiletools.filemanager.pro.interfaces.ItemOperationsListener import com.simplemobiletools.filemanager.pro.interfaces.ItemOperationsListener
import com.simplemobiletools.filemanager.pro.models.ListItem import com.simplemobiletools.filemanager.pro.models.ListItem
import com.stericson.RootTools.RootTools import com.stericson.RootTools.RootTools
import java.io.BufferedInputStream
import kotlinx.android.synthetic.main.item_file_dir_grid.view.* import kotlinx.android.synthetic.main.item_file_dir_grid.view.*
import kotlinx.android.synthetic.main.item_file_dir_list.view.* import kotlinx.android.synthetic.main.item_file_dir_list.view.*
import kotlinx.android.synthetic.main.item_file_dir_list.view.item_frame import kotlinx.android.synthetic.main.item_file_dir_list.view.item_frame
@ -50,13 +51,18 @@ import kotlinx.android.synthetic.main.item_section.view.*
import java.io.Closeable import java.io.Closeable
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.net.URI
import java.net.URLEncoder
import java.util.* import java.util.*
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipFile import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList<ListItem>, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView, class ItemsAdapter(
val isPickMultipleIntent: Boolean, fastScroller: FastScroller?, val swipeRefreshLayout: SwipeRefreshLayout, itemClick: (Any) -> Unit) : activity: SimpleActivity, var listItems: MutableList<ListItem>, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView,
val isPickMultipleIntent: Boolean, fastScroller: FastScroller?, val swipeRefreshLayout: SwipeRefreshLayout, itemClick: (Any) -> Unit
) :
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) { MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private val TYPE_FILE_DIR = 1 private val TYPE_FILE_DIR = 1
@ -329,7 +335,7 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList<ListItem
val shouldShowHidden = activity.config.shouldShowHidden val shouldShowHidden = activity.config.shouldShowHidden
when { when {
activity.isRestrictedAndroidDir(path) -> { activity.isRestrictedAndroidDir(path) -> {
activity.getStorageItemsWithTreeUri(path, shouldShowHidden, false){ files-> activity.getStorageItemsWithTreeUri(path, shouldShowHidden, false) { files ->
files.forEach { files.forEach {
addFileUris(activity.getPrimaryAndroidSAFUri(it.path).toString(), paths) addFileUris(activity.getPrimaryAndroidSAFUri(it.path).toString(), paths)
} }
@ -463,22 +469,27 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList<ListItem
CompressAsDialog(activity, firstPath) { CompressAsDialog(activity, firstPath) {
val destination = it val destination = it
activity.handleSAFDialog(firstPath) { activity.handlePrimarySAFDialog(firstPath) { granted ->
if (!it) { if (!granted) {
return@handleSAFDialog return@handlePrimarySAFDialog
} }
activity.handleSAFDialog(firstPath) {
if (!it) {
return@handleSAFDialog
}
activity.toast(R.string.compressing) activity.toast(R.string.compressing)
val paths = getSelectedFileDirItems().map { it.path } val paths = getSelectedFileDirItems().map { it.path }
ensureBackgroundThread { ensureBackgroundThread {
if (compressPaths(paths, destination)) { if (compressPaths(paths, destination)) {
activity.runOnUiThread { activity.runOnUiThread {
activity.toast(R.string.compression_successful) activity.toast(R.string.compression_successful)
listener?.refreshItems() listener?.refreshItems()
finishActMode() finishActMode()
}
} else {
activity.toast(R.string.compressing_failed)
} }
} else {
activity.toast(R.string.compressing_failed)
} }
} }
} }
@ -513,88 +524,94 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList<ListItem
} }
private fun tryDecompressingPaths(sourcePaths: List<String>, callback: (success: Boolean) -> Unit) { private fun tryDecompressingPaths(sourcePaths: List<String>, callback: (success: Boolean) -> Unit) {
sourcePaths.forEach { sourcePaths.forEach { path ->
try { val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path)))
val zipFile = ZipFile(it) zipInputStream.use {
val entries = zipFile.entries() try {
val fileDirItems = ArrayList<FileDirItem>() val fileDirItems = ArrayList<FileDirItem>()
while (entries.hasMoreElements()) { var entry = zipInputStream.nextEntry
val entry = entries.nextElement() while (entry != null) {
val currPath = if (entry.isDirectory) it else "${it.getParentPath().trimEnd('/')}/${entry.name}" val currPath = if (entry.isDirectory) path else "${path.getParentPath().trimEnd('/')}/${entry.name}"
val fileDirItem = FileDirItem(currPath, entry.name, entry.isDirectory, 0, entry.size) val fileDirItem = FileDirItem(currPath, entry.name, entry.isDirectory, 0, entry.size)
fileDirItems.add(fileDirItem) fileDirItems.add(fileDirItem)
} zipInputStream.closeEntry()
entry = zipInputStream.nextEntry
val destinationPath = fileDirItems.first().getParentPath().trimEnd('/')
activity.checkConflicts(fileDirItems, destinationPath, 0, LinkedHashMap()) {
ensureBackgroundThread {
decompressPaths(sourcePaths, it, callback)
} }
zipInputStream.closeEntry()
val destinationPath = fileDirItems.first().getParentPath().trimEnd('/')
activity.checkConflicts(fileDirItems, destinationPath, 0, LinkedHashMap()) {
ensureBackgroundThread {
decompressPaths(sourcePaths, it, callback)
}
}
} catch (exception: Exception) {
exception.printStackTrace()
activity.showErrorToast(exception)
} }
} catch (exception: Exception) {
activity.showErrorToast(exception)
} }
} }
} }
private fun decompressPaths(paths: List<String>, conflictResolutions: LinkedHashMap<String, Int>, callback: (success: Boolean) -> Unit) { private fun decompressPaths(paths: List<String>, conflictResolutions: LinkedHashMap<String, Int>, callback: (success: Boolean) -> Unit) {
paths.forEach { paths.forEach { path ->
try { val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path)))
val zipFile = ZipFile(it) zipInputStream.use {
val entries = zipFile.entries() try {
val zipFileName = it.getFilenameFromPath() var entry = zipInputStream.nextEntry
val newFolderName = zipFileName.subSequence(0, zipFileName.length - 4) val zipFileName = path.getFilenameFromPath()
while (entries.hasMoreElements()) { val newFolderName = zipFileName.subSequence(0, zipFileName.length - 4)
val entry = entries.nextElement() while (entry != null) {
val parentPath = it.getParentPath() val parentPath = path.getParentPath()
val newPath = "$parentPath/$newFolderName/${entry.name.trimEnd('/')}" val newPath = "$parentPath/$newFolderName/${entry.name.trimEnd('/')}"
val resolution = getConflictResolution(conflictResolutions, newPath) val resolution = getConflictResolution(conflictResolutions, newPath)
val doesPathExist = activity.getDoesFilePathExist(newPath) val doesPathExist = activity.getDoesFilePathExist(newPath)
if (doesPathExist && resolution == CONFLICT_OVERWRITE) { if (doesPathExist && resolution == CONFLICT_OVERWRITE) {
val fileDirItem = FileDirItem(newPath, newPath.getFilenameFromPath(), entry.isDirectory) val fileDirItem = FileDirItem(newPath, newPath.getFilenameFromPath(), entry.isDirectory)
if (activity.getIsPathDirectory(it)) { if (activity.getIsPathDirectory(path)) {
activity.deleteFolderBg(fileDirItem, false) { activity.deleteFolderBg(fileDirItem, false) {
if (it) { if (it) {
extractEntry(newPath, entry, zipFile) extractEntry(newPath, entry, zipInputStream)
} else { } else {
callback(false) callback(false)
} }
} }
} else { } else {
activity.deleteFileBg(fileDirItem, false) { activity.deleteFileBg(fileDirItem, false) {
if (it) { if (it) {
extractEntry(newPath, entry, zipFile) extractEntry(newPath, entry, zipInputStream)
} else { } else {
callback(false) callback(false)
}
} }
} }
} else if (!doesPathExist) {
extractEntry(newPath, entry, zipInputStream)
} }
} else if (!doesPathExist) {
extractEntry(newPath, entry, zipFile) zipInputStream.closeEntry()
entry = zipInputStream.nextEntry
} }
callback(true)
} catch (e: Exception) {
e.printStackTrace()
activity.showErrorToast(e)
callback(false)
} }
callback(true)
} catch (e: Exception) {
activity.showErrorToast(e)
callback(false)
} }
} }
} }
private fun extractEntry(newPath: String, entry: ZipEntry, zipFile: ZipFile) { private fun extractEntry(newPath: String, entry: ZipEntry, zipInputStream: ZipInputStream) {
if (entry.isDirectory) { if (entry.isDirectory) {
if (!activity.createDirectorySync(newPath) && !activity.getDoesFilePathExist(newPath)) { if (!activity.createDirectorySync(newPath) && !activity.getDoesFilePathExist(newPath)) {
val error = String.format(activity.getString(R.string.could_not_create_file), newPath) val error = String.format(activity.getString(R.string.could_not_create_file), newPath)
activity.showErrorToast(error) activity.showErrorToast(error)
} }
} else { } else {
val ins = zipFile.getInputStream(entry) val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType())
ins.use { if (fos != null) {
val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType()) zipInputStream.copyTo(fos)
if (fos != null) {
ins.copyTo(fos)
}
} }
} }
} }
@ -610,48 +627,68 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList<ListItem
} }
private fun compressPaths(sourcePaths: List<String>, targetPath: String): Boolean { private fun compressPaths(sourcePaths: List<String>, targetPath: String): Boolean {
val queue = LinkedList<File>() val queue = LinkedList<String>()
val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false
val zout = ZipOutputStream(fos) val zout = ZipOutputStream(fos)
var res: Closeable = fos var res: Closeable = fos
try { try {
sourcePaths.forEach { sourcePaths.forEach { currentPath ->
var name: String var name: String
var mainFile = File(it) var mainFilePath = currentPath
val base = mainFile.parentFile.toURI() val base = "${mainFilePath.getParentPath()}/"
res = zout res = zout
queue.push(mainFile) queue.push(mainFilePath)
if (activity.getIsPathDirectory(mainFile.absolutePath)) { if (activity.getIsPathDirectory(mainFilePath)) {
name = "${mainFile.name.trimEnd('/')}/" name = "${mainFilePath.getFilenameFromPath()}/"
zout.putNextEntry(ZipEntry(name)) zout.putNextEntry(ZipEntry(name))
} }
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
mainFile = queue.pop() mainFilePath = queue.pop()
if (activity.getIsPathDirectory(mainFile.absolutePath)) { if (activity.getIsPathDirectory(mainFilePath)) {
for (file in mainFile.listFiles()) { if (activity.isRestrictedAndroidDir(mainFilePath)) {
name = base.relativize(file.toURI()).path activity.getStorageItemsWithTreeUri(mainFilePath, true) { files ->
if (activity.getIsPathDirectory(file.absolutePath)) { for (file in files) {
queue.push(file) name = file.path.relativizeWith(base)
name = "${name.trimEnd('/')}/" if (activity.getIsPathDirectory(file.path)) {
zout.putNextEntry(ZipEntry(name)) queue.push(file.path)
} else { name = "${name.trimEnd('/')}/"
zout.putNextEntry(ZipEntry(name)) zout.putNextEntry(ZipEntry(name))
FileInputStream(file).copyTo(zout) } else {
zout.closeEntry() zout.putNextEntry(ZipEntry(name))
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
zout.closeEntry()
}
}
}
} else {
val mainFile = File(mainFilePath)
for (file in mainFile.listFiles()) {
name = file.path.relativizeWith(base)
if (activity.getIsPathDirectory(file.absolutePath)) {
queue.push(file.absolutePath)
name = "${name.trimEnd('/')}/"
zout.putNextEntry(ZipEntry(name))
} else {
zout.putNextEntry(ZipEntry(name))
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
zout.closeEntry()
}
} }
} }
} else { } else {
name = if (base.path == it) it.getFilenameFromPath() else base.relativize(mainFile.toURI()).path name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base)
zout.putNextEntry(ZipEntry(name)) zout.putNextEntry(ZipEntry(name))
FileInputStream(mainFile).copyTo(zout) activity.getFileInputStreamSync(mainFilePath)!!.copyTo(zout)
zout.closeEntry() zout.closeEntry()
} }
} }
} }
} catch (exception: Exception) { } catch (exception: Exception) {
exception.printStackTrace()
activity.showErrorToast(exception) activity.showErrorToast(exception)
return false return false
} finally { } finally {
@ -835,7 +872,8 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList<ListItem
return activity.resources.getQuantityString(R.plurals.items, children, children) return activity.resources.getQuantityString(R.plurals.items, children, children)
} }
private fun getOTGPublicPath(itemToLoad: String) = "${baseConfig.OTGTreeUri}/document/${baseConfig.OTGPartition}%3A${itemToLoad.substring(baseConfig.OTGPath.length).replace("/", "%2F")}" private fun getOTGPublicPath(itemToLoad: String) =
"${baseConfig.OTGTreeUri}/document/${baseConfig.OTGPartition}%3A${itemToLoad.substring(baseConfig.OTGPath.length).replace("/", "%2F")}"
private fun getImagePathToLoad(path: String): Any { private fun getImagePathToLoad(path: String): Any {
var itemToLoad = if (path.endsWith(".apk", true)) { var itemToLoad = if (path.endsWith(".apk", true)) {