Skip to content

Commit 25a4ee3

Browse files
Merge pull request #15453 from nextcloud/perf/remove-file
perf: increase file deletion performance πŸš€
2 parents 737a489 + a398bb9 commit 25a4ee3

File tree

5 files changed

+117
-127
lines changed

5 files changed

+117
-127
lines changed

β€Žapp/src/main/java/com/owncloud/android/operations/RemoveFileOperation.javaβ€Ž

Lines changed: 0 additions & 120 deletions
This file was deleted.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2025 Alper Ozturk <[email protected]>
5+
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <[email protected]>
6+
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
7+
* SPDX-FileCopyrightText: 2015 MarΓ­a Asensio Valverde <[email protected]>
8+
* SPDX-FileCopyrightText: 2012 David A. Velasco <[email protected]>
9+
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
10+
*/
11+
package com.owncloud.android.operations
12+
import android.content.Context
13+
import com.nextcloud.client.account.User
14+
import com.owncloud.android.datamodel.FileDataStorageManager
15+
import com.owncloud.android.datamodel.OCFile
16+
import com.owncloud.android.datamodel.ThumbnailsCacheManager
17+
import com.owncloud.android.lib.common.OwnCloudClient
18+
import com.owncloud.android.lib.common.operations.RemoteOperation
19+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
20+
import com.owncloud.android.lib.resources.files.RemoveFileRemoteOperation
21+
import com.owncloud.android.operations.common.SyncOperation
22+
import com.owncloud.android.utils.MimeTypeUtil
23+
24+
/**
25+
* Remote operation to remove a remote file or folder from an ownCloud server.
26+
*
27+
* @param file OCFile instance representing the remote file or folder to remove.
28+
* @param onlyLocalCopy If true, only the local copy will be removed (if it exists).
29+
* @param user User account associated with the operation.
30+
* @param isInBackground Flag indicating if the operation runs in the background.
31+
* @param context Android context.
32+
* @param storageManager Storage manager handling local file operations.
33+
*/
34+
@Suppress("LongParameterList")
35+
class RemoveFileOperation(
36+
val file: OCFile,
37+
private val onlyLocalCopy: Boolean,
38+
private val user: User,
39+
val isInBackground: Boolean,
40+
private val context: Context,
41+
storageManager: FileDataStorageManager
42+
) : SyncOperation(storageManager) {
43+
44+
/**
45+
* Executes the remove operation.
46+
*
47+
* If the file is an image, it will also be removed from the thumbnail cache.
48+
* Handles both encrypted and non-encrypted files. Removes the file locally if needed.
49+
*
50+
* @param client OwnCloudClient used to communicate with the remote server.
51+
* @return RemoteOperationResult indicating success or failure of the operation.
52+
*/
53+
override fun run(client: OwnCloudClient?): RemoteOperationResult<*> {
54+
var result: RemoteOperationResult<*>? = null
55+
val operation: RemoteOperation<*>?
56+
57+
var localRemovalFailed = false
58+
59+
if (onlyLocalCopy) {
60+
// generate resize image if image is deleted only locally, to save server request
61+
if (MimeTypeUtil.isImage(file.mimeType)) {
62+
ThumbnailsCacheManager.generateResizedImage(file)
63+
}
64+
65+
localRemovalFailed = !storageManager.removeFile(file, false, true)
66+
if (!localRemovalFailed) {
67+
result = RemoteOperationResult<Any?>(RemoteOperationResult.ResultCode.OK)
68+
}
69+
} else {
70+
operation = if (file.isEncrypted) {
71+
val parent = storageManager.getFileById(file.parentId)
72+
if (parent == null) {
73+
return RemoteOperationResult<Any?>(RemoteOperationResult.ResultCode.LOCAL_FILE_NOT_FOUND)
74+
}
75+
RemoveRemoteEncryptedFileOperation(
76+
file.remotePath,
77+
user,
78+
context,
79+
file.getEncryptedFileName(),
80+
parent,
81+
file.isFolder
82+
)
83+
} else {
84+
RemoveFileRemoteOperation(file.remotePath)
85+
}
86+
87+
result = operation.execute(client)
88+
if (result.isSuccess || result.code == RemoteOperationResult.ResultCode.FILE_NOT_FOUND) {
89+
localRemovalFailed = !storageManager.removeFile(file, true, true)
90+
}
91+
}
92+
93+
if (localRemovalFailed) {
94+
result = RemoteOperationResult<Any?>(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_REMOVED)
95+
}
96+
97+
return result ?: RemoteOperationResult<Any?>(RemoteOperationResult.ResultCode.CANCELLED)
98+
}
99+
}

