forked from hardcoresushi/DroidFS
Fix move operation
This commit is contained in:
parent
b6b8bba666
commit
cba1418417
@ -344,11 +344,19 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
} else if (currentItemAction == ItemsActions.MOVE){
|
} else if (currentItemAction == ItemsActions.MOVE){
|
||||||
mapFileForMove(itemsToProcess, itemsToProcess[0].explorerElement.parentPath)
|
itemsToProcess.forEach {
|
||||||
checkPathOverwrite(itemsToProcess, currentDirectoryPath){ items ->
|
it.dstPath = PathUtils.pathJoin(currentDirectoryPath, it.explorerElement.name)
|
||||||
items?.let {
|
it.overwriteConfirmed = false // reset the field in case of a previous cancelled move
|
||||||
|
}
|
||||||
|
val toMove = ArrayList<OperationFile>(itemsToProcess.size)
|
||||||
|
val toClean = ArrayList<ExplorerElement>()
|
||||||
|
prepareFilesForMove(
|
||||||
|
itemsToProcess,
|
||||||
|
toMove,
|
||||||
|
toClean,
|
||||||
|
) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val failedItem = fileOperationService.moveElements(it.toMutableList() as ArrayList<OperationFile>)
|
val failedItem = fileOperationService.moveElements(toMove, toClean)
|
||||||
if (failedItem == null) {
|
if (failedItem == null) {
|
||||||
Toast.makeText(this@ExplorerActivity, R.string.move_success, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@ExplorerActivity, R.string.move_success, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
@ -360,7 +368,6 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
}
|
}
|
||||||
setCurrentPath(currentDirectoryPath)
|
setCurrentPath(currentDirectoryPath)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
cancelItemAction()
|
cancelItemAction()
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
@ -403,22 +410,85 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mapFileForMove(items: ArrayList<OperationFile>, srcDirectoryPath: String): ArrayList<OperationFile> {
|
/**
|
||||||
val newItems = ArrayList<OperationFile>()
|
* Ask the user what to do if an item would overwrite another item in case of a move.
|
||||||
items.forEach {
|
*
|
||||||
if (it.explorerElement.isDirectory){
|
* All [OperationFile] must have a non-null [dstPath][OperationFile.dstPath].
|
||||||
if (gocryptfsVolume.pathExists(PathUtils.pathJoin(currentDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, it.explorerElement.fullPath)))){
|
*/
|
||||||
newItems.addAll(
|
private fun checkMoveOverwrite(items: List<OperationFile>, callback: (List<OperationFile>?) -> Unit) {
|
||||||
mapFileForMove(
|
for (item in items) {
|
||||||
gocryptfsVolume.listDir(it.explorerElement.fullPath).map { e -> OperationFile.fromExplorerElement(e) } as ArrayList<OperationFile>,
|
if (gocryptfsVolume.pathExists(item.dstPath!!) && !item.overwriteConfirmed) {
|
||||||
srcDirectoryPath
|
CustomAlertDialogBuilder(this, themeValue)
|
||||||
|
.setTitle(R.string.warning)
|
||||||
|
.setMessage(
|
||||||
|
getString(
|
||||||
|
if (item.explorerElement.isDirectory) {
|
||||||
|
R.string.dir_overwrite_question
|
||||||
|
} else {
|
||||||
|
R.string.file_overwrite_question
|
||||||
|
},
|
||||||
|
item.dstPath!!
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
.setPositiveButton(R.string.yes) {_, _ ->
|
||||||
|
item.overwriteConfirmed = true
|
||||||
|
checkMoveOverwrite(items, callback)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.no) { _, _ ->
|
||||||
|
with(EditTextDialog(this, R.string.enter_new_name) {
|
||||||
|
item.dstPath = PathUtils.pathJoin(PathUtils.getParentPath(item.dstPath!!), it)
|
||||||
|
checkMoveOverwrite(items, callback)
|
||||||
|
}) {
|
||||||
|
setSelectedText(item.explorerElement.name)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for destination overwriting in case of a move operation.
|
||||||
|
*
|
||||||
|
* If the user decides to merge the content of a folder, the function recursively tests all
|
||||||
|
* children of the source folder to see if they will overwrite.
|
||||||
|
*
|
||||||
|
* The items to be moved are stored in [toMove]. We also need to keep track of the merged
|
||||||
|
* folders to delete them after the move. These folders are stored in [toClean].
|
||||||
|
*/
|
||||||
|
private fun prepareFilesForMove(
|
||||||
|
items: List<OperationFile>,
|
||||||
|
toMove: ArrayList<OperationFile>,
|
||||||
|
toClean: ArrayList<ExplorerElement>,
|
||||||
|
onReady: () -> Unit
|
||||||
|
) {
|
||||||
|
checkMoveOverwrite(items) { checkedItems ->
|
||||||
|
checkedItems?.let {
|
||||||
|
for (item in checkedItems) {
|
||||||
|
if (!item.overwriteConfirmed || !item.explorerElement.isDirectory) {
|
||||||
|
toMove.add(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val toCheck = mutableListOf<OperationFile>()
|
||||||
|
for (item in checkedItems) {
|
||||||
|
if (item.overwriteConfirmed && item.explorerElement.isDirectory) {
|
||||||
|
val children = gocryptfsVolume.listDir(item.explorerElement.fullPath)
|
||||||
|
toCheck.addAll(children.map {
|
||||||
|
OperationFile(it, PathUtils.pathJoin(item.dstPath!!, it.name))
|
||||||
|
})
|
||||||
|
toClean.add(item.explorerElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toCheck.isEmpty()) {
|
||||||
|
onReady()
|
||||||
|
} else {
|
||||||
|
prepareFilesForMove(toCheck, toMove, toClean, onReady)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items.addAll(newItems)
|
|
||||||
return items
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancelItemAction() {
|
private fun cancelItemAction() {
|
||||||
|
@ -183,32 +183,26 @@ class FileOperationService : Service() {
|
|||||||
waitForTask(notification, task).failedItem
|
waitForTask(notification, task).failedItem
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun moveElements(items: ArrayList<OperationFile>): String? = coroutineScope {
|
suspend fun moveElements(toMove: List<OperationFile>, toClean: List<ExplorerElement>): String? = coroutineScope {
|
||||||
val notification = showNotification(R.string.file_op_move_msg, items.size)
|
val notification = showNotification(R.string.file_op_move_msg, toMove.size)
|
||||||
val task = async {
|
val task = async(Dispatchers.IO) {
|
||||||
|
val total = toMove.size+toClean.size
|
||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
withContext(Dispatchers.IO) {
|
for ((i, item) in toMove.withIndex()) {
|
||||||
val mergedFolders = ArrayList<String>()
|
if (!gocryptfsVolume.rename(item.explorerElement.fullPath, item.dstPath!!)) {
|
||||||
for (i in 0 until items.size) {
|
failedItem = item.explorerElement.fullPath
|
||||||
if (items[i].explorerElement.isDirectory && gocryptfsVolume.pathExists(items[i].dstPath!!)) { //folder will be merged
|
|
||||||
mergedFolders.add(items[i].explorerElement.fullPath)
|
|
||||||
} else {
|
|
||||||
if (!gocryptfsVolume.rename(items[i].explorerElement.fullPath, items[i].dstPath!!)) {
|
|
||||||
failedItem = items[i].explorerElement.fullPath
|
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
updateNotificationProgress(notification, i+1, items.size)
|
updateNotificationProgress(notification, i+1, total)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failedItem == null) {
|
if (failedItem == null) {
|
||||||
for (i in 0 until mergedFolders.size) {
|
for ((i, folder) in toClean.asReversed().withIndex()) {
|
||||||
if (!gocryptfsVolume.rmdir(mergedFolders[i])) {
|
if (!gocryptfsVolume.rmdir(folder.fullPath)) {
|
||||||
failedItem = mergedFolders[i]
|
failedItem = folder.fullPath
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
updateNotificationProgress(notification, items.size-(mergedFolders.size-i), items.size)
|
updateNotificationProgress(notification, toMove.size+i+1, total)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user