|
|
|
@ -344,22 +344,29 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|
|
|
|
invalidateOptionsMenu()
|
|
|
|
|
}
|
|
|
|
|
} else if (currentItemAction == ItemsActions.MOVE){
|
|
|
|
|
mapFileForMove(itemsToProcess, itemsToProcess[0].explorerElement.parentPath)
|
|
|
|
|
checkPathOverwrite(itemsToProcess, currentDirectoryPath){ items ->
|
|
|
|
|
items?.let {
|
|
|
|
|
lifecycleScope.launch {
|
|
|
|
|
val failedItem = fileOperationService.moveElements(it.toMutableList() as ArrayList<OperationFile>)
|
|
|
|
|
if (failedItem == null) {
|
|
|
|
|
Toast.makeText(this@ExplorerActivity, R.string.move_success, Toast.LENGTH_SHORT).show()
|
|
|
|
|
} else {
|
|
|
|
|
CustomAlertDialogBuilder(this@ExplorerActivity, themeValue)
|
|
|
|
|
.setTitle(R.string.error)
|
|
|
|
|
.setMessage(getString(R.string.move_failed, failedItem))
|
|
|
|
|
.setPositiveButton(R.string.ok, null)
|
|
|
|
|
.show()
|
|
|
|
|
}
|
|
|
|
|
setCurrentPath(currentDirectoryPath)
|
|
|
|
|
itemsToProcess.forEach {
|
|
|
|
|
it.dstPath = PathUtils.pathJoin(currentDirectoryPath, it.explorerElement.name)
|
|
|
|
|
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 {
|
|
|
|
|
val failedItem = fileOperationService.moveElements(toMove, toClean)
|
|
|
|
|
if (failedItem == null) {
|
|
|
|
|
Toast.makeText(this@ExplorerActivity, R.string.move_success, Toast.LENGTH_SHORT).show()
|
|
|
|
|
} else {
|
|
|
|
|
CustomAlertDialogBuilder(this@ExplorerActivity, themeValue)
|
|
|
|
|
.setTitle(R.string.error)
|
|
|
|
|
.setMessage(getString(R.string.move_failed, failedItem))
|
|
|
|
|
.setPositiveButton(R.string.ok, null)
|
|
|
|
|
.show()
|
|
|
|
|
}
|
|
|
|
|
setCurrentPath(currentDirectoryPath)
|
|
|
|
|
}
|
|
|
|
|
cancelItemAction()
|
|
|
|
|
invalidateOptionsMenu()
|
|
|
|
@ -403,22 +410,85 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun mapFileForMove(items: ArrayList<OperationFile>, srcDirectoryPath: String): ArrayList<OperationFile> {
|
|
|
|
|
val newItems = ArrayList<OperationFile>()
|
|
|
|
|
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<OperationFile>,
|
|
|
|
|
srcDirectoryPath
|
|
|
|
|
/**
|
|
|
|
|
* Ask the user what to do if an item would overwrite another item in case of a move.
|
|
|
|
|
*
|
|
|
|
|
* All [OperationFile] must have a non-null [dstPath][OperationFile.dstPath].
|
|
|
|
|
*/
|
|
|
|
|
private fun checkMoveOverwrite(items: List<OperationFile>, callback: (List<OperationFile>?) -> Unit) {
|
|
|
|
|
for (item in items) {
|
|
|
|
|
if (gocryptfsVolume.pathExists(item.dstPath!!) && !item.overwriteConfirmed) {
|
|
|
|
|
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() {
|
|
|
|
|