diff --git a/app/src/androidTest/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialogIT.java b/app/src/androidTest/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialogIT.java
new file mode 100644
index 000000000000..8804a6b0154a
--- /dev/null
+++ b/app/src/androidTest/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialogIT.java
@@ -0,0 +1,204 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2020 Tobias Kaminsky
+ * Copyright (C) 2020 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.nmc.android.ui.conflict;
+
+import android.content.Intent;
+
+import com.nextcloud.client.account.UserAccountManagerImpl;
+import com.owncloud.android.AbstractIT;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.db.OCUpload;
+import com.owncloud.android.ui.activity.ConflictsResolveActivity;
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
+import com.owncloud.android.utils.FileStorageUtils;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+
+import androidx.test.espresso.intent.rule.IntentsTestRule;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+public class ConflictsResolveConsentDialogIT extends AbstractIT {
+ @Rule public IntentsTestRule activityRule =
+ new IntentsTestRule<>(ConflictsResolveActivity.class, true, false);
+ private boolean returnCode;
+
+ @Test
+ public void replaceWithNewFile() {
+ returnCode = false;
+
+ OCUpload newUpload = new OCUpload(FileStorageUtils.getSavePath(user.getAccountName()) + "/nonEmpty.txt",
+ "/newFile.txt",
+ user.getAccountName());
+
+ OCFile existingFile = new OCFile("/newFile.txt");
+ existingFile.setFileLength(1024000);
+ existingFile.setModificationTimestamp(1582019340);
+ existingFile.setRemoteId("00000123abc");
+
+ OCFile newFile = new OCFile("/newFile.txt");
+ newFile.setFileLength(56000);
+ newFile.setModificationTimestamp(1522019340);
+ newFile.setStoragePath(FileStorageUtils.getSavePath(user.getAccountName()) + "/nonEmpty.txt");
+
+ FileDataStorageManager storageManager = new FileDataStorageManager(user, targetContext.getContentResolver());
+ storageManager.saveNewFile(existingFile);
+
+ Intent intent = new Intent(targetContext, ConflictsResolveActivity.class);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_FILE, newFile);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.getUploadId());
+ intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true);
+
+ ConflictsResolveActivity sut = activityRule.launchActivity(intent);
+
+ ConflictsResolveConsentDialog dialog = ConflictsResolveConsentDialog.newInstance(existingFile,
+ newFile,
+ UserAccountManagerImpl
+ .fromContext(targetContext)
+ .getUser()
+ );
+ dialog.showDialog(sut);
+
+ sut.listener = decision -> {
+ assertEquals(decision, ConflictsResolveDialog.Decision.KEEP_LOCAL);
+ returnCode = true;
+ };
+
+ getInstrumentation().waitForIdleSync();
+
+ onView(withId(R.id.replace_btn)).perform(click());
+
+ assertTrue(returnCode);
+ }
+
+ @Test
+ public void keepBothFiles() {
+ returnCode = false;
+
+ OCUpload newUpload = new OCUpload(FileStorageUtils.getSavePath(user.getAccountName()) + "/nonEmpty.txt",
+ "/newFile.txt",
+ user.getAccountName());
+
+ OCFile existingFile = new OCFile("/newFile.txt");
+ existingFile.setFileLength(1024000);
+ existingFile.setModificationTimestamp(1582019340);
+
+ OCFile newFile = new OCFile("/newFile.txt");
+ newFile.setFileLength(56000);
+ newFile.setModificationTimestamp(1522019340);
+ newFile.setStoragePath(FileStorageUtils.getSavePath(user.getAccountName()) + "/nonEmpty.txt");
+
+ FileDataStorageManager storageManager = new FileDataStorageManager(user, targetContext.getContentResolver());
+ storageManager.saveNewFile(existingFile);
+
+ Intent intent = new Intent(targetContext, ConflictsResolveActivity.class);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_FILE, newFile);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.getUploadId());
+ intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true);
+
+ ConflictsResolveActivity sut = activityRule.launchActivity(intent);
+
+ ConflictsResolveConsentDialog dialog = ConflictsResolveConsentDialog.newInstance(existingFile,
+ newFile,
+ UserAccountManagerImpl
+ .fromContext(targetContext)
+ .getUser()
+ );
+ dialog.showDialog(sut);
+
+ sut.listener = decision -> {
+ assertEquals(decision, ConflictsResolveDialog.Decision.KEEP_BOTH);
+ returnCode = true;
+ };
+
+ getInstrumentation().waitForIdleSync();
+
+ onView(withId(R.id.keep_both_btn)).perform(click());
+
+ assertTrue(returnCode);
+ }
+
+ @Test
+ public void keepExistingFile() {
+ returnCode = false;
+
+ OCUpload newUpload = new OCUpload(FileStorageUtils.getSavePath(user.getAccountName()) + "/nonEmpty.txt",
+ "/newFile.txt",
+ user.getAccountName());
+
+ OCFile existingFile = new OCFile("/newFile.txt");
+ existingFile.setFileLength(1024000);
+ existingFile.setModificationTimestamp(1582019340);
+
+ OCFile newFile = new OCFile("/newFile.txt");
+ newFile.setFileLength(56000);
+ newFile.setModificationTimestamp(1522019340);
+ newFile.setStoragePath(FileStorageUtils.getSavePath(user.getAccountName()) + "/nonEmpty.txt");
+
+ FileDataStorageManager storageManager = new FileDataStorageManager(user, targetContext.getContentResolver());
+ storageManager.saveNewFile(existingFile);
+
+ Intent intent = new Intent(targetContext, ConflictsResolveActivity.class);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_FILE, newFile);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile);
+ intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.getUploadId());
+ intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true);
+
+ ConflictsResolveActivity sut = activityRule.launchActivity(intent);
+
+ ConflictsResolveConsentDialog dialog = ConflictsResolveConsentDialog.newInstance(existingFile,
+ newFile,
+ UserAccountManagerImpl
+ .fromContext(targetContext)
+ .getUser()
+ );
+ dialog.showDialog(sut);
+
+ sut.listener = decision -> {
+ assertEquals(decision, ConflictsResolveDialog.Decision.KEEP_SERVER);
+ returnCode = true;
+ };
+
+ getInstrumentation().waitForIdleSync();
+
+ onView(withId(R.id.cancel_keep_existing_btn)).perform(click());
+
+ assertTrue(returnCode);
+ }
+
+ @After
+ public void after() {
+ getStorageManager().deleteAllFiles();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.java b/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.java
new file mode 100644
index 000000000000..a192e2416191
--- /dev/null
+++ b/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.java
@@ -0,0 +1,197 @@
+/*
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * Copyright (C) 2012 Bartek Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.nmc.android.ui.conflict;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Toast;
+
+import com.nextcloud.client.account.User;
+import com.owncloud.android.R;
+import com.owncloud.android.databinding.ConflictResolveConsentDialogBinding;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
+
+import java.io.File;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentTransaction;
+
+
+/**
+ * Dialog which will be displayed to user upon keep-in-sync file conflict.
+ */
+public class ConflictsResolveConsentDialog extends DialogFragment {
+
+ private ConflictResolveConsentDialogBinding binding;
+
+ private OCFile existingFile;
+ private File newFile;
+ public ConflictsResolveDialog.OnConflictDecisionMadeListener listener;
+ private User user;
+
+ private static final String KEY_NEW_FILE = "file";
+ private static final String KEY_EXISTING_FILE = "ocfile";
+ private static final String KEY_USER = "user";
+
+ public static ConflictsResolveConsentDialog newInstance(OCFile existingFile, OCFile newFile, User user) {
+ ConflictsResolveConsentDialog dialog = new ConflictsResolveConsentDialog();
+
+ Bundle args = new Bundle();
+ args.putParcelable(KEY_EXISTING_FILE, existingFile);
+ args.putSerializable(KEY_NEW_FILE, new File(newFile.getStoragePath()));
+ args.putParcelable(KEY_USER, user);
+ dialog.setArguments(args);
+
+ return dialog;
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ try {
+ listener = (ConflictsResolveDialog.OnConflictDecisionMadeListener) context;
+ } catch (ClassCastException e) {
+ throw new ClassCastException("Activity of this dialog must implement OnConflictDecisionMadeListener");
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ AlertDialog alertDialog = (AlertDialog) getDialog();
+
+ if (alertDialog == null) {
+ Toast.makeText(getContext(), "Failed to create conflict dialog", Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ existingFile = savedInstanceState.getParcelable(KEY_EXISTING_FILE);
+ newFile = (File) savedInstanceState.getSerializable(KEY_NEW_FILE);
+ user = savedInstanceState.getParcelable(KEY_USER);
+ } else if (getArguments() != null) {
+ existingFile = getArguments().getParcelable(KEY_EXISTING_FILE);
+ newFile = (File) getArguments().getSerializable(KEY_NEW_FILE);
+ user = getArguments().getParcelable(KEY_USER);
+ } else {
+ Toast.makeText(getContext(), "Failed to create conflict dialog", Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putParcelable(KEY_EXISTING_FILE, existingFile);
+ outState.putSerializable(KEY_NEW_FILE, newFile);
+ outState.putParcelable(KEY_USER, user);
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Inflate the layout for the dialog
+ binding = ConflictResolveConsentDialogBinding.inflate(requireActivity().getLayoutInflater());
+
+ // TODO: 26-05-2021 change replace and keep both button text for multiple files
+ binding.replaceBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (listener != null) {
+ listener.conflictDecisionMade(ConflictsResolveDialog.Decision.KEEP_LOCAL);
+ }
+ }
+ });
+
+ binding.keepBothBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (listener != null) {
+ listener.conflictDecisionMade(ConflictsResolveDialog.Decision.KEEP_BOTH);
+ }
+ }
+ });
+
+ binding.moreDetailsBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ }
+ });
+
+ binding.cancelKeepExistingBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (listener != null) {
+ listener.conflictDecisionMade(ConflictsResolveDialog.Decision.KEEP_SERVER);
+ }
+ }
+ });
+
+ // Build the dialog
+ // TODO: 26-05-2021 Handle multiple dialog message
+ String dialogMessage = String.format(getString(R.string.conflict_dialog_message),
+ existingFile.getDecryptedFileName());
+ AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
+ builder.setView(binding.getRoot())
+ // TODO: 26-05-2021 handle multiple dialog title
+ .setTitle(getString(R.string.conflict_dialog_title))
+ .setMessage(dialogMessage);
+
+
+ return builder.create();
+ }
+
+ public void showDialog(AppCompatActivity activity) {
+ Fragment prev = activity.getSupportFragmentManager().findFragmentByTag("dialog");
+ FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
+ if (prev != null) {
+ ft.remove(prev);
+ }
+ ft.addToBackStack(null);
+
+ this.show(ft, "dialog");
+ }
+
+ @Override
+ public void onCancel(@NonNull DialogInterface dialog) {
+ if (listener != null) {
+ listener.conflictDecisionMade(ConflictsResolveDialog.Decision.CANCEL);
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
index d0ee77afc191..8362262c17d7 100644
--- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
+++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
@@ -487,13 +487,13 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare
return collisionResult;
}
- mFile.setDecryptedRemotePath(parentFile.getDecryptedRemotePath() + originalFile.getName());
+ mFile.setDecryptedRemotePath(parentFile.getDecryptedRemotePath() + mFile.getFileName());
String expectedPath = FileStorageUtils.getDefaultSavePathFor(user.getAccountName(), mFile);
expectedFile = new File(expectedPath);
result = copyFile(originalFile, expectedPath);
if (!result.isSuccess()) {
- return result;
+ return returnGracefully(temporalFile, token, parentFile, client, result);
}
// Get the last modification date of the file from the file system
@@ -602,7 +602,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare
}
if (result.isSuccess()) {
- mFile.setDecryptedRemotePath(parentFile.getDecryptedRemotePath() + originalFile.getName());
+ mFile.setDecryptedRemotePath(parentFile.getDecryptedRemotePath() + mFile.getFileName());
mFile.setRemotePath(parentFile.getRemotePath() + encryptedFileName);
// update metadata
@@ -682,6 +682,20 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare
getStorageManager().saveConflict(mFile, mFile.getEtagInConflict());
}
+ return returnGracefully(temporalFile, token, parentFile, client, result);
+ }
+
+ private RemoteOperationResult returnGracefully(
+ File temporalFile,
+ String token,
+ OCFile parentFile,
+ OwnCloudClient client,
+ RemoteOperationResult result) {
+ // delete temporal file
+ if (temporalFile != null && temporalFile.exists() && !temporalFile.delete()) {
+ Log_OC.e(TAG, "Could not delete temporal file " + temporalFile.getAbsolutePath());
+ }
+
// unlock must be done always
if (token != null) {
RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parentFile,
@@ -692,12 +706,6 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare
return unlockFolderResult;
}
}
-
- // delete temporal file
- if (temporalFile != null && temporalFile.exists() && !temporalFile.delete()) {
- Log_OC.e(TAG, "Could not delete temporal file " + temporalFile.getAbsolutePath());
- }
-
return result;
}
@@ -966,6 +974,26 @@ private RemoteOperationResult checkNameCollision(OwnCloudClient client,
break;
case OVERWRITE:
Log_OC.d(TAG, "Overwriting file");
+ if (encrypted) {
+ OCFile file = getStorageManager().getFileByDecryptedRemotePath(mRemotePath);
+
+ if (file != null) {
+ RemoteOperationResult removeResult = new RemoveFileOperation(file,
+ false,
+ user,
+ true,
+ mContext,
+ getStorageManager())
+ .execute(client);
+
+ if (!removeResult.isSuccess()) {
+ throw new IllegalArgumentException("Failed to remove old encrypted file!");
+ }
+
+ } else {
+ throw new IllegalArgumentException("File to remove is null!");
+ }
+ }
break;
case ASK_USER:
Log_OC.d(TAG, "Name collision; asking the user what to do");
@@ -1110,6 +1138,7 @@ private void createNewOCFile(String newRemotePath) {
newFile.setLastSyncDateForData(mFile.getLastSyncDateForData());
newFile.setStoragePath(mFile.getStoragePath());
newFile.setParentId(mFile.getParentId());
+ newFile.setEncrypted(mFile.isEncrypted());
mOldFile = mFile;
mFile = newFile;
}
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
index 8f41b3aea679..5efd04697c82 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
@@ -24,6 +24,7 @@
import com.nextcloud.client.account.User;
import com.nextcloud.java.util.Optional;
+import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.UploadsStorageManager;
@@ -35,7 +36,6 @@
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.ui.dialog.ConflictsResolveDialog;
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision;
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener;
import com.owncloud.android.utils.FileStorageUtils;
@@ -60,7 +60,10 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
*/
public static final String EXTRA_LOCAL_BEHAVIOUR = "LOCAL_BEHAVIOUR";
public static final String EXTRA_EXISTING_FILE = "EXISTING_FILE";
-
+ /**
+ * variable to tell activity that it has been launched from test class
+ */
+ public static final String EXTRA_LAUNCHED_FROM_TEST = "LAUNCHED_FROM_TEST";
private static final String TAG = ConflictsResolveActivity.class.getSimpleName();
@Inject UploadsStorageManager uploadsStorageManager;
@@ -69,7 +72,7 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
private OCFile existingFile;
private OCFile newFile;
private int localBehaviour = FileUploader.LOCAL_BEHAVIOUR_FORGET;
- protected OnConflictDecisionMadeListener listener;
+ public OnConflictDecisionMadeListener listener;
public static Intent createIntent(OCFile file,
User user,
@@ -81,6 +84,7 @@ public static Intent createIntent(OCFile file,
intent.setFlags(intent.getFlags() | flag);
}
intent.putExtra(EXTRA_FILE, file);
+ intent.putExtra(EXTRA_EXISTING_FILE, file);
intent.putExtra(EXTRA_USER, user);
intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId);
@@ -141,6 +145,10 @@ protected void onCreate(Bundle savedInstanceState) {
uploadsStorageManager.removeUpload(upload);
break;
case KEEP_SERVER: // Download
+ if (newFile.isEncrypted()) {
+ // NMC-2361 fix
+ break;
+ }
if (!shouldDeleteLocal()) {
// Overwrite local file
Intent intent = new Intent(getBaseContext(), FileDownloader.class);
@@ -231,10 +239,12 @@ private void startDialog() {
fragmentTransaction.remove(prev);
}
- if (existingFile != null && getStorageManager().fileExists(newFile.getRemotePath())) {
- ConflictsResolveDialog dialog = ConflictsResolveDialog.newInstance(existingFile,
- newFile,
- userOptional.get());
+ // TODO renaming does not work?
+ // TODO check all three conflict options
+ if (existingFile != null && getStorageManager().getFileByDecryptedRemotePath(newFile.getRemotePath()) != null) {
+ ConflictsResolveConsentDialog dialog = ConflictsResolveConsentDialog.newInstance(existingFile,
+ newFile,
+ userOptional.get());
dialog.show(fragmentTransaction, "conflictDialog");
} else {
// Account was changed to a different one - just finish
@@ -244,8 +254,13 @@ private void startDialog() {
}
private void showErrorAndFinish() {
- runOnUiThread(() -> Toast.makeText(this, R.string.conflict_dialog_error, Toast.LENGTH_LONG).show());
- finish();
+ //if activity is launched from test case then don't finish the activity as it is required to show the dialog
+ //but during normal app run activity should finish during error so we have to pass it false or don't pass
+ // anything
+ if (!getIntent().getBooleanExtra(EXTRA_LAUNCHED_FROM_TEST, false)) {
+ runOnUiThread(() -> Toast.makeText(this, R.string.conflict_dialog_error, Toast.LENGTH_LONG).show());
+ finish();
+ }
}
/**
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 0298ef49bc0e..47dea84f3ba7 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
@@ -495,11 +495,10 @@ private boolean checkAndOpenConflictResolutionDialog(User user,
OCUpload item,
String status) {
String remotePath = item.getRemotePath();
- OCFile ocFile = storageManager.getFileByPath(remotePath);
+ OCFile ocFile = storageManager.getFileByDecryptedRemotePath(remotePath);
- if (ocFile == null) {
- // Remote file doesn't exist, try to refresh folder
- OCFile folder = storageManager.getFileByPath(new File(remotePath).getParent() + "/");
+ if (ocFile == null) { // Remote file doesn't exist, try to refresh folder
+ OCFile folder = storageManager.getFileByDecryptedRemotePath(new File(remotePath).getParent() + "/");
if (folder != null && folder.isFolder()) {
this.refreshFolder(itemViewHolder, user, folder, (caller, result) -> {
itemViewHolder.binding.uploadStatus.setText(status);
diff --git a/app/src/main/res/color/dialog_positive_btn_color.xml b/app/src/main/res/color/dialog_positive_btn_color.xml
new file mode 100644
index 000000000000..5913e0da1a1d
--- /dev/null
+++ b/app/src/main/res/color/dialog_positive_btn_color.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/conflict_resolve_consent_dialog.xml b/app/src/main/res/layout-land/conflict_resolve_consent_dialog.xml
new file mode 100644
index 000000000000..325749554862
--- /dev/null
+++ b/app/src/main/res/layout-land/conflict_resolve_consent_dialog.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/conflict_resolve_consent_dialog.xml b/app/src/main/res/layout/conflict_resolve_consent_dialog.xml
new file mode 100644
index 000000000000..f0ac8de88111
--- /dev/null
+++ b/app/src/main/res/layout/conflict_resolve_consent_dialog.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index fa7fc73fd5f9..b8b89e13c8a2 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1007,4 +1007,16 @@
- %d ausgewählt
- %d ausgewählt
+
+ Ersetzen
+ Alle ersetzen
+ Beide behalten
+ Beide Versionen für alle behalten
+ Mehr Details
+ Abbrechen und bestehende Datei behalten
+ Dateikonflikt
+ %d Dateikonflikte
+ %1$s ist im Zielordner bereits vorhanden. Möchten Sie die bestehende Datei behalten oder überschreiben?
+ Die Dateien sind im Zielordner bereits vorhanden. Möchten Sie die bestehenden Dateien behalten oder überschreiben?
+
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index 08bf64d552ad..88a29668c4cd 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -48,4 +48,70 @@
#1E1E1E
@android:color/white
+
+
+ #FFFFFF
+ @color/grey_30
+ @color/grey_30
+ #CCCCCC
+ @color/grey_70
+ @color/grey_80
+ #2D2D2D
+ @color/grey_70
+ @color/grey_70
+
+
+ @color/grey_80
+ @color/grey_0
+
+
+ @color/grey_80
+ @color/grey_0
+
+
+ @color/grey_60
+ @color/grey_0
+ @color/grey_0
+ @color/grey_30
+ #FFFFFF
+ @color/grey_30
+ @color/grey_80
+ #FFFFFF
+
+
+ @color/grey_80
+ @color/grey_30
+ @color/grey_0
+
+
+ @color/grey_80
+ @color/grey_0
+ @color/grey_80
+
+
+ @color/grey_70
+ @color/grey_60
+ @color/grey_70
+ @color/grey_60
+
+
+ @color/grey_70
+ @color/grey_70
+
+
+ #FFFFFF
+ @color/grey_30
+ @color/grey_0
+ @color/grey_0
+ @color/grey_0
+ @color/grey_0
+ @color/grey_60
+ @color/grey_0
+ #FFFFFF
+
+
+ #121212
+ @color/grey_0
+ @color/grey_80
+ @color/grey_80
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index d72d9d458f83..0ae14280757c 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -80,4 +80,95 @@
@android:color/white
#666666
#A5A5A5
+
+
+ #191919
+ @color/primary
+ #191919
+ #191919
+ @color/grey_30
+ @android:color/white
+ #FFFFFF
+ @color/grey_0
+ #CCCCCC
+ #77c4ff
+ #B3FFFFFF
+ @color/grey_10
+
+
+ #101010
+ #F2F2F2
+ #E5E5E5
+ #B2B2B2
+ #666666
+ #4C4C4C
+ #333333
+
+
+ @color/design_snackbar_background_color
+ @color/white
+
+
+ #FFFFFF
+ #191919
+
+
+ @color/grey_0
+ #191919
+ @color/primary
+ #191919
+ @color/primary
+ @color/grey_30
+ @color/white
+ #191919
+
+
+ #FFFFFF
+ #191919
+ #191919
+
+
+ #FFFFFF
+ #191919
+ #FFFFFF
+
+
+ @color/primary
+ #F399C7
+ @color/grey_0
+ @color/grey_0
+ #FFFFFF
+ @color/grey_30
+ @color/grey_0
+ @color/grey_0
+
+
+ @color/primary
+ @color/grey_30
+ @color/grey_30
+ #CCCCCC
+
+
+ #191919
+ @color/grey_30
+ #191919
+ #191919
+ #191919
+ #191919
+ @color/grey_30
+ #191919
+ #000000
+ #191919
+ #F6E5EB
+ #C16F81
+ #0D39DF
+ #0099ff
+
+
+ @color/grey_0
+ #191919
+ @color/grey_0
+ @color/grey_30
+ #77b6bb
+ #5077b6bb
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 000000000000..cc9e25255a10
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,31 @@
+
+
+ 4dp
+ 16dp
+ 24dp
+ 6dp
+ 18sp
+ 15sp
+ 15dp
+ 56dp
+ 86dp
+ 80dp
+ 11sp
+ 30dp
+ 55dp
+ 258dp
+ 17sp
+ 20dp
+ 160dp
+ 50dp
+ 150dp
+ 55dp
+ 48dp
+ 48dp
+ 24dp
+ 26dp
+ 20sp
+ 145dp
+ 1dp
+ 13sp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d552f8c69bc1..af48688a1fd8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1080,6 +1080,19 @@
Multiple images
Cannot create local file
Invalid filename for local file
+
+ Replace
+ Replace all
+ Keep both
+ Keep both for all
+ More details
+ Cancel and keep existing
+ File conflict
+ %d File conflicts
+ %1$s already exists in this location. Do you want to replace it with the
+ file you are moving?
+ The files already exist in this location. Do you want to replace them with the files you are moving?
+
Groupfolders
+%1$d
Unable to open password-protected PDF. Please use an external PDF viewer.
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 400b7bb7d326..062055de17e9 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -468,6 +468,19 @@
- ?android:attr/colorBackground
+
+
+
+
+
+
+