mirror of
https://github.com/SimpleMobileTools/Simple-File-Manager.git
synced 2025-01-17 03:07:22 +01:00
Add support for creating password protected zips
This commit is contained in:
parent
2ac5648037
commit
9a640c802c
@ -64,7 +64,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.github.SimpleMobileTools:Simple-Commons:84c71fdcc1'
|
implementation 'com.github.SimpleMobileTools:Simple-Commons:db25f91be3'
|
||||||
implementation 'com.github.tibbi:AndroidPdfViewer:e6a533125b'
|
implementation 'com.github.tibbi:AndroidPdfViewer:e6a533125b'
|
||||||
implementation 'com.github.Stericson:RootTools:df729dcb13'
|
implementation 'com.github.Stericson:RootTools:df729dcb13'
|
||||||
implementation 'com.github.Stericson:RootShell:1.6'
|
implementation 'com.github.Stericson:RootShell:1.6'
|
||||||
@ -72,4 +72,5 @@ dependencies {
|
|||||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
implementation 'me.grantland:autofittextview:0.2.1'
|
implementation 'me.grantland:autofittextview:0.2.1'
|
||||||
|
implementation 'net.lingala.zip4j:zip4j:2.11.5'
|
||||||
}
|
}
|
||||||
|
@ -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_dir_list.view.item_name
|
||||||
import kotlinx.android.synthetic.main.item_file_grid.view.*
|
import kotlinx.android.synthetic.main.item_file_grid.view.*
|
||||||
import kotlinx.android.synthetic.main.item_section.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.BufferedInputStream
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import java.util.zip.ZipOutputStream
|
|
||||||
|
|
||||||
class ItemsAdapter(
|
class ItemsAdapter(
|
||||||
activity: SimpleActivity, var listItems: MutableList<ListItem>, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView,
|
activity: SimpleActivity, var listItems: MutableList<ListItem>, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView,
|
||||||
@ -482,8 +483,7 @@ class ItemsAdapter(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressAsDialog(activity, firstPath) {
|
CompressAsDialog(activity, firstPath) { destination, password ->
|
||||||
val destination = it
|
|
||||||
activity.handleAndroidSAFDialog(firstPath) { granted ->
|
activity.handleAndroidSAFDialog(firstPath) { granted ->
|
||||||
if (!granted) {
|
if (!granted) {
|
||||||
return@handleAndroidSAFDialog
|
return@handleAndroidSAFDialog
|
||||||
@ -496,7 +496,7 @@ class ItemsAdapter(
|
|||||||
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, password)) {
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
activity.toast(R.string.compression_successful)
|
activity.toast(R.string.compression_successful)
|
||||||
listener?.refreshFragment()
|
listener?.refreshFragment()
|
||||||
@ -643,13 +643,17 @@ class ItemsAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private fun compressPaths(sourcePaths: List<String>, targetPath: String): Boolean {
|
private fun compressPaths(sourcePaths: List<String>, targetPath: String, password: String? = null): Boolean {
|
||||||
val queue = LinkedList<String>()
|
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 = password?.let { ZipOutputStream(fos, password.toCharArray()) } ?: ZipOutputStream(fos)
|
||||||
var res: Closeable = fos
|
var res: Closeable = fos
|
||||||
|
|
||||||
|
fun zipEntry(name: String) = ZipParameters().also {
|
||||||
|
it.fileNameInZip = name
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sourcePaths.forEach { currentPath ->
|
sourcePaths.forEach { currentPath ->
|
||||||
var name: String
|
var name: String
|
||||||
@ -659,7 +663,11 @@ class ItemsAdapter(
|
|||||||
queue.push(mainFilePath)
|
queue.push(mainFilePath)
|
||||||
if (activity.getIsPathDirectory(mainFilePath)) {
|
if (activity.getIsPathDirectory(mainFilePath)) {
|
||||||
name = "${mainFilePath.getFilenameFromPath()}/"
|
name = "${mainFilePath.getFilenameFromPath()}/"
|
||||||
zout.putNextEntry(ZipEntry(name))
|
zout.putNextEntry(
|
||||||
|
ZipParameters().also {
|
||||||
|
it.fileNameInZip = name
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
@ -672,9 +680,9 @@ class ItemsAdapter(
|
|||||||
if (activity.getIsPathDirectory(file.path)) {
|
if (activity.getIsPathDirectory(file.path)) {
|
||||||
queue.push(file.path)
|
queue.push(file.path)
|
||||||
name = "${name.trimEnd('/')}/"
|
name = "${name.trimEnd('/')}/"
|
||||||
zout.putNextEntry(ZipEntry(name))
|
zout.putNextEntry(zipEntry(name))
|
||||||
} else {
|
} else {
|
||||||
zout.putNextEntry(ZipEntry(name))
|
zout.putNextEntry(zipEntry(name))
|
||||||
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
|
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
|
||||||
zout.closeEntry()
|
zout.closeEntry()
|
||||||
}
|
}
|
||||||
@ -687,9 +695,9 @@ class ItemsAdapter(
|
|||||||
if (activity.getIsPathDirectory(file.absolutePath)) {
|
if (activity.getIsPathDirectory(file.absolutePath)) {
|
||||||
queue.push(file.absolutePath)
|
queue.push(file.absolutePath)
|
||||||
name = "${name.trimEnd('/')}/"
|
name = "${name.trimEnd('/')}/"
|
||||||
zout.putNextEntry(ZipEntry(name))
|
zout.putNextEntry(zipEntry(name))
|
||||||
} else {
|
} else {
|
||||||
zout.putNextEntry(ZipEntry(name))
|
zout.putNextEntry(zipEntry(name))
|
||||||
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
|
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
|
||||||
zout.closeEntry()
|
zout.closeEntry()
|
||||||
}
|
}
|
||||||
@ -698,7 +706,7 @@ class ItemsAdapter(
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base)
|
name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base)
|
||||||
zout.putNextEntry(ZipEntry(name))
|
zout.putNextEntry(zipEntry(name))
|
||||||
activity.getFileInputStreamSync(mainFilePath)!!.copyTo(zout)
|
activity.getFileInputStreamSync(mainFilePath)!!.copyTo(zout)
|
||||||
zout.closeEntry()
|
zout.closeEntry()
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,9 @@ import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
|||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.filemanager.pro.R
|
import com.simplemobiletools.filemanager.pro.R
|
||||||
import com.simplemobiletools.filemanager.pro.extensions.config
|
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.*
|
||||||
import kotlinx.android.synthetic.main.dialog_compress_as.view.folder
|
|
||||||
|
|
||||||
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)
|
private val view = activity.layoutInflater.inflate(R.layout.dialog_compress_as, null)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -29,6 +28,10 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c
|
|||||||
realPath = it
|
realPath = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
password_protect.setOnCheckedChangeListener { _, _ ->
|
||||||
|
enter_password_hint.beVisibleIf(password_protect.isChecked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.getAlertDialogBuilder()
|
activity.getAlertDialogBuilder()
|
||||||
@ -39,6 +42,14 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c
|
|||||||
alertDialog.showKeyboard(view.filename_value)
|
alertDialog.showKeyboard(view.filename_value)
|
||||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener {
|
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener {
|
||||||
val name = view.filename_value.value
|
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 {
|
when {
|
||||||
name.isEmpty() -> activity.toast(R.string.empty_name)
|
name.isEmpty() -> activity.toast(R.string.empty_name)
|
||||||
name.isAValidFilename() -> {
|
name.isAValidFilename() -> {
|
||||||
@ -49,8 +60,9 @@ class CompressAsDialog(val activity: BaseSimpleActivity, val path: String, val c
|
|||||||
}
|
}
|
||||||
|
|
||||||
alertDialog.dismiss()
|
alertDialog.dismiss()
|
||||||
callback(newPath)
|
callback(newPath, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> activity.toast(R.string.invalid_name)
|
else -> activity.toast(R.string.invalid_name)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/folder_hint"
|
android:layout_below="@+id/folder_hint"
|
||||||
|
android:layout_marginBottom="@dimen/activity_margin"
|
||||||
android:hint="@string/filename_without_zip">
|
android:hint="@string/filename_without_zip">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
@ -39,4 +40,34 @@
|
|||||||
android:textSize="@dimen/bigger_text_size" />
|
android:textSize="@dimen/bigger_text_size" />
|
||||||
|
|
||||||
</com.simplemobiletools.commons.views.MyTextInputLayout>
|
</com.simplemobiletools.commons.views.MyTextInputLayout>
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||||
|
android:id="@+id/password_protect"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/filename_hint"
|
||||||
|
android:layout_marginTop="@dimen/small_margin"
|
||||||
|
android:paddingTop="@dimen/normal_margin"
|
||||||
|
android:paddingBottom="@dimen/normal_margin"
|
||||||
|
android:text="@string/password" />
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextInputLayout
|
||||||
|
android:id="@+id/enter_password_hint"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/password_protect"
|
||||||
|
android:hint="@string/password"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/activity_margin"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textCursorDrawable="@null"
|
||||||
|
android:textSize="@dimen/normal_text_size" />
|
||||||
|
|
||||||
|
</com.simplemobiletools.commons.views.MyTextInputLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user