Merge pull request #13947 from nextcloud/feature/offline-file-remove

Feature - Offline File Deletion
This commit is contained in:
Tobias Kaminsky 2024-11-20 12:26:24 +01:00 committed by GitHub
commit 9d7d5bb283
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 108 additions and 30 deletions

View file

@ -46,6 +46,11 @@ class OfflineOperationTypeAdapter : JsonSerializer<OfflineOperationType>, JsonDe
jsonObject.addProperty("newName", src.newName) jsonObject.addProperty("newName", src.newName)
} }
is OfflineOperationType.RemoveFile -> {
jsonObject.addProperty("type", src.type)
jsonObject.addProperty("path", src.path)
}
null -> Unit null -> Unit
} }
@ -78,6 +83,11 @@ class OfflineOperationTypeAdapter : JsonSerializer<OfflineOperationType>, JsonDe
jsonObject.get("newName").asString jsonObject.get("newName").asString
) )
OfflineOperationRawType.RemoveFile.name -> OfflineOperationType.RemoveFile(
jsonObject.get("type").asString,
jsonObject.get("path").asString
)
else -> null else -> null
} }
} }

View file

@ -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.common.utils.Log_OC
import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation
import com.owncloud.android.operations.CreateFolderOperation import com.owncloud.android.operations.CreateFolderOperation
import com.owncloud.android.operations.RemoveFileOperation
import com.owncloud.android.operations.RenameFileOperation import com.owncloud.android.operations.RenameFileOperation
import com.owncloud.android.utils.theme.ViewThemeUtils import com.owncloud.android.utils.theme.ViewThemeUtils
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -163,6 +164,16 @@ class OfflineOperationsWorker(
renameFileOperation?.execute(client) to renameFileOperation 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 -> { else -> {
Log_OC.d(TAG, "Unsupported operation type: ${operation.type}") Log_OC.d(TAG, "Unsupported operation type: ${operation.type}")
null null
@ -186,7 +197,15 @@ class OfflineOperationsWorker(
Log_OC.d(TAG, "$logMessage filename: ${operation.filename}, type: ${operation.type}") Log_OC.d(TAG, "$logMessage filename: ${operation.filename}, type: ${operation.type}")
if (result.isSuccess) { 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) fileDataStorageManager.offlineOperationDao.delete(operation)
notificationManager.update(totalOperations, currentSuccessfulOperationIndex, operation.filename ?: "") notificationManager.update(totalOperations, currentSuccessfulOperationIndex, operation.filename ?: "")
} else { } else {

View file

@ -24,10 +24,13 @@ sealed class OfflineOperationType {
var ocFileId: Long, var ocFileId: Long,
val newName: String val newName: String
) : OfflineOperationType() ) : OfflineOperationType()
data class RemoveFile(override val type: String, var path: String) : OfflineOperationType()
} }
enum class OfflineOperationRawType { enum class OfflineOperationRawType {
CreateFolder, CreateFolder,
CreateFile, CreateFile,
RenameFile RenameFile,
RemoveFile
} }

View file

@ -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) { public OfflineOperationEntity addCreateFolderOfflineOperation(String path, String filename, Long parentOCFileId) {
OfflineOperationEntity entity = new OfflineOperationEntity(); OfflineOperationEntity entity = new OfflineOperationEntity();
@ -246,6 +250,25 @@ public class FileDataStorageManager {
return filename; 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) { public void renameOfflineOperation(OCFile file, String newFolderName) {
var entity = offlineOperationDao.getByPath(file.getDecryptedRemotePath()); var entity = offlineOperationDao.getByPath(file.getDecryptedRemotePath());
if (entity == null) { if (entity == null) {

View file

@ -612,28 +612,11 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
localSize = localFile.length(); localSize = localFile.length();
} }
holder.getFileSize().setVisibility(View.VISIBLE); prepareFileSize(holder, file, localSize);
if (file.isOfflineOperation()) {
holder.getFileSize().setText(MainApp.string(R.string.oc_file_list_adapter_offline_operation_description_text));
} else {
holder.getFileSize().setText(DisplayUtils.bytesToHumanReadable(localSize));
}
holder.getFileSizeSeparator().setVisibility(View.VISIBLE);
} else { } else {
final long fileLength = file.getFileLength(); final long fileLength = file.getFileLength();
if (fileLength >= 0) { if (fileLength >= 0) {
holder.getFileSize().setVisibility(View.VISIBLE); prepareFileSize(holder, file, fileLength);
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);
} else { } else {
holder.getFileSize().setVisibility(View.GONE); holder.getFileSize().setVisibility(View.GONE);
holder.getFileSizeSeparator().setVisibility(View.GONE); holder.getFileSizeSeparator().setVisibility(View.GONE);
@ -671,6 +654,28 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
applyVisualsForOfflineOperations(holder, file); applyVisualsForOfflineOperations(holder, file);
} }
private void prepareFileSize(ListItemViewHolder holder, OCFile file, long size) {
holder.getFileSize().setVisibility(View.VISIBLE);
ViewExtensionsKt.setVisibleIf(holder.getFileSizeSeparator(), !file.isOfflineOperation());
String fileSizeText = getFileSizeText(file, size);
holder.getFileSize().setText(fileSizeText);
}
private String getFileSizeText(OCFile file, long size) {
OfflineOperationEntity entity = mStorageManager.getOfflineEntityFromOCFile(file);
boolean isRemoveOperation = entity != null && entity.getType() instanceof OfflineOperationType.RemoveFile;
if (isRemoveOperation) {
return activity.getString(R.string.oc_file_list_adapter_offline_operation_remove_description_text);
}
if (file.isOfflineOperation()) {
return activity.getString(R.string.oc_file_list_adapter_offline_operation_description_text);
}
return DisplayUtils.bytesToHumanReadable(size);
}
private void applyVisualsForOfflineOperations(ListItemViewHolder holder, OCFile file) { private void applyVisualsForOfflineOperations(ListItemViewHolder holder, OCFile file) {
ViewExtensionsKt.setVisibleIf(holder.getShared(), !file.isOfflineOperation()); ViewExtensionsKt.setVisibleIf(holder.getShared(), !file.isOfflineOperation());

View file

@ -90,17 +90,33 @@ class RemoveFilesDialogFragment : ConfirmationDialogFragment(), ConfirmationDial
fileDataStorageManager.deleteOfflineOperation(it) fileDataStorageManager.deleteOfflineOperation(it)
} }
if (files.isNotEmpty()) { if (requireActivity() is FileDisplayActivity) {
val cg = activity as ComponentsGetter? val activity = requireActivity() as FileDisplayActivity
cg?.fileOperationsHelper?.removeFiles(files, onlyLocalCopy, false) activity.connectivityService.isNetworkAndServerAvailable { result ->
} if (result) {
if (files.isNotEmpty()) {
val cg = activity as ComponentsGetter?
cg?.fileOperationsHelper?.removeFiles(files, onlyLocalCopy, false)
}
if (offlineFiles.isNotEmpty()) { if (offlineFiles.isNotEmpty()) {
val activity = requireActivity() as? FileDisplayActivity activity.refreshCurrentDirectory()
activity?.refreshCurrentDirectory() }
} } else {
files.forEach { file ->
fileDataStorageManager.addRemoveFileOfflineOperation(
file.decryptedRemotePath,
file.fileName,
file.parentId
)
}
finishActionMode() activity.refreshCurrentDirectory()
}
finishActionMode()
}
}
} }
override fun onNeutral(callerTag: String?) { override fun onNeutral(callerTag: String?) {

View file

@ -1269,4 +1269,6 @@
<string name="two_way_sync_activity_empty_list_desc">To set up a two way sync folder, please enable it in the details tab of the folder in question.</string> <string name="two_way_sync_activity_empty_list_desc">To set up a two way sync folder, please enable it in the details tab of the folder in question.</string>
<string name="two_way_sync_activity_title">Internal two way sync</string> <string name="two_way_sync_activity_title">Internal two way sync</string>
<string name="two_way_sync_activity_disable_all_button_title">Disable for all folders</string> <string name="two_way_sync_activity_disable_all_button_title">Disable for all folders</string>
<string name="oc_file_list_adapter_offline_operation_remove_description_text">Pending Remove Operation</string>
</resources> </resources>