β€Žapp/src/main/java/com/owncloud/android/services/OperationsService.javaβ€Ž

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,11 @@ private Pair<Target, RemoteOperation> newOperation(Intent operationIntent) {
690690
case ACTION_REMOVE:
691691
// Remove file or folder
692692
OCFile file = IntentExtensionsKt.getParcelableArgument(operationIntent, EXTRA_FILE, OCFile.class);
693+
if (file == null) {
694+
Log_OC.w(TAG, "file is null cannot remove file");
695+
break;
696+
}
697+
693698
boolean onlyLocalCopy = operationIntent.getBooleanExtra(EXTRA_REMOVE_ONLY_LOCAL, false);
694699
boolean inBackground = operationIntent.getBooleanExtra(EXTRA_IN_BACKGROUND, false);
695700
operation = new RemoveFileOperation(file,
@@ -748,6 +753,11 @@ private Pair<Target, RemoteOperation> newOperation(Intent operationIntent) {
748753

749754
case ACTION_RESTORE_VERSION:
750755
FileVersion fileVersion = IntentExtensionsKt.getParcelableArgument(operationIntent, EXTRA_FILE_VERSION, FileVersion.class);
756+
if (fileVersion == null) {
757+
Log_OC.w(TAG, "file version is null cannot restore file");
758+
break;
759+
}
760+
751761
operation = new RestoreFileVersionRemoteOperation(fileVersion.getLocalId(),
752762
fileVersion.getFileName());
753763
break;

β€Žapp/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.ktβ€Ž

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,24 @@ class RemoveFilesDialogFragment :
9797

9898
val fileActivity = getTypedActivity(FileActivity::class.java)
9999
val fda = getTypedActivity(FileDisplayActivity::class.java)
100-
101100
fileActivity?.connectivityService?.isNetworkAndServerAvailable { result ->
102101
if (result) {
102+
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment))
103+
103104
if (files.isNotEmpty()) {
104-
fileActivity.fileOperationsHelper?.removeFiles(files, onlyLocalCopy, false)
105+
// Display the snackbar message only when a single file is deleted.
106+
val inBackground = (files.size != 1)
107+
fileActivity.fileOperationsHelper?.removeFiles(files, onlyLocalCopy, inBackground)
105108
}
106109

107110
if (offlineFiles.isNotEmpty()) {
108111
fda?.refreshCurrentDirectory()
109112
}
113+
114+
fileActivity.dismissLoadingDialog()
110115
} else {
111116
if (onlyLocalCopy) {
112-
fileActivity.fileOperationsHelper?.removeFiles(files, true, false)
117+
fileActivity.fileOperationsHelper?.removeFiles(files, true, true)
113118
} else {
114119
files.forEach { file ->
115120
fileDataStorageManager.addRemoveFileOfflineOperation(file)

β€Žapp/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.javaβ€Ž

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -950,10 +950,6 @@ public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy, boolean
950950
for (OCFile file : files) {
951951
removeFile(file, onlyLocalCopy, inBackground);
952952
}
953-
954-
if (!inBackground) {
955-
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
956-
}
957953
}
958954

959955
public void removeFile(OCFile file, boolean onlyLocalCopy, boolean inBackground) {

0 commit comments

Comments
Β (0)