From a2d12f45fff1966eb1b52e62fbce7538f192cc7d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 5 Nov 2024 09:45:13 +0100 Subject: [PATCH] add offline file remove capability Signed-off-by: alperozturk --- .../OfflineOperationTypeAdapter.kt | 10 +++++ .../OfflineOperationsWorker.kt | 21 ++++++++- .../nextcloud/model/OfflineOperationType.kt | 5 ++- .../datamodel/FileDataStorageManager.java | 23 ++++++++++ .../android/ui/adapter/OCFileListAdapter.java | 43 +++++++++++-------- .../ui/dialog/RemoveFilesDialogFragment.kt | 34 +++++++++++---- app/src/main/res/values/strings.xml | 2 + 7 files changed, 108 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/typeAdapter/OfflineOperationTypeAdapter.kt b/app/src/main/java/com/nextcloud/client/database/typeAdapter/OfflineOperationTypeAdapter.kt index 32a28eacca..1b2fb2f42b 100644 --- a/app/src/main/java/com/nextcloud/client/database/typeAdapter/OfflineOperationTypeAdapter.kt +++ b/app/src/main/java/com/nextcloud/client/database/typeAdapter/OfflineOperationTypeAdapter.kt @@ -46,6 +46,11 @@ class OfflineOperationTypeAdapter : JsonSerializer, JsonDe jsonObject.addProperty("newName", src.newName) } + is OfflineOperationType.RemoveFile -> { + jsonObject.addProperty("type", src.type) + jsonObject.addProperty("path", src.path) + } + null -> Unit } @@ -78,6 +83,11 @@ class OfflineOperationTypeAdapter : JsonSerializer, JsonDe jsonObject.get("newName").asString ) + OfflineOperationRawType.RemoveFile.name -> OfflineOperationType.RemoveFile( + jsonObject.get("type").asString, + jsonObject.get("path").asString + ) + else -> null } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt index db471b79e2..f7aa61f3f2 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt @@ -25,6 +25,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation import com.owncloud.android.operations.CreateFolderOperation +import com.owncloud.android.operations.RemoveFileOperation import com.owncloud.android.operations.RenameFileOperation import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers @@ -163,6 +164,16 @@ class OfflineOperationsWorker( renameFileOperation?.execute(client) to renameFileOperation } + is OfflineOperationType.RemoveFile -> { + val removeFileOperation = withContext(NonCancellable) { + val operationType = (operation.type as OfflineOperationType.RemoveFile) + val ocFile = fileDataStorageManager.getFileByDecryptedRemotePath(operationType.path) + RemoveFileOperation(ocFile, false, user, true, context, fileDataStorageManager) + } + + removeFileOperation.execute(client) to removeFileOperation + } + else -> { Log_OC.d(TAG, "Unsupported operation type: ${operation.type}") null @@ -186,7 +197,15 @@ class OfflineOperationsWorker( Log_OC.d(TAG, "$logMessage filename: ${operation.filename}, type: ${operation.type}") if (result.isSuccess) { - repository.updateNextOperations(operation) + if (operation.type is OfflineOperationType.RemoveFile) { + val operationType = operation.type as OfflineOperationType.RemoveFile + fileDataStorageManager.getFileByDecryptedRemotePath(operationType.path)?.let { ocFile -> + repository.deleteOperation(ocFile) + } + } else { + repository.updateNextOperations(operation) + } + fileDataStorageManager.offlineOperationDao.delete(operation) notificationManager.update(totalOperations, currentSuccessfulOperationIndex, operation.filename ?: "") } else { diff --git a/app/src/main/java/com/nextcloud/model/OfflineOperationType.kt b/app/src/main/java/com/nextcloud/model/OfflineOperationType.kt index 028c8ac3dc..17b7e35298 100644 --- a/app/src/main/java/com/nextcloud/model/OfflineOperationType.kt +++ b/app/src/main/java/com/nextcloud/model/OfflineOperationType.kt @@ -24,10 +24,13 @@ sealed class OfflineOperationType { var ocFileId: Long, val newName: String ) : OfflineOperationType() + + data class RemoveFile(override val type: String, var path: String) : OfflineOperationType() } enum class OfflineOperationRawType { CreateFolder, CreateFile, - RenameFile + RenameFile, + RemoveFile } diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index f2f0666a73..8df5366f51 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -175,6 +175,10 @@ public class FileDataStorageManager { } } + public OfflineOperationEntity getOfflineEntityFromOCFile(OCFile file) { + return offlineOperationDao.getByPath(file.getDecryptedRemotePath()); + } + public OfflineOperationEntity addCreateFolderOfflineOperation(String path, String filename, Long parentOCFileId) { OfflineOperationEntity entity = new OfflineOperationEntity(); @@ -246,6 +250,25 @@ public class FileDataStorageManager { return filename; } + public void addRemoveFileOfflineOperation(String path, String filename, Long parentOCFileId) { + OfflineOperationEntity entity = new OfflineOperationEntity(); + + entity.setFilename(filename); + entity.setParentOCFileId(parentOCFileId); + + OfflineOperationType.RemoveFile operationType = new OfflineOperationType.RemoveFile(OfflineOperationRawType.RemoveFile.name(), path); + entity.setType(operationType); + entity.setPath(path); + + long createdAt = System.currentTimeMillis(); + long modificationTimestamp = System.currentTimeMillis(); + + entity.setCreatedAt(createdAt); + entity.setModifiedAt(modificationTimestamp / 1000); + + offlineOperationDao.insert(entity); + } + public void renameOfflineOperation(OCFile file, String newFolderName) { var entity = offlineOperationDao.getByPath(file.getDecryptedRemotePath()); if (entity == null) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 6c290c5548..eb41ff42a7 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -607,28 +607,11 @@ public class OCFileListAdapter extends RecyclerView.Adapter= 0) { - holder.getFileSize().setVisibility(View.VISIBLE); - - if (file.isOfflineOperation()) { - holder.getFileSize().setText(MainApp.string(R.string.oc_file_list_adapter_offline_operation_description_text)); - } else { - holder.getFileSize().setText(DisplayUtils.bytesToHumanReadable(fileLength)); - } - - holder.getFileSizeSeparator().setVisibility(View.VISIBLE); + prepareFileSize(holder, file, fileLength); } else { holder.getFileSize().setVisibility(View.GONE); holder.getFileSizeSeparator().setVisibility(View.GONE); @@ -666,6 +649,28 @@ public class OCFileListAdapter extends RecyclerView.Adapter + if (result) { + if (files.isNotEmpty()) { + val cg = activity as ComponentsGetter? + cg?.fileOperationsHelper?.removeFiles(files, onlyLocalCopy, false) + } - if (offlineFiles.isNotEmpty()) { - val activity = requireActivity() as? FileDisplayActivity - activity?.refreshCurrentDirectory() - } + if (offlineFiles.isNotEmpty()) { + activity.refreshCurrentDirectory() + } + } else { + files.forEach { file -> + fileDataStorageManager.addRemoveFileOfflineOperation( + file.decryptedRemotePath, + file.fileName, + file.parentId + ) + } - finishActionMode() + activity.refreshCurrentDirectory() + } + + finishActionMode() + } + } } override fun onNeutral(callerTag: String?) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index df0aa8fc00..524000ad38 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1263,4 +1263,6 @@ To set up a two way sync folder, please enable it in the details tab of the folder in question. Internal two way sync Disable for all folders + + Pending Remove Operation