Offload file discovery for copy in coroutine

This commit is contained in:
Matéo Duparc 2023-05-11 21:20:19 +02:00
parent cdf98a7190
commit 393c458495
Signed by: hardcoresushi
GPG Key ID: AFE384344A45E13A
2 changed files with 63 additions and 50 deletions

View File

@ -373,10 +373,10 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene
}.show()
}
protected fun checkPathOverwrite(items: ArrayList<OperationFile>, dstDirectoryPath: String, callback: (ArrayList<OperationFile>?) -> Unit) {
protected fun checkPathOverwrite(items: List<OperationFile>, dstDirectoryPath: String, callback: (List<OperationFile>?) -> Unit) {
val srcDirectoryPath = items[0].parentPath
var ready = true
for (i in 0 until items.size) {
for (i in items.indices) {
val testDstPath: String
if (items[i].dstPath == null){
testDstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].srcPath))
@ -410,7 +410,7 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene
with(EditTextDialog(this, R.string.enter_new_name) {
items[i].dstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].parentPath), it)
if (items[i].isDirectory) {
for (j in 0 until items.size){
for (j in items.indices) {
if (PathUtils.isChildOf(items[j].srcPath, items[i].srcPath)) {
items[j].dstPath = PathUtils.pathJoin(items[i].dstPath!!, PathUtils.getRelativePath(items[i].srcPath, items[j].srcPath))
}

View File

@ -9,9 +9,11 @@ import android.widget.Toast
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.lifecycleScope
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.launch
import sushi.hardcore.droidfs.CameraActivity
import sushi.hardcore.droidfs.LoadingTask
import sushi.hardcore.droidfs.MainActivity
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
@ -37,45 +39,29 @@ class ExplorerActivity : BaseExplorerActivity() {
val srcVolumeId = resultIntent.getIntExtra("volumeId", -1)
val srcEncryptedVolume = app.volumeManager.getVolume(srcVolumeId)!!
val path = resultIntent.getStringExtra("path")
val operationFiles = ArrayList<OperationFile>()
if (path == null){ //multiples elements
val paths = resultIntent.getStringArrayListExtra("paths")
val types = resultIntent.getIntegerArrayListExtra("types")
if (types != null && paths != null){
for (i in paths.indices) {
operationFiles.add(
OperationFile(paths[i], types[i])
)
if (types[i] == Stat.S_IFDIR) {
srcEncryptedVolume.recursiveMapFiles(paths[i])?.forEach {
operationFiles.add(OperationFile.fromExplorerElement(it))
object : LoadingTask<List<OperationFile>>(this, theme, R.string.discovering_files) {
override suspend fun doTask(): List<OperationFile> {
val operationFiles = ArrayList<OperationFile>()
for (i in paths.indices) {
operationFiles.add(OperationFile(paths[i], types[i]))
if (types[i] == Stat.S_IFDIR) {
srcEncryptedVolume.recursiveMapFiles(paths[i])?.forEach {
operationFiles.add(OperationFile.fromExplorerElement(it))
}
}
}
return operationFiles
}
}.startTask(lifecycleScope) { operationFiles ->
importFilesFromVolume(srcVolumeId, operationFiles)
}
}
} else {
operationFiles.add(
OperationFile(path, Stat.S_IFREG)
)
}
if (operationFiles.size > 0){
checkPathOverwrite(operationFiles, currentDirectoryPath) { items ->
if (items != null) {
// stop loading thumbnails while writing files
explorerAdapter.loadThumbnails = false
activityScope.launch {
onTaskResult(
fileOperationService.copyElements(
volumeId,
items,
srcVolumeId
), R.string.import_failed, R.string.success_import
)
explorerAdapter.loadThumbnails = true
setCurrentPath(currentDirectoryPath)
}
}
}
importFilesFromVolume(srcVolumeId, arrayListOf(OperationFile(path, Stat.S_IFREG)))
}
}
}
@ -120,6 +106,27 @@ class ExplorerActivity : BaseExplorerActivity() {
}
}
private fun importFilesFromVolume(srcVolumeId: Int, operationFiles: List<OperationFile>) {
checkPathOverwrite(operationFiles, currentDirectoryPath) { items ->
if (items != null) {
// stop loading thumbnails while writing files
explorerAdapter.loadThumbnails = false
activityScope.launch {
onTaskResult(
fileOperationService.copyElements(
volumeId,
items,
srcVolumeId
), R.string.import_failed, R.string.success_import
)
explorerAdapter.loadThumbnails = true
setCurrentPath(currentDirectoryPath)
}
}
}
}
private fun onImportComplete(urisToWipe: List<Uri>, rootFile: DocumentFile? = null) {
CustomAlertDialogBuilder(this, theme)
.setTitle(R.string.success_import)
@ -289,11 +296,6 @@ class ExplorerActivity : BaseExplorerActivity() {
R.id.copy -> {
for (i in explorerAdapter.selectedItems){
itemsToProcess.add(OperationFile.fromExplorerElement(explorerElements[i]))
if (explorerElements[i].isDirectory){
encryptedVolume.recursiveMapFiles(explorerElements[i].fullPath)?.forEach {
itemsToProcess.add(OperationFile.fromExplorerElement(it))
}
}
}
currentItemAction = ItemsActions.COPY
unselectAll()
@ -301,20 +303,31 @@ class ExplorerActivity : BaseExplorerActivity() {
}
R.id.validate -> {
if (currentItemAction == ItemsActions.COPY){
checkPathOverwrite(itemsToProcess, currentDirectoryPath) {
// copying before being cleared
it?.toMutableList()?.let { items ->
activityScope.launch {
onTaskResult(
fileOperationService.copyElements(volumeId, items),
R.string.copy_failed,
R.string.copy_success,
)
setCurrentPath(currentDirectoryPath)
object : LoadingTask<List<OperationFile>>(this, theme, R.string.discovering_files) {
override suspend fun doTask(): List<OperationFile> {
val items = itemsToProcess.toMutableList()
itemsToProcess.filter { it.isDirectory }.forEach { dir ->
encryptedVolume.recursiveMapFiles(dir.srcPath)?.forEach {
items.add(OperationFile.fromExplorerElement(it))
}
}
return items
}
}.startTask(lifecycleScope) { items ->
checkPathOverwrite(items, currentDirectoryPath) {
it?.let { checkedItems ->
activityScope.launch {
onTaskResult(
fileOperationService.copyElements(volumeId, checkedItems),
R.string.copy_failed,
R.string.copy_success,
)
setCurrentPath(currentDirectoryPath)
}
}
cancelItemAction()
invalidateOptionsMenu()
}
cancelItemAction()
invalidateOptionsMenu()
}
} else if (currentItemAction == ItemsActions.MOVE){
itemsToProcess.forEach {