forked from hardcoresushi/DroidFS
Offload file discovery for copy in coroutine
This commit is contained in:
parent
cdf98a7190
commit
393c458495
@ -373,10 +373,10 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene
|
|||||||
}.show()
|
}.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
|
val srcDirectoryPath = items[0].parentPath
|
||||||
var ready = true
|
var ready = true
|
||||||
for (i in 0 until items.size) {
|
for (i in items.indices) {
|
||||||
val testDstPath: String
|
val testDstPath: String
|
||||||
if (items[i].dstPath == null){
|
if (items[i].dstPath == null){
|
||||||
testDstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].srcPath))
|
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) {
|
with(EditTextDialog(this, R.string.enter_new_name) {
|
||||||
items[i].dstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].parentPath), it)
|
items[i].dstPath = PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, items[i].parentPath), it)
|
||||||
if (items[i].isDirectory) {
|
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)) {
|
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))
|
items[j].dstPath = PathUtils.pathJoin(items[i].dstPath!!, PathUtils.getRelativePath(items[i].srcPath, items[j].srcPath))
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,11 @@ import android.widget.Toast
|
|||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import sushi.hardcore.droidfs.CameraActivity
|
import sushi.hardcore.droidfs.CameraActivity
|
||||||
|
import sushi.hardcore.droidfs.LoadingTask
|
||||||
import sushi.hardcore.droidfs.MainActivity
|
import sushi.hardcore.droidfs.MainActivity
|
||||||
import sushi.hardcore.droidfs.R
|
import sushi.hardcore.droidfs.R
|
||||||
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
|
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
|
||||||
@ -37,45 +39,29 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
val srcVolumeId = resultIntent.getIntExtra("volumeId", -1)
|
val srcVolumeId = resultIntent.getIntExtra("volumeId", -1)
|
||||||
val srcEncryptedVolume = app.volumeManager.getVolume(srcVolumeId)!!
|
val srcEncryptedVolume = app.volumeManager.getVolume(srcVolumeId)!!
|
||||||
val path = resultIntent.getStringExtra("path")
|
val path = resultIntent.getStringExtra("path")
|
||||||
val operationFiles = ArrayList<OperationFile>()
|
|
||||||
if (path == null){ //multiples elements
|
if (path == null){ //multiples elements
|
||||||
val paths = resultIntent.getStringArrayListExtra("paths")
|
val paths = resultIntent.getStringArrayListExtra("paths")
|
||||||
val types = resultIntent.getIntegerArrayListExtra("types")
|
val types = resultIntent.getIntegerArrayListExtra("types")
|
||||||
if (types != null && paths != null){
|
if (types != null && paths != null){
|
||||||
for (i in paths.indices) {
|
object : LoadingTask<List<OperationFile>>(this, theme, R.string.discovering_files) {
|
||||||
operationFiles.add(
|
override suspend fun doTask(): List<OperationFile> {
|
||||||
OperationFile(paths[i], types[i])
|
val operationFiles = ArrayList<OperationFile>()
|
||||||
)
|
for (i in paths.indices) {
|
||||||
if (types[i] == Stat.S_IFDIR) {
|
operationFiles.add(OperationFile(paths[i], types[i]))
|
||||||
srcEncryptedVolume.recursiveMapFiles(paths[i])?.forEach {
|
if (types[i] == Stat.S_IFDIR) {
|
||||||
operationFiles.add(OperationFile.fromExplorerElement(it))
|
srcEncryptedVolume.recursiveMapFiles(paths[i])?.forEach {
|
||||||
|
operationFiles.add(OperationFile.fromExplorerElement(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return operationFiles
|
||||||
}
|
}
|
||||||
|
}.startTask(lifecycleScope) { operationFiles ->
|
||||||
|
importFilesFromVolume(srcVolumeId, operationFiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
operationFiles.add(
|
importFilesFromVolume(srcVolumeId, arrayListOf(OperationFile(path, Stat.S_IFREG)))
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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) {
|
private fun onImportComplete(urisToWipe: List<Uri>, rootFile: DocumentFile? = null) {
|
||||||
CustomAlertDialogBuilder(this, theme)
|
CustomAlertDialogBuilder(this, theme)
|
||||||
.setTitle(R.string.success_import)
|
.setTitle(R.string.success_import)
|
||||||
@ -289,11 +296,6 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
R.id.copy -> {
|
R.id.copy -> {
|
||||||
for (i in explorerAdapter.selectedItems){
|
for (i in explorerAdapter.selectedItems){
|
||||||
itemsToProcess.add(OperationFile.fromExplorerElement(explorerElements[i]))
|
itemsToProcess.add(OperationFile.fromExplorerElement(explorerElements[i]))
|
||||||
if (explorerElements[i].isDirectory){
|
|
||||||
encryptedVolume.recursiveMapFiles(explorerElements[i].fullPath)?.forEach {
|
|
||||||
itemsToProcess.add(OperationFile.fromExplorerElement(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
currentItemAction = ItemsActions.COPY
|
currentItemAction = ItemsActions.COPY
|
||||||
unselectAll()
|
unselectAll()
|
||||||
@ -301,20 +303,31 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
}
|
}
|
||||||
R.id.validate -> {
|
R.id.validate -> {
|
||||||
if (currentItemAction == ItemsActions.COPY){
|
if (currentItemAction == ItemsActions.COPY){
|
||||||
checkPathOverwrite(itemsToProcess, currentDirectoryPath) {
|
object : LoadingTask<List<OperationFile>>(this, theme, R.string.discovering_files) {
|
||||||
// copying before being cleared
|
override suspend fun doTask(): List<OperationFile> {
|
||||||
it?.toMutableList()?.let { items ->
|
val items = itemsToProcess.toMutableList()
|
||||||
activityScope.launch {
|
itemsToProcess.filter { it.isDirectory }.forEach { dir ->
|
||||||
onTaskResult(
|
encryptedVolume.recursiveMapFiles(dir.srcPath)?.forEach {
|
||||||
fileOperationService.copyElements(volumeId, items),
|
items.add(OperationFile.fromExplorerElement(it))
|
||||||
R.string.copy_failed,
|
}
|
||||||
R.string.copy_success,
|
|
||||||
)
|
|
||||||
setCurrentPath(currentDirectoryPath)
|
|
||||||
}
|
}
|
||||||
|
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){
|
} else if (currentItemAction == ItemsActions.MOVE){
|
||||||
itemsToProcess.forEach {
|
itemsToProcess.forEach {
|
||||||
|
Loading…
Reference in New Issue
Block a user