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 18de79ad31df..9d12c88650f4 100644
--- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
+++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
@@ -534,13 +534,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
@@ -646,7 +646,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);
@@ -767,11 +767,30 @@ 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,
+ client,
+ token);
+
+ if (!unlockFolderResult.isSuccess()) {
+ return unlockFolderResult;
+ }
+ }
return result;
}
@@ -1045,6 +1064,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");
@@ -1188,6 +1227,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.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt
index a83e5c6dd000..85741b1e2fd3 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt
+++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt
@@ -20,6 +20,7 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.jobs.upload.UploadNotificationManager
import com.nextcloud.model.HTTPStatusCodes
import com.nextcloud.utils.extensions.getParcelableArgument
+import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog
import com.owncloud.android.R
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
@@ -29,7 +30,6 @@ import com.owncloud.android.files.services.NameCollisionPolicy
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
@@ -114,7 +114,9 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
}
Decision.KEEP_SERVER -> {
- if (!shouldDeleteLocal()) {
+ if (newFile?.isEncrypted == true) {
+ // NMC-2361 fix
+ } else if (!shouldDeleteLocal()) {
// Overwrite local file
file?.let {
FileDownloadHelper.instance().downloadFile(
@@ -204,7 +206,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
fragmentTransaction.remove(prev)
}
if (existingFile != null && storageManager.fileExists(remotePath)) {
- val dialog = ConflictsResolveDialog.newInstance(
+ val dialog = ConflictsResolveConsentDialog.newInstance(
existingFile,
newFile,
userOptional.get()
@@ -219,9 +221,15 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
private fun showErrorAndFinish(code: Int? = null) {
val message = parseErrorMessage(code)
- runOnUiThread {
- Toast.makeText(this, message, Toast.LENGTH_LONG).show()
- finish()
+ // NMC Customization
+ // 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 (!intent.getBooleanExtra(EXTRA_LAUNCHED_FROM_TEST, false)) {
+ runOnUiThread {
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show()
+ finish()
+ }
}
}
@@ -251,6 +259,10 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
*/
const val EXTRA_LOCAL_BEHAVIOUR = "LOCAL_BEHAVIOUR"
const val EXTRA_EXISTING_FILE = "EXISTING_FILE"
+ /**
+ * variable to tell activity that it has been launched from test class
+ */
+ const val EXTRA_LAUNCHED_FROM_TEST = "LAUNCHED_FROM_TEST"
private val TAG = ConflictsResolveActivity::class.java.simpleName
@JvmStatic
@@ -266,6 +278,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
intent.flags = intent.flags or flag
}
intent.putExtra(EXTRA_FILE, file)
+ intent.putExtra(EXTRA_EXISTING_FILE, file)
intent.putExtra(EXTRA_USER, user)
intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId)
return intent
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 2ee4e4e20576..46f6d719ad12 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
@@ -567,11 +567,11 @@ private boolean checkAndOpenConflictResolutionDialog(User user,
OCUpload item,
String status) {
String remotePath = item.getRemotePath();
- OCFile localFile = storageManager.getFileByEncryptedRemotePath(remotePath);
+ OCFile localFile = storageManager.getFileByDecryptedRemotePath(remotePath);
if (localFile == null) {
// Remote file doesn't exist, try to refresh folder
- OCFile folder = storageManager.getFileByEncryptedRemotePath(new File(remotePath).getParent() + "/");
+ OCFile folder = storageManager.getFileByDecryptedRemotePath(new File(remotePath).getParent() + "/");
if (folder != null && folder.isFolder()) {
refreshFolderAndUpdateUI(itemViewHolder, user, folder, remotePath, item, 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/nmc_conflict_dialog.xml b/app/src/main/res/values-de/nmc_conflict_dialog.xml
new file mode 100644
index 000000000000..a919012dfb20
--- /dev/null
+++ b/app/src/main/res/values-de/nmc_conflict_dialog.xml
@@ -0,0 +1,19 @@
+
+
+
+ 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?
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index e9c749b86943..76e4e05ca495 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -36,4 +36,68 @@
#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_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 9a721eb3e385..248aa18d524c 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -76,4 +76,93 @@
@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
+ #FFFFFF
+ @color/grey_30
+ @color/grey_10
+ @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/nmc_conflict_dialog.xml b/app/src/main/res/values/nmc_conflict_dialog.xml
new file mode 100644
index 000000000000..78c8e470dd17
--- /dev/null
+++ b/app/src/main/res/values/nmc_conflict_dialog.xml
@@ -0,0 +1,20 @@
+
+
+
+ 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?
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 1a8b501ee4b7..402a9f77a167 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -432,6 +432,19 @@
- ?android:attr/colorBackground
+
+
+
+
+
+
+