diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt
index 9c343e640c71..8c71a8b6677e 100644
--- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt
+++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt
@@ -39,7 +39,11 @@ import com.owncloud.android.db.OCUpload
import com.owncloud.android.db.UploadResult
import com.owncloud.android.files.services.NameCollisionPolicy
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
+import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation
+import com.owncloud.android.lib.resources.files.model.RemoteFile
+import com.owncloud.android.utils.FileUtil
import java.io.File
import javax.inject.Inject
@@ -255,6 +259,25 @@ class FileUploadHelper {
}
}
+ @Suppress("MagicNumber")
+ fun isSameFileOnRemote(user: User, localFile: File, remotePath: String, context: Context): Boolean {
+ // Compare remote file to local file
+ val localLastModifiedTimestamp = localFile.lastModified() / 1000 // remote file timestamp in milli not micro sec
+ val localCreationTimestamp = FileUtil.getCreationTimestamp(localFile)
+ val localSize: Long = localFile.length()
+
+ val operation = ReadFileRemoteOperation(remotePath)
+ val result: RemoteOperationResult<*> = operation.execute(user, context)
+ if (result.isSuccess) {
+ val remoteFile = result.data[0] as RemoteFile
+ return remoteFile.size == localSize &&
+ localCreationTimestamp != null &&
+ localCreationTimestamp == remoteFile.creationTimestamp &&
+ remoteFile.modifiedTimestamp == localLastModifiedTimestamp * 1000
+ }
+ return false
+ }
+
class UploadNotificationActionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val accountName = intent.getStringExtra(FileUploadWorker.EXTRA_ACCOUNT_NAME)
diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt
index 2397e3bed7bb..b00d3a37354f 100644
--- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt
+++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt
@@ -259,6 +259,14 @@ class FileUploadWorker(
return
}
+ // Only notify if it is not same file on remote that causes conflict
+ if (uploadResult.code == ResultCode.SYNC_CONFLICT && FileUploadHelper().isSameFileOnRemote(
+ uploadFileOperation.user, File(uploadFileOperation.storagePath), uploadFileOperation.remotePath, context
+ )
+ ) {
+ return
+ }
+
val notDelayed = uploadResult.code !in setOf(
ResultCode.DELAYED_FOR_WIFI,
ResultCode.DELAYED_FOR_CHARGING,
diff --git a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
index acc9dc9cd79a..be3fdf15e1dc 100644
--- a/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
+++ b/app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
@@ -34,6 +34,7 @@
import com.nextcloud.client.account.CurrentAccountProvider;
import com.nextcloud.client.account.User;
+import com.nextcloud.client.jobs.upload.FileUploadHelper;
import com.nextcloud.client.jobs.upload.FileUploadWorker;
import com.owncloud.android.MainApp;
import com.owncloud.android.db.OCUpload;
@@ -44,6 +45,7 @@
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.operations.UploadFileOperation;
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -737,6 +739,25 @@ public void updateDatabaseUploadResult(RemoteOperationResult uploadResult, Uploa
upload.getRemotePath(),
localPath
);
+ } else if (uploadResult.getCode() == RemoteOperationResult.ResultCode.SYNC_CONFLICT &&
+ new FileUploadHelper().isSameFileOnRemote(
+ upload.getUser(), new File(upload.getStoragePath()), upload.getRemotePath(), upload.getContext())) {
+
+ updateUploadStatus(
+ upload.getOCUploadId(),
+ UploadStatus.UPLOAD_SUCCEEDED,
+ UploadResult.SAME_FILE_CONFLICT,
+ upload.getRemotePath(),
+ localPath
+ );
+ } else if (uploadResult.getCode() == RemoteOperationResult.ResultCode.LOCAL_FILE_NOT_FOUND) {
+ updateUploadStatus(
+ upload.getOCUploadId(),
+ UploadStatus.UPLOAD_SUCCEEDED,
+ UploadResult.FILE_NOT_FOUND,
+ upload.getRemotePath(),
+ localPath
+ );
} else {
updateUploadStatus(
upload.getOCUploadId(),
diff --git a/app/src/main/java/com/owncloud/android/db/UploadResult.java b/app/src/main/java/com/owncloud/android/db/UploadResult.java
index 17533f0413be..919be585cb19 100644
--- a/app/src/main/java/com/owncloud/android/db/UploadResult.java
+++ b/app/src/main/java/com/owncloud/android/db/UploadResult.java
@@ -45,7 +45,8 @@ public enum UploadResult {
SYNC_CONFLICT(19),
CANNOT_CREATE_FILE(20),
LOCAL_STORAGE_NOT_COPIED(21),
- QUOTA_EXCEEDED(22);
+ QUOTA_EXCEEDED(22),
+ SAME_FILE_CONFLICT(23);
private final int value;
@@ -107,6 +108,8 @@ public static UploadResult fromValue(int value) {
return LOCAL_STORAGE_NOT_COPIED;
case 22:
return QUOTA_EXCEEDED;
+ case 23:
+ return SAME_FILE_CONFLICT;
}
return UNKNOWN;
}
diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java
index 5012cd15f5d1..3a5e26fc9732 100755
--- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java
+++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.format.DateUtils;
@@ -259,6 +260,7 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati
itemViewHolder.binding.uploadRemotePath.setVisibility(View.VISIBLE);
itemViewHolder.binding.uploadFileSize.setVisibility(View.VISIBLE);
itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE);
+ itemViewHolder.binding.uploadStatus.setTypeface(null, Typeface.NORMAL);
itemViewHolder.binding.uploadProgressBar.setVisibility(View.GONE);
// Update information depending of upload details
@@ -300,6 +302,15 @@ public void onBindViewHolder(SectionedViewHolder holder, int section, int relati
case UPLOAD_FAILED -> itemViewHolder.binding.uploadDate.setVisibility(View.GONE);
case UPLOAD_SUCCEEDED -> itemViewHolder.binding.uploadStatus.setVisibility(View.GONE);
}
+
+ // show status if same file conflict or local file deleted
+ if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED && item.getLastResult() != UploadResult.UPLOADED){
+ itemViewHolder.binding.uploadStatus.setVisibility(View.VISIBLE);
+ itemViewHolder.binding.uploadStatus.setTypeface(null, Typeface.BOLD);
+ itemViewHolder.binding.uploadDate.setVisibility(View.GONE);
+ itemViewHolder.binding.uploadFileSize.setVisibility(View.GONE);
+ }
+
itemViewHolder.binding.uploadStatus.setText(status);
// bind listeners to perform actions
@@ -612,7 +623,13 @@ private String getStatusText(OCUpload upload) {
break;
case UPLOAD_SUCCEEDED:
- status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded);
+ if (upload.getLastResult() == UploadResult.SAME_FILE_CONFLICT){
+ status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded_same_file);
+ }else if (upload.getLastResult() == UploadResult.FILE_NOT_FOUND) {
+ status = getUploadFailedStatusText(upload.getLastResult());
+ } else {
+ status = parentActivity.getString(R.string.uploads_view_upload_status_succeeded);
+ }
break;
case UPLOAD_FAILED:
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8ba77bc10d47..28509ebd0180 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -153,6 +153,7 @@
Failed/pending restart
Uploaded
Completed
+ Same file found on remote, skipping upload
Cancelled
Connection error
Credentials error