diff --git a/app/build.gradle b/app/build.gradle index 6bf0bc9d..27fdbdfa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,7 +64,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:84c71fdcc1' + implementation 'com.github.SimpleMobileTools:Simple-Commons:db25f91be3' implementation 'com.github.tibbi:AndroidPdfViewer:e6a533125b' implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' @@ -72,4 +72,5 @@ dependencies { implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'me.grantland:autofittextview:0.2.1' + implementation 'net.lingala.zip4j:zip4j:2.11.5' } 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 ef24564b..70603dbd 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 @@ -44,13 +44,14 @@ import kotlinx.android.synthetic.main.item_file_dir_list.view.item_icon import kotlinx.android.synthetic.main.item_file_dir_list.view.item_name import kotlinx.android.synthetic.main.item_file_grid.view.* import kotlinx.android.synthetic.main.item_section.view.* +import net.lingala.zip4j.io.outputstream.ZipOutputStream +import net.lingala.zip4j.model.ZipParameters import java.io.BufferedInputStream import java.io.Closeable import java.io.File import java.util.* import java.util.zip.ZipEntry import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream class ItemsAdapter( activity: SimpleActivity, var listItems: MutableList, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView, @@ -482,8 +483,7 @@ class ItemsAdapter( return } - CompressAsDialog(activity, firstPath) { - val destination = it + CompressAsDialog(activity, firstPath) { destination, password -> activity.handleAndroidSAFDialog(firstPath) { granted -> if (!granted) { return@handleAndroidSAFDialog @@ -496,7 +496,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() @@ -643,13 +643,17 @@ 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 + } + try { sourcePaths.forEach { currentPath -> var name: String @@ -659,7 +663,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()) { @@ -672,9 +680,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() } @@ -687,9 +695,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() } @@ -698,7 +706,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..a49febc4 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) + 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..48b763d6 100644 --- a/app/src/main/res/layout/dialog_compress_as.xml +++ b/app/src/main/res/layout/dialog_compress_as.xml @@ -27,6 +27,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/folder_hint" + android:layout_marginBottom="@dimen/activity_margin" android:hint="@string/filename_without_zip"> + + + + + + + +