diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 78e6687..baf4b40 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -86,6 +86,8 @@
android:name=".file_viewers.TextEditor"
android:configChanges="screenSize|orientation" />
+
+
0) {
+ val written = gocryptfsVolume.writeFile(dstHandleId, offset, ioBuffer, length).toLong()
+ if (written == length.toLong()) {
+ offset += written
+ } else {
+ success = false
+ break
+ }
+ }
+ gocryptfsVolume.closeFile(dstHandleId)
+ } else {
+ success = false
+ }
+ remoteGocryptfsVolume.closeFile(srcHandleId)
+ } else {
+ success = false
+ }
+ return success
+ }
+
+ fun copyElements(items: ArrayList, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume, callback: (String?) -> Unit){
+ Thread {
+ var failedItem: String? = null
+ for (item in items){
+ if (item.explorerElement.isDirectory){
+ if (!gocryptfsVolume.pathExists(item.dstPath!!)) {
+ if (!gocryptfsVolume.mkdir(item.dstPath!!)) {
+ failedItem = item.explorerElement.fullPath
+ }
+ }
+ } else {
+ if (!copyFile(item.explorerElement.fullPath, item.dstPath!!, remoteGocryptfsVolume)){
+ failedItem = item.explorerElement.fullPath
+ }
+ }
+ if (failedItem != null){
+ break
+ }
+ }
+ callback(failedItem)
+ }.start()
+ }
+
+ fun moveElements(items: ArrayList, callback: (String?) -> Unit){
+ Thread {
+ val mergedFolders = ArrayList()
+ var failedItem: String? = null
+ for (item in items){
+ if (item.explorerElement.isDirectory && gocryptfsVolume.pathExists(item.dstPath!!)){ //folder will be merged
+ mergedFolders.add(item.explorerElement.fullPath)
+ } else {
+ if (!gocryptfsVolume.rename(item.explorerElement.fullPath, item.dstPath!!)){
+ failedItem = item.explorerElement.fullPath
+ break
+ }
+ }
+ }
+ if (failedItem == null){
+ for (path in mergedFolders) {
+ if (!gocryptfsVolume.rmdir(path)){
+ failedItem = path
+ break
+ }
+ }
+ }
+ callback(failedItem)
+ }.start()
+ }
+
+ fun importFilesFromUris(items: ArrayList, uris: List, callback: (String?) -> Unit){
+ Thread {
+ var failedIndex = -1
+ for (i in 0 until items.size) {
+ try {
+ if (!gocryptfsVolume.importFile(this, uris[i], items[i].dstPath!!)){
+ failedIndex = i
+ }
+ } catch (e: FileNotFoundException){
+ failedIndex = i
+ }
+ if (failedIndex != -1){
+ callback(uris[failedIndex].toString())
+ break
+ }
+ }
+ if (failedIndex == -1){
+ callback(null)
+ }
+ }.start()
+ }
+
+ fun wipeUris(uris: List, callback: (String?) -> Unit){
+ Thread {
+ var errorMsg: String? = null
+ for (uri in uris) {
+ errorMsg = Wiper.wipe(this, uri)
+ if (errorMsg != null) {
+ break
+ }
+ }
+ callback(errorMsg)
+ }.start()
+ }
+
+ private fun exportFileInto(srcPath: String, treeDocumentFile: DocumentFile): Boolean {
+ val outputStream = treeDocumentFile.createFile("*/*", File(srcPath).name)?.uri?.let {
+ contentResolver.openOutputStream(it)
+ }
+ return if (outputStream != null){
+ gocryptfsVolume.exportFile(srcPath, outputStream)
+ } else {
+ false
+ }
+ }
+
+ private fun recursiveExportDirectory(plain_directory_path: String, treeDocumentFile: DocumentFile): String? {
+ treeDocumentFile.createDirectory(File(plain_directory_path).name)?.let { childTree ->
+ val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
+ for (e in explorerElements) {
+ val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
+ if (e.isDirectory) {
+ val failedItem = recursiveExportDirectory(fullPath, childTree)
+ failedItem?.let { return it }
+ } else {
+ if (!exportFileInto(fullPath, childTree)){
+ return fullPath
+ }
+ }
+ }
+ return null
+ }
+ return treeDocumentFile.name
+ }
+
+ fun exportFiles(uri: Uri, items: List, callback: (String?) -> Unit){
+ Thread {
+ contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+ DocumentFile.fromTreeUri(this, uri)?.let { treeDocumentFile ->
+ var failedItem: String? = null
+ for (element in items) {
+ failedItem = if (element.isDirectory) {
+ recursiveExportDirectory(element.fullPath, treeDocumentFile)
+ } else {
+ if (exportFileInto(element.fullPath, treeDocumentFile)) null else element.fullPath
+ }
+ if (failedItem != null) {
+ break
+ }
+ }
+ callback(failedItem)
+ }
+ }.start()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
index 6091376..368eb29 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
@@ -1,12 +1,12 @@
package sushi.hardcore.droidfs.explorers
-import android.content.DialogInterface
+import android.content.ComponentName
+import android.content.Context
import android.content.Intent
+import android.content.ServiceConnection
import android.net.Uri
import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
-import android.os.Message
+import android.os.IBinder
import android.view.Menu
import android.view.MenuItem
import android.view.View
@@ -26,10 +26,12 @@ import sushi.hardcore.droidfs.ConstValues.Companion.isAudio
import sushi.hardcore.droidfs.ConstValues.Companion.isImage
import sushi.hardcore.droidfs.ConstValues.Companion.isText
import sushi.hardcore.droidfs.ConstValues.Companion.isVideo
+import sushi.hardcore.droidfs.FileOperationService
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
import sushi.hardcore.droidfs.adapters.ExplorerElementAdapter
import sushi.hardcore.droidfs.adapters.OpenAsDialogAdapter
+import sushi.hardcore.droidfs.file_operations.OperationFile
import sushi.hardcore.droidfs.file_viewers.AudioPlayer
import sushi.hardcore.droidfs.file_viewers.ImageViewer
import sushi.hardcore.droidfs.file_viewers.TextEditor
@@ -37,11 +39,8 @@ import sushi.hardcore.droidfs.file_viewers.VideoPlayer
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
import sushi.hardcore.droidfs.util.ExternalProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume
-import sushi.hardcore.droidfs.util.LoadingTask
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
-import java.io.File
-import java.io.FileNotFoundException
open class BaseExplorerActivity : BaseActivity() {
private lateinit var sortOrderEntries: Array
@@ -55,6 +54,7 @@ open class BaseExplorerActivity : BaseActivity() {
field = value
explorerViewModel.currentDirectoryPath = value
}
+ protected lateinit var fileOperationService: FileOperationService
protected lateinit var explorerElements: MutableList
protected lateinit var explorerAdapter: ExplorerElementAdapter
private var isCreating = true
@@ -87,6 +87,7 @@ open class BaseExplorerActivity : BaseActivity() {
setCurrentPath(currentDirectoryPath)
refresher.isRefreshing = false
}
+ bindFileOperationService()
}
class ExplorerViewModel: ViewModel() {
@@ -97,6 +98,21 @@ open class BaseExplorerActivity : BaseActivity() {
setContentView(R.layout.activity_explorer_base)
}
+ protected open fun bindFileOperationService(){
+ Intent(this, FileOperationService::class.java).also {
+ bindService(it, object : ServiceConnection {
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ val binder = service as FileOperationService.LocalBinder
+ fileOperationService = binder.getService()
+ binder.setGocryptfsVolume(gocryptfsVolume)
+ }
+ override fun onServiceDisconnected(arg0: ComponentName) {
+
+ }
+ }, Context.BIND_AUTO_CREATE)
+ }
+ }
+
private fun startFileViewer(cls: Class<*>, filePath: String, sortOrder: String = ""){
val intent = Intent(this, cls)
intent.putExtra("path", filePath)
@@ -274,97 +290,97 @@ open class BaseExplorerActivity : BaseActivity() {
dialog.show()
}
- protected fun checkPathOverwrite(path: String, isDirectory: Boolean): String? {
- var outputPath: String? = null
- if (gocryptfsVolume.pathExists(path)){
- val fileName = File(path).name
- val handler = Handler{ msg ->
- outputPath = msg.obj as String?
- throw RuntimeException()
+ protected fun checkPathOverwrite(items: ArrayList, dstDirectoryPath: String, callback: (ArrayList?) -> Unit) {
+ val srcDirectoryPath = items[0].explorerElement.parentPath
+ var ready = true
+ for (i in 0 until items.size) {
+ val testDstPath: String
+ if (items[i].dstPath == null){
+ testDstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].explorerElement.fullPath))
+ if (gocryptfsVolume.pathExists(testDstPath)){
+ ready = false
+ } else {
+ items[i].dstPath = testDstPath
+ }
+ } else {
+ testDstPath = items[i].dstPath!!
+ if (gocryptfsVolume.pathExists(testDstPath) && !items[i].overwriteConfirmed){
+ ready = false
+ }
}
- runOnUiThread {
- val dialog = ColoredAlertDialogBuilder(this)
+ if (!ready){
+ ColoredAlertDialogBuilder(this)
.setTitle(R.string.warning)
- .setMessage(getString(if (isDirectory){R.string.dir_overwrite_question} else {R.string.file_overwrite_question}, path))
+ .setMessage(getString(if (items[i].explorerElement.isDirectory){R.string.dir_overwrite_question} else {R.string.file_overwrite_question}, testDstPath))
+ .setPositiveButton(R.string.yes) {_, _ ->
+ items[i].dstPath = testDstPath
+ items[i].overwriteConfirmed = true
+ checkPathOverwrite(items, dstDirectoryPath, callback)
+ }
.setNegativeButton(R.string.no) { _, _ ->
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
val dialogEditText = dialogEditTextView.findViewById(R.id.dialog_edit_text)
- dialogEditText.setText(fileName)
+ dialogEditText.setText(items[i].explorerElement.name)
dialogEditText.selectAll()
val dialog = ColoredAlertDialogBuilder(this)
- .setView(dialogEditTextView)
- .setTitle(R.string.enter_new_name)
- .setPositiveButton(R.string.ok) { _, _ ->
- handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.pathJoin(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
- }
- .setNegativeButton(R.string.cancel) { _, _ -> handler.sendMessage(Message().apply { obj = null }) }
- .create()
+ .setView(dialogEditTextView)
+ .setTitle(R.string.enter_new_name)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ items[i].dstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].explorerElement.parentPath), dialogEditText.text.toString())
+ checkPathOverwrite(items, dstDirectoryPath, callback)
+ }
+ .setOnCancelListener{
+ callback(null)
+ }
+ .create()
dialogEditText.setOnEditorActionListener { _, _, _ ->
dialog.dismiss()
- handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.pathJoin(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
+ items[i].dstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].explorerElement.parentPath), dialogEditText.text.toString())
+ checkPathOverwrite(items, dstDirectoryPath, callback)
true
}
- dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
dialog.show()
}
- .setPositiveButton(R.string.yes) { _, _ -> handler.sendMessage(Message().apply { obj = path }) }
- .create()
- dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
- dialog.show()
+ .setOnCancelListener{
+ callback(null)
+ }
+ .show()
+ break
}
- try { Looper.loop() }
- catch (e: RuntimeException) {}
- } else {
- outputPath = path
}
- return outputPath
+ if (ready){
+ callback(items)
+ }
}
- protected fun importFilesFromUris(uris: List, task: LoadingTask, callback: (DialogInterface.OnClickListener)? = null): Boolean {
- var success = false
+ protected fun importFilesFromUris(uris: List, callback: (String?) -> Unit) {
+ val items = ArrayList()
for (uri in uris) {
- val fileName = PathUtils.getFilenameFromURI(task.activity, uri)
- if (fileName == null){
- task.stopTask {
- ColoredAlertDialogBuilder(task.activity)
+ val fileName = PathUtils.getFilenameFromURI(this, uri)
+ if (fileName == null) {
+ ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(getString(R.string.error_retrieving_filename, uri))
.setPositiveButton(R.string.ok, null)
.show()
- }
- success = false
+ items.clear()
break
} else {
- val dstPath = checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, fileName), false)
- if (dstPath == null){
- break
- } else {
- var message: String? = null
- try {
- success = gocryptfsVolume.importFile(task.activity, uri, dstPath)
- } catch (e: FileNotFoundException){
- message = if (e.message != null){
- e.message!!+"\n"
- } else {
- ""
+ items.add(OperationFile.fromExplorerElement(ExplorerElement(fileName, 1, -1, -1, currentDirectoryPath)))
+ }
+ }
+ if (items.size > 0) {
+ checkPathOverwrite(items, currentDirectoryPath) { checkedItems ->
+ checkedItems?.let {
+ fileOperationService.importFilesFromUris(checkedItems, uris){ failedItem ->
+ runOnUiThread {
+ callback(failedItem)
}
}
- if (!success || message != null) {
- task.stopTask {
- ColoredAlertDialogBuilder(task.activity)
- .setTitle(R.string.error)
- .setMessage((message ?: "")+getString(R.string.import_failed, uri))
- .setCancelable(callback == null)
- .setPositiveButton(R.string.ok, callback)
- .show()
- }
- break
- }
}
}
}
- return success
}
protected fun rename(old_name: String, new_name: String){
diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt
index 5f9070d..9b4a17a 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt
@@ -3,20 +3,20 @@ package sushi.hardcore.droidfs.explorers
import android.app.Activity
import android.content.Intent
import android.net.Uri
-import android.os.Looper
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.WindowManager
import android.widget.EditText
import android.widget.Toast
-import androidx.appcompat.app.AppCompatActivity
-import androidx.documentfile.provider.DocumentFile
import sushi.hardcore.droidfs.CameraActivity
import sushi.hardcore.droidfs.OpenActivity
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
-import sushi.hardcore.droidfs.util.*
+import sushi.hardcore.droidfs.file_operations.OperationFile
+import sushi.hardcore.droidfs.util.ExternalProvider
+import sushi.hardcore.droidfs.util.GocryptfsVolume
+import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File
@@ -30,7 +30,7 @@ class ExplorerActivity : BaseExplorerActivity() {
private var usf_decrypt = false
private var usf_share = false
private var currentItemAction = ItemsActions.NONE
- private val itemsToProcess = ArrayList()
+ private val itemsToProcess = ArrayList()
override fun init() {
setContentView(R.layout.activity_explorer)
usf_decrypt = sharedPrefs.getBoolean("usf_decrypt", false)
@@ -47,19 +47,17 @@ class ExplorerActivity : BaseExplorerActivity() {
if (fileName.isEmpty()) {
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
} else {
- checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, fileName), false)?.let {
- val handleID = gocryptfsVolume.openWriteMode(it)
- if (handleID == -1) {
- ColoredAlertDialogBuilder(this)
+ val handleID = gocryptfsVolume.openWriteMode(fileName) //don't check overwrite because openWriteMode open in read-write (doesn't erase content)
+ if (handleID == -1) {
+ ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.file_creation_failed)
.setPositiveButton(R.string.ok, null)
.show()
- } else {
- gocryptfsVolume.closeFile(handleID)
- setCurrentPath(currentDirectoryPath)
- invalidateOptionsMenu()
- }
+ } else {
+ gocryptfsVolume.closeFile(handleID)
+ setCurrentPath(currentDirectoryPath)
+ invalidateOptionsMenu()
}
}
}
@@ -138,162 +136,137 @@ class ExplorerActivity : BaseExplorerActivity() {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PICK_FILES_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) {
- object : LoadingTask(this, R.string.loading_msg_import){
- override fun doTask(activity: AppCompatActivity) {
- val uris: MutableList = ArrayList()
- val singleUri = data.data
- if (singleUri == null) { //multiples choices
- val clipData = data.clipData
- if (clipData != null){
- for (i in 0 until clipData.itemCount) {
- uris.add(clipData.getItemAt(i).uri)
- }
- }
- } else {
- uris.add(singleUri)
+ val uris: MutableList = ArrayList()
+ val singleUri = data.data
+ if (singleUri == null) { //multiples choices
+ val clipData = data.clipData
+ if (clipData != null){
+ for (i in 0 until clipData.itemCount) {
+ uris.add(clipData.getItemAt(i).uri)
}
- Looper.prepare()
- if (importFilesFromUris(uris, this)) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.success_import)
- .setMessage("""
+ }
+ } else {
+ uris.add(singleUri)
+ }
+ importFilesFromUris(uris){ failedItem ->
+ if (failedItem == null){
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.success_import)
+ .setMessage("""
${getString(R.string.success_import_msg)}
${getString(R.string.ask_for_wipe)}
""".trimIndent())
- .setPositiveButton(R.string.yes) { _, _ ->
- object : LoadingTask(activity, R.string.loading_msg_wipe){
- override fun doTask(activity: AppCompatActivity) {
- var success = true
- for (uri in uris) {
- val errorMsg = Wiper.wipe(activity, uri)
- if (errorMsg != null) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.error)
- .setMessage(getString(R.string.wipe_failed, errorMsg))
- .setPositiveButton(R.string.ok, null)
- .show()
- }
- success = false
- break
- }
- }
- if (success) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.wipe_successful)
- .setMessage(R.string.wipe_success_msg)
- .setPositiveButton(R.string.ok, null)
- .show()
- }
- }
+ .setPositiveButton(R.string.yes) { _, _ ->
+ fileOperationService.wipeUris(uris) { errorMsg ->
+ runOnUiThread {
+ if (errorMsg == null){
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.wipe_successful)
+ .setMessage(R.string.wipe_success_msg)
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(getString(R.string.wipe_failed, errorMsg))
+ .setPositiveButton(R.string.ok, null)
+ .show()
}
}
+
}
- .setNegativeButton(R.string.no, null)
- .show()
- }
- }
- }
- override fun doFinally(activity: AppCompatActivity){
- setCurrentPath(currentDirectoryPath)
+ }
+ .setNegativeButton(R.string.no, null)
+ .show()
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(getString(R.string.import_failed, failedItem))
+ .setPositiveButton(R.string.ok, null)
+ .show()
}
}
}
} else if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) {
- object : LoadingTask(this, R.string.loading_msg_export){
- override fun doTask(activity: AppCompatActivity) {
- data.data?.let {uri ->
- contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
- DocumentFile.fromTreeUri(activity, uri)?.let { treeDocumentFile ->
- var failedItem: String? = null
- for (i in explorerAdapter.selectedItems) {
- val element = explorerAdapter.getItem(i)
- val fullPath = PathUtils.pathJoin(currentDirectoryPath, element.name)
- failedItem = if (element.isDirectory) {
- recursiveExportDirectory(fullPath, treeDocumentFile)
- } else {
- if (exportFileInto(fullPath, treeDocumentFile)) null else fullPath
- }
- if (failedItem != null) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.error)
- .setMessage(getString(R.string.export_failed, failedItem))
- .setPositiveButton(R.string.ok, null)
- .show()
- }
- break
- }
- }
- if (failedItem == null) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.success_export)
- .setMessage(R.string.success_export_msg)
- .setPositiveButton(R.string.ok, null)
- .show()
- }
- }
+ data.data?.let { uri ->
+ fileOperationService.exportFiles(uri, explorerAdapter.selectedItems.map { i -> explorerElements[i] }){ failedItem ->
+ runOnUiThread {
+ if (failedItem == null){
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.success_export)
+ .setMessage(R.string.success_export_msg)
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(getString(R.string.export_failed, failedItem))
+ .setPositiveButton(R.string.ok, null)
+ .show()
}
}
}
- override fun doFinally(activity: AppCompatActivity) {
- unselectAll()
- }
+ unselectAll()
}
}
} else if (requestCode == PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) {
- object : LoadingTask(this, R.string.loading_msg_import){
- override fun doTask(activity: AppCompatActivity) {
- val remoteSessionID = data.getIntExtra("sessionID", -1)
- val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
- val path = data.getStringExtra("path")
- var failedItem: String? = null
- Looper.prepare()
- if (path == null) {
- val paths = data.getStringArrayListExtra("paths")
- val types = data.getIntegerArrayListExtra("types")
- if (types != null && paths != null){
- for (i in paths.indices) {
- failedItem = if (types[i] == 0) { //directory
- recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
- } else {
- safeImportFileFromOtherVolume(remoteGocryptfsVolume, paths[i], PathUtils.pathJoin(currentDirectoryPath, File(paths[i]).name))
- }
- if (failedItem != null) {
- break
- }
+ val remoteSessionID = data.getIntExtra("sessionID", -1)
+ val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
+ val path = data.getStringExtra("path")
+ val operationFiles = ArrayList()
+ if (path == null){ //multiples elements
+ val paths = data.getStringArrayListExtra("paths")
+ val types = data.getIntegerArrayListExtra("types")
+ if (types != null && paths != null){
+ for (i in paths.indices) {
+ operationFiles.add(
+ OperationFile.fromExplorerElement(
+ ExplorerElement(File(paths[i]).name, types[i].toShort(), -1, -1, PathUtils.getParentPath(paths[i]))
+ )
+ )
+ if (types[i] == 0){ //directory
+ remoteGocryptfsVolume.recursiveMapFiles(paths[i]).forEach {
+ operationFiles.add(OperationFile.fromExplorerElement(it))
}
}
+ }
+ }
+ } else {
+ operationFiles.add(
+ OperationFile.fromExplorerElement(
+ ExplorerElement(File(path).name, 1, -1, -1, PathUtils.getParentPath(path))
+ )
+ )
+ }
+ if (operationFiles.size > 0){
+ checkPathOverwrite(operationFiles, currentDirectoryPath) { items ->
+ if (items == null) {
+ remoteGocryptfsVolume.close()
} else {
- failedItem = safeImportFileFromOtherVolume(remoteGocryptfsVolume, path, PathUtils.pathJoin(currentDirectoryPath, File(path).name))
- }
- if (failedItem == null) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.success_import)
- .setMessage(R.string.success_import_msg)
- .setPositiveButton(R.string.ok, null)
- .show()
- }
- } else if (failedItem!!.isNotEmpty()){
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.error)
- .setMessage(getString(R.string.import_failed, failedItem))
- .setPositiveButton(R.string.ok, null)
- .show()
+ fileOperationService.copyElements(items, remoteGocryptfsVolume){ failedItem ->
+ runOnUiThread {
+ if (failedItem == null){
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.success_import)
+ .setMessage(R.string.success_import_msg)
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(getString(R.string.import_failed, failedItem))
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+ }
+ remoteGocryptfsVolume.close()
}
}
- remoteGocryptfsVolume.close()
- }
- override fun doFinally(activity: AppCompatActivity) {
- setCurrentPath(currentDirectoryPath)
}
+ } else {
+ remoteGocryptfsVolume.close()
}
}
}
@@ -344,7 +317,7 @@ class ExplorerActivity : BaseExplorerActivity() {
}
R.id.cut -> {
for (i in explorerAdapter.selectedItems){
- itemsToProcess.add(explorerElements[i])
+ itemsToProcess.add(OperationFile.fromExplorerElement(explorerElements[i]))
}
currentItemAction = ItemsActions.MOVE
unselectAll()
@@ -352,7 +325,12 @@ class ExplorerActivity : BaseExplorerActivity() {
}
R.id.copy -> {
for (i in explorerAdapter.selectedItems){
- itemsToProcess.add(explorerElements[i])
+ itemsToProcess.add(OperationFile.fromExplorerElement(explorerElements[i]))
+ if (explorerElements[i].isDirectory){
+ gocryptfsVolume.recursiveMapFiles(explorerElements[i].fullPath).forEach {
+ itemsToProcess.add(OperationFile.fromExplorerElement(it))
+ }
+ }
}
currentItemAction = ItemsActions.COPY
unselectAll()
@@ -360,81 +338,45 @@ class ExplorerActivity : BaseExplorerActivity() {
}
R.id.validate -> {
if (currentItemAction == ItemsActions.COPY){
- object : LoadingTask(this, R.string.loading_msg_copy){
- override fun doTask(activity: AppCompatActivity) {
- var failedItem: String? = null
- Looper.prepare()
- for (element in itemsToProcess) {
- val dstPath = checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, element.name), element.isDirectory)
- failedItem = if (dstPath == null){
- ""
- } else {
- if (element.isDirectory) {
- recursiveCopyDirectory(element.fullPath, dstPath)
- } else {
- if (copyFile(element.fullPath, dstPath)) null else element.fullPath
- }
- }
- if (failedItem != null){
- if (failedItem.isNotEmpty()) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
+ checkPathOverwrite(itemsToProcess, currentDirectoryPath){ items ->
+ items?.let {
+ fileOperationService.copyElements(it.toMutableList() as ArrayList){ failedItem ->
+ runOnUiThread {
+ if (failedItem != null){
+ ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
- .setMessage(getString(
- R.string.copy_failed,
- failedItem
- ))
+ .setMessage(getString(R.string.copy_failed, failedItem))
.setPositiveButton(R.string.ok, null)
.show()
- }
+ } else {
+ Toast.makeText(this, R.string.copy_success, Toast.LENGTH_SHORT).show()
}
- break
- }
- }
- if (failedItem == null) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(getString(R.string.copy_success))
- .setMessage(getString(R.string.copy_success_msg))
- .setPositiveButton(R.string.ok, null)
- .show()
}
}
}
- override fun doFinally(activity: AppCompatActivity) {
- cancelItemAction()
- unselectAll()
- setCurrentPath(currentDirectoryPath)
- }
+ cancelItemAction()
+ unselectAll()
}
} else if (currentItemAction == ItemsActions.MOVE){
- object : LoadingTask(this, R.string.loading_msg_move){
- override fun doTask(activity: AppCompatActivity) {
- Looper.prepare()
- val failedItem = moveElements(itemsToProcess, currentDirectoryPath)
- if (failedItem == null) {
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(getString(R.string.move_success))
- .setMessage(getString(R.string.move_success_msg))
- .setPositiveButton(R.string.ok, null)
- .show()
- }
- } else if (failedItem.isNotEmpty()){
- stopTask {
- ColoredAlertDialogBuilder(activity)
- .setTitle(R.string.error)
- .setMessage(getString(R.string.move_failed, failedItem))
- .setPositiveButton(R.string.ok, null)
- .show()
+ mapFileForMove(itemsToProcess, itemsToProcess[0].explorerElement.parentPath)
+ checkPathOverwrite(itemsToProcess, currentDirectoryPath){ items ->
+ items?.let {
+ fileOperationService.moveElements(it.toMutableList() as ArrayList){ failedItem ->
+ runOnUiThread {
+ if (failedItem != null){
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(getString(R.string.move_failed, failedItem))
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ } else {
+ Toast.makeText(this, R.string.move_success, Toast.LENGTH_SHORT).show()
+ }
}
}
}
- override fun doFinally(activity: AppCompatActivity) {
- cancelItemAction()
- unselectAll()
- setCurrentPath(currentDirectoryPath)
- }
+ cancelItemAction()
+ unselectAll()
}
}
true
@@ -473,6 +415,24 @@ class ExplorerActivity : BaseExplorerActivity() {
}
}
+ private fun mapFileForMove(items: ArrayList, srcDirectoryPath: String): ArrayList {
+ val newItems = ArrayList()
+ items.forEach {
+ if (it.explorerElement.isDirectory){
+ if (gocryptfsVolume.pathExists(PathUtils.pathJoin(currentDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, it.explorerElement.fullPath)))){
+ newItems.addAll(
+ mapFileForMove(
+ gocryptfsVolume.listDir(it.explorerElement.fullPath).map { e -> OperationFile.fromExplorerElement(e) } as ArrayList,
+ srcDirectoryPath
+ )
+ )
+ }
+ }
+ }
+ items.addAll(newItems)
+ return items
+ }
+
private fun cancelItemAction() {
if (currentItemAction != ItemsActions.NONE){
currentItemAction = ItemsActions.NONE
@@ -489,220 +449,13 @@ class ExplorerActivity : BaseExplorerActivity() {
}
}
- private fun copyFile(srcPath: String, dstPath: String): Boolean {
- var success = true
- val originalHandleId = gocryptfsVolume.openReadMode(srcPath)
- if (originalHandleId != -1){
- val newHandleId = gocryptfsVolume.openWriteMode(dstPath)
- if (newHandleId != -1){
- var offset: Long = 0
- val ioBuffer = ByteArray(GocryptfsVolume.DefaultBS)
- var length: Int
- while (gocryptfsVolume.readFile(originalHandleId, offset, ioBuffer).also { length = it } > 0) {
- val written = gocryptfsVolume.writeFile(newHandleId, offset, ioBuffer, length).toLong()
- if (written == length.toLong()) {
- offset += written
- } else {
- success = false
- break
- }
- }
- gocryptfsVolume.closeFile(newHandleId)
- } else {
- success = false
- }
- gocryptfsVolume.closeFile(originalHandleId)
- } else {
- success = false
- }
- return success
- }
-
- private fun recursiveCopyDirectory(srcDirectoryPath: String, dstDirectoryPath: String): String? {
- val mappedElements = gocryptfsVolume.recursiveMapFiles(srcDirectoryPath)
- if (!gocryptfsVolume.pathExists(dstDirectoryPath)){
- if (!gocryptfsVolume.mkdir(dstDirectoryPath)) {
- return srcDirectoryPath
- }
- }
- for (e in mappedElements) {
- val dstPath = checkPathOverwrite(PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, e.fullPath)), e.isDirectory)
- if (dstPath == null){
- return ""
- } else {
- if (e.isDirectory) {
- if (!gocryptfsVolume.pathExists(dstPath)){
- if (!gocryptfsVolume.mkdir(dstPath)){
- return e.fullPath
- }
- }
- } else {
- if (!copyFile(e.fullPath, dstPath)) {
- return e.fullPath
- }
- }
- }
- }
- return null
- }
-
- private fun moveDirectory(srcDirectoryPath: String, dstDirectoryPath: String): String? {
- if (!gocryptfsVolume.pathExists(dstDirectoryPath)) {
- if (!gocryptfsVolume.rename(srcDirectoryPath, dstDirectoryPath)) {
- return srcDirectoryPath
- }
- } else {
- moveElements(gocryptfsVolume.listDir(srcDirectoryPath), dstDirectoryPath)
- gocryptfsVolume.rmdir(srcDirectoryPath)
- }
- return null
- }
-
- private fun moveElements(elements: List, dstDirectoryPath: String): String? {
- for (element in elements){
- val dstPath = checkPathOverwrite(PathUtils.pathJoin(dstDirectoryPath, element.name), element.isDirectory)
- if (dstPath == null){
- return ""
- } else {
- if (element.isDirectory){
- moveDirectory(element.fullPath, dstPath)?.let{
- return it
- }
- } else {
- if (!gocryptfsVolume.rename(element.fullPath, dstPath)){
- return element.fullPath
- }
- }
- }
- }
- return null
- }
-
- private fun importFileFromOtherVolume(remoteGocryptfsVolume: GocryptfsVolume, srcPath: String, dstPath: String): Boolean {
- var success = true
- val srcHandleID = remoteGocryptfsVolume.openReadMode(srcPath)
- if (srcHandleID != -1) {
- val dstHandleID = gocryptfsVolume.openWriteMode(dstPath)
- if (dstHandleID != -1) {
- var length: Int
- val ioBuffer = ByteArray(GocryptfsVolume.DefaultBS)
- var offset: Long = 0
- while (remoteGocryptfsVolume.readFile(srcHandleID, offset, ioBuffer).also { length = it } > 0) {
- val written =
- gocryptfsVolume.writeFile(dstHandleID, offset, ioBuffer, length).toLong()
- if (written == length.toLong()) {
- offset += length.toLong()
- } else {
- success = false
- break
- }
- }
- gocryptfsVolume.closeFile(dstHandleID)
- }
- remoteGocryptfsVolume.closeFile(srcHandleID)
- }
- return success
- }
-
- private fun safeImportFileFromOtherVolume(remoteGocryptfsVolume: GocryptfsVolume, srcPath: String, dstPath: String): String? {
- val checkedDstPath = checkPathOverwrite(dstPath, false)
- return if (checkedDstPath == null){
- ""
- } else {
- if (importFileFromOtherVolume(remoteGocryptfsVolume, srcPath, checkedDstPath)) null else srcPath
- }
- }
-
- private fun recursiveImportDirectoryFromOtherVolume(remote_gocryptfsVolume: GocryptfsVolume, remote_directory_path: String, outputPath: String): String? {
- val mappedElements = remote_gocryptfsVolume.recursiveMapFiles(remote_directory_path)
- val dstDirectoryPath = checkPathOverwrite(PathUtils.pathJoin(outputPath, File(remote_directory_path).name), true)
- if (dstDirectoryPath == null){
- return ""
- } else {
- if (!gocryptfsVolume.pathExists(dstDirectoryPath)) {
- if (!gocryptfsVolume.mkdir(dstDirectoryPath)) {
- return remote_directory_path
- }
- }
- for (e in mappedElements) {
- val dstPath = checkPathOverwrite(PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(remote_directory_path, e.fullPath)), e.isDirectory)
- if (dstPath == null){
- return ""
- } else {
- if (e.isDirectory) {
- if (!gocryptfsVolume.pathExists(dstPath)){
- if (!gocryptfsVolume.mkdir(dstPath)){
- return e.fullPath
- }
- }
- } else {
- if (!importFileFromOtherVolume(remote_gocryptfsVolume, e.fullPath, dstPath)) {
- return e.fullPath
- }
- }
- }
- }
- }
- return null
- }
-
- private fun exportFileInto(srcPath: String, treeDocumentFile: DocumentFile): Boolean {
- val outputStream = treeDocumentFile.createFile("*/*", File(srcPath).name)?.uri?.let {
- contentResolver.openOutputStream(it)
- }
- return if (outputStream != null){
- gocryptfsVolume.exportFile(srcPath, outputStream)
- } else {
- false
- }
- }
-
- private fun recursiveExportDirectory(plain_directory_path: String, treeDocumentFile: DocumentFile): String? {
- treeDocumentFile.createDirectory(File(plain_directory_path).name)?.let {childTree ->
- val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
- for (e in explorerElements) {
- val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
- if (e.isDirectory) {
- val failedItem = recursiveExportDirectory(fullPath, childTree)
- failedItem?.let { return it }
- } else {
- if (!exportFileInto(fullPath, childTree)){
- return fullPath
- }
- }
- }
- return null
- }
- return treeDocumentFile.name
- }
-
- private fun recursiveRemoveDirectory(plain_directory_path: String): String? {
- val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
- for (e in explorerElements) {
- val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
- if (e.isDirectory) {
- val result = recursiveRemoveDirectory(fullPath)
- result?.let { return it }
- } else {
- if (!gocryptfsVolume.removeFile(fullPath)) {
- return fullPath
- }
- }
- }
- return if (!gocryptfsVolume.rmdir(plain_directory_path)) {
- plain_directory_path
- } else {
- null
- }
- }
-
private fun removeSelectedItems() {
var failedItem: String? = null
for (i in explorerAdapter.selectedItems) {
val element = explorerAdapter.getItem(i)
val fullPath = PathUtils.pathJoin(currentDirectoryPath, element.name)
if (element.isDirectory) {
- val result = recursiveRemoveDirectory(fullPath)
+ val result = gocryptfsVolume.recursiveRemoveDirectory(fullPath)
result?.let{ failedItem = it }
} else {
if (!gocryptfsVolume.removeFile(fullPath)) {
diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt
index b623dbd..2574854 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt
@@ -1,15 +1,11 @@
package sushi.hardcore.droidfs.explorers
-import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
-import android.os.Looper
import android.view.Menu
import android.view.MenuItem
import android.view.View
-import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.R
-import sushi.hardcore.droidfs.util.LoadingTask
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
class ExplorerActivityDrop : BaseExplorerActivity() {
@@ -31,54 +27,61 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.validate -> {
- object : LoadingTask(this, R.string.loading_msg_import) {
- override fun doTask(activity: AppCompatActivity) {
- val alertDialog = ColoredAlertDialogBuilder(activity)
- alertDialog.setCancelable(false)
- alertDialog.setPositiveButton(R.string.ok) { _, _ -> finish() }
- val errorMsg: String?
- val extras = intent.extras
- if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)){
- Looper.prepare()
- when (intent.action) {
- Intent.ACTION_SEND -> {
- val uri = intent.getParcelableExtra(Intent.EXTRA_STREAM)
- errorMsg = if (uri == null){
- getString(R.string.share_intent_parsing_failed)
- } else {
- if (importFilesFromUris(listOf(uri), this){ _, _ -> finish() }) null else ""
- }
- }
- Intent.ACTION_SEND_MULTIPLE -> {
- val uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
- errorMsg = if (uris != null){
- if (importFilesFromUris(uris, this){ _, _ -> finish() }) null else ""
- } else {
- getString(R.string.share_intent_parsing_failed)
- }
- }
- else -> {
- errorMsg = getString(R.string.share_intent_parsing_failed)
- }
+ val extras = intent.extras
+ val errorMsg: String? = if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) {
+ when (intent.action) {
+ Intent.ACTION_SEND -> {
+ val uri = intent.getParcelableExtra(Intent.EXTRA_STREAM)
+ if (uri == null) {
+ getString(R.string.share_intent_parsing_failed)
+ } else {
+ importFilesFromUris(listOf(uri), ::onImported)
+ null
}
- } else {
- errorMsg = getString(R.string.share_intent_parsing_failed)
}
- if (errorMsg == null || errorMsg.isNotEmpty()){
- if (errorMsg == null) {
- alertDialog.setTitle(R.string.success_import)
- alertDialog.setMessage(R.string.success_import_msg)
- } else if (errorMsg.isNotEmpty()) {
- alertDialog.setTitle(R.string.error)
- alertDialog.setMessage(errorMsg)
+ Intent.ACTION_SEND_MULTIPLE -> {
+ val uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
+ if (uris != null) {
+ importFilesFromUris(uris, ::onImported)
+ null
+ } else {
+ getString(R.string.share_intent_parsing_failed)
}
- stopTask { alertDialog.show() }
}
+ else -> getString(R.string.share_intent_parsing_failed)
}
+ } else {
+ getString(R.string.share_intent_parsing_failed)
+ }
+ errorMsg?.let {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(it)
+ .setPositiveButton(R.string.ok, null)
+ .show()
}
true
}
else -> super.onOptionsItemSelected(item)
}
}
+
+ private fun onImported(failedItem: String?){
+ if (failedItem == null) {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.success_import)
+ .setMessage(R.string.success_import_msg)
+ .setCancelable(false)
+ .setPositiveButton(R.string.ok){_, _ ->
+ finish()
+ }
+ .show()
+ } else {
+ ColoredAlertDialogBuilder(this)
+ .setTitle(R.string.error)
+ .setMessage(getString(R.string.import_failed, failedItem))
+ .setPositiveButton(R.string.ok, null)
+ .show()
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt
index 8003a35..85a7bee 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt
@@ -17,6 +17,10 @@ class ExplorerActivityPick : BaseExplorerActivity() {
resultIntent.putExtra("sessionID", gocryptfsVolume.sessionID)
}
+ override fun bindFileOperationService() {
+ //don't bind
+ }
+
override fun onExplorerItemClick(position: Int) {
val wasSelecting = explorerAdapter.selectedItems.isNotEmpty()
explorerAdapter.onItemClick(position)
diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerElement.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerElement.kt
index f011bd4..68e8b6e 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerElement.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerElement.kt
@@ -3,7 +3,7 @@ package sushi.hardcore.droidfs.explorers
import sushi.hardcore.droidfs.util.PathUtils
import java.util.*
-class ExplorerElement(val name: String, val elementType: Short, var size: Long, mtime: Long, parentPath: String) {
+class ExplorerElement(val name: String, val elementType: Short, var size: Long, val mtime: Long, val parentPath: String) {
val mTime = Date((mtime * 1000).toString().toLong())
val fullPath: String = PathUtils.pathJoin(parentPath, name)
diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_operations/OperationFile.kt b/app/src/main/java/sushi/hardcore/droidfs/file_operations/OperationFile.kt
new file mode 100644
index 0000000..cec8481
--- /dev/null
+++ b/app/src/main/java/sushi/hardcore/droidfs/file_operations/OperationFile.kt
@@ -0,0 +1,11 @@
+package sushi.hardcore.droidfs.file_operations
+
+import sushi.hardcore.droidfs.explorers.ExplorerElement
+
+class OperationFile(val explorerElement: ExplorerElement, var dstPath: String? = null, var overwriteConfirmed: Boolean = false) {
+ companion object {
+ fun fromExplorerElement(e: ExplorerElement): OperationFile {
+ return OperationFile(e, null)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt
index 6215cde..8b1e93f 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/util/GocryptfsVolume.kt
@@ -187,4 +187,24 @@ class GocryptfsVolume(var sessionID: Int) {
}
return result
}
+
+ fun recursiveRemoveDirectory(plain_directory_path: String): String? {
+ val explorerElements = listDir(plain_directory_path)
+ for (e in explorerElements) {
+ val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
+ if (e.isDirectory) {
+ val result = recursiveRemoveDirectory(fullPath)
+ result?.let { return it }
+ } else {
+ if (!removeFile(fullPath)) {
+ return fullPath
+ }
+ }
+ }
+ return if (!rmdir(plain_directory_path)) {
+ plain_directory_path
+ } else {
+ null
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt b/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt
index 949c979..0266c50 100644
--- a/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt
+++ b/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt
@@ -43,7 +43,17 @@ object PathUtils {
}
fun getRelativePath(parentPath: String, childPath: String): String {
- return childPath.substring(parentPath.length + 1)
+ return when {
+ parentPath.isEmpty() -> {
+ childPath
+ }
+ parentPath.length == childPath.length -> {
+ ""
+ }
+ else -> {
+ childPath.substring(parentPath.length + 1)
+ }
+ }
}
fun getFilenameFromURI(context: Context, uri: Uri): String? {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9e6ab3f..a931ee3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -133,8 +133,6 @@
Creating volume…
Changing password…
Opening volume…
- Importing selected files…
- Wiping original files…
Exporting files…
Unable to access this file
About
@@ -144,9 +142,7 @@
The DroidFS repository on the DryCat Gitea instance. Gitea is fully free and self-hosted. Source code, documentation, bug tracker…
Share
Export/Decrypt
- Copying selected items…
Copy of %s failed.
- The selected items have been successfully copied.
Copy successful !
Add
Take photo
@@ -159,9 +155,7 @@
Reset theme color
Reset theme color to the default one
Copy
- Moving selected items…
Move of %s failed.
- The selected items have been successfully moved.
Move successful !
Enter the timer duration (in s)
Please enter a numeric value
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0e42234..1f3fdbc 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=11657af6356b7587bfb37287b5992e94a9686d5c8a0a1b60b87b9928a2decde5
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists