diff --git a/app/build.gradle b/app/build.gradle index 058dd146..a6f6f09d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,7 +64,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:2d4e07e5f4' + implementation 'com.github.SimpleMobileTools:Simple-Commons:79b117a9ba' implementation 'com.github.tibbi:AndroidPdfViewer:e6a533125b' implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index 04725d3c..440efb08 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -46,13 +46,14 @@ import kotlinx.android.synthetic.main.item_file_grid.view.* import kotlinx.android.synthetic.main.item_section.view.* import net.lingala.zip4j.exception.ZipException import net.lingala.zip4j.io.inputstream.ZipInputStream +import net.lingala.zip4j.io.outputstream.ZipOutputStream import net.lingala.zip4j.model.LocalFileHeader +import net.lingala.zip4j.model.ZipParameters +import net.lingala.zip4j.model.enums.EncryptionMethod import java.io.BufferedInputStream import java.io.Closeable import java.io.File import java.util.* -import java.util.zip.ZipEntry -import java.util.zip.ZipOutputStream class ItemsAdapter( activity: SimpleActivity, var listItems: MutableList, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView, @@ -484,8 +485,7 @@ class ItemsAdapter( return } - CompressAsDialog(activity, firstPath) { - val destination = it + CompressAsDialog(activity, firstPath) { destination, password -> activity.handleAndroidSAFDialog(firstPath) { granted -> if (!granted) { return@handleAndroidSAFDialog @@ -498,7 +498,7 @@ class ItemsAdapter( activity.toast(R.string.compressing) val paths = getSelectedFileDirItems().map { it.path } ensureBackgroundThread { - if (compressPaths(paths, destination)) { + if (compressPaths(paths, destination, password)) { activity.runOnUiThread { activity.toast(R.string.compression_successful) listener?.refreshFragment() @@ -648,13 +648,21 @@ class ItemsAdapter( } @SuppressLint("NewApi") - private fun compressPaths(sourcePaths: List, targetPath: String): Boolean { + private fun compressPaths(sourcePaths: List, targetPath: String, password: String? = null): Boolean { val queue = LinkedList() val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false - val zout = ZipOutputStream(fos) + val zout = password?.let { ZipOutputStream(fos, password.toCharArray()) } ?: ZipOutputStream(fos) var res: Closeable = fos + fun zipEntry(name: String) = ZipParameters().also { + it.fileNameInZip = name + if (password != null) { + it.isEncryptFiles = true + it.encryptionMethod = EncryptionMethod.AES + } + } + try { sourcePaths.forEach { currentPath -> var name: String @@ -664,7 +672,11 @@ class ItemsAdapter( queue.push(mainFilePath) if (activity.getIsPathDirectory(mainFilePath)) { name = "${mainFilePath.getFilenameFromPath()}/" - zout.putNextEntry(ZipEntry(name)) + zout.putNextEntry( + ZipParameters().also { + it.fileNameInZip = name + } + ) } while (!queue.isEmpty()) { @@ -677,9 +689,9 @@ class ItemsAdapter( if (activity.getIsPathDirectory(file.path)) { queue.push(file.path) name = "${name.trimEnd('/')}/" - zout.putNextEntry(ZipEntry(name)) + zout.putNextEntry(zipEntry(name)) } else { - zout.putNextEntry(ZipEntry(name)) + zout.putNextEntry(zipEntry(name)) activity.getFileInputStreamSync(file.path)!!.copyTo(zout) zout.closeEntry() } @@ -692,9 +704,9 @@ class ItemsAdapter( if (activity.getIsPathDirectory(file.absolutePath)) { queue.push(file.absolutePath) name = "${name.trimEnd('/')}/" - zout.putNextEntry(ZipEntry(name)) + zout.putNextEntry(zipEntry(name)) } else { - zout.putNextEntry(ZipEntry(name)) + zout.putNextEntry(zipEntry(name)) activity.getFileInputStreamSync(file.path)!!.copyTo(zout) zout.closeEntry() } @@ -703,7 +715,7 @@ class ItemsAdapter( } else { name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base) - zout.putNextEntry(ZipEntry(name)) + zout.putNextEntry(zipEntry(name)) activity.getFileInputStreamSync(mainFilePath)!!.copyTo(zout) zout.closeEntry() } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CompressAsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CompressAsDialog.kt index 29ab70de..e56aaca6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CompressAsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CompressAsDialog.kt @@ -7,10 +7,9 @@ import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.filemanager.pro.R import com.simplemobiletools.filemanager.pro.extensions.config -import kotlinx.android.synthetic.main.dialog_compress_as.view.filename_value -import kotlinx.android.synthetic.main.dialog_compress_as.view.folder +import kotlinx.android.synthetic.main.dialog_compress_as.view.* -class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val callback: (destination: String) -> Unit) { +class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val callback: (destination: String, password: String?) -> Unit) { private val view = activity.layoutInflater.inflate(R.layout.dialog_compress_as, null) init { @@ -29,6 +28,10 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c realPath = it } } + + password_protect.setOnCheckedChangeListener { _, _ -> + enter_password_hint.beVisibleIf(password_protect.isChecked) + } } activity.getAlertDialogBuilder() @@ -39,6 +42,14 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c alertDialog.showKeyboard(view.filename_value) alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener { val name = view.filename_value.value + var password: String? = null + if (view.password_protect.isChecked) { + password = view.password.value + if (password.isEmpty()) { + activity.toast(R.string.empty_password_new) + return@OnClickListener + } + } when { name.isEmpty() -> activity.toast(R.string.empty_name) name.isAValidFilename() -> { @@ -49,8 +60,9 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c } alertDialog.dismiss() - callback(newPath) + callback(newPath, password) } + else -> activity.toast(R.string.invalid_name) } }) diff --git a/app/src/main/res/layout/dialog_compress_as.xml b/app/src/main/res/layout/dialog_compress_as.xml index e6642758..f5229ff1 100644 --- a/app/src/main/res/layout/dialog_compress_as.xml +++ b/app/src/main/res/layout/dialog_compress_as.xml @@ -1,5 +1,6 @@ + + + + + + + +