diff --git a/app/src/androidTest/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialogIT.kt b/app/src/androidTest/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialogIT.kt
new file mode 100644
index 000000000000..74f3542703b1
--- /dev/null
+++ b/app/src/androidTest/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialogIT.kt
@@ -0,0 +1,214 @@
+/*
+ *
+ * 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 androidx.test.espresso.Espresso
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.intent.rule.IntentsTestRule
+import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.platform.app.InstrumentationRegistry
+import com.nextcloud.client.account.UserAccountManagerImpl
+import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog.Companion.newInstance
+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.activity.FileActivity
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision
+import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
+import com.owncloud.android.utils.FileStorageUtils
+import junit.framework.TestCase
+import org.junit.After
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class ConflictsResolveConsentDialogIT : AbstractIT() {
+ @get:Rule
+ val activityRule = IntentsTestRule(ConflictsResolveActivity::class.java, true, false)
+
+ private var returnCode = false
+
+ @Test
+ fun replaceWithNewFile() {
+ returnCode = false
+
+ val newUpload = OCUpload(
+ FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
+ "/newFile.txt",
+ user.accountName
+ )
+
+ val existingFile = OCFile("/newFile.txt")
+ existingFile.fileLength = 1024000
+ existingFile.modificationTimestamp = 1582019340
+ existingFile.remoteId = "00000123abc"
+
+ val newFile = OCFile("/newFile.txt")
+ newFile.fileLength = 56000
+ newFile.modificationTimestamp = 1522019340
+ newFile.storagePath = FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt"
+
+ val storageManager = FileDataStorageManager(user, targetContext.contentResolver)
+ storageManager.saveNewFile(existingFile)
+
+ val intent = Intent(targetContext, ConflictsResolveActivity::class.java)
+ intent.putExtra(FileActivity.EXTRA_FILE, newFile)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true)
+
+ val sut = activityRule.launchActivity(intent)
+
+ val dialog = newInstance(
+ existingFile,
+ newFile,
+ UserAccountManagerImpl
+ .fromContext(targetContext)
+ .user
+ )
+ dialog.showDialog(sut)
+
+ sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
+ Assert.assertEquals(decision, Decision.KEEP_LOCAL)
+ returnCode = true
+ }
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
+ Espresso.onView(ViewMatchers.withId(R.id.replace_btn)).perform(ViewActions.click())
+
+ TestCase.assertTrue(returnCode)
+ }
+
+ @Test
+ fun keepBothFiles() {
+ returnCode = false
+
+ val newUpload = OCUpload(
+ FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
+ "/newFile.txt",
+ user.accountName
+ )
+
+ val existingFile = OCFile("/newFile.txt")
+ existingFile.fileLength = 1024000
+ existingFile.modificationTimestamp = 1582019340
+
+ val newFile = OCFile("/newFile.txt")
+ newFile.fileLength = 56000
+ newFile.modificationTimestamp = 1522019340
+ newFile.storagePath = FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt"
+
+ val storageManager = FileDataStorageManager(user, targetContext.contentResolver)
+ storageManager.saveNewFile(existingFile)
+
+ val intent = Intent(targetContext, ConflictsResolveActivity::class.java)
+ intent.putExtra(FileActivity.EXTRA_FILE, newFile)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
+ intent.putExtra(FileActivity.EXTRA_USER, user)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true)
+
+ val sut = activityRule.launchActivity(intent)
+
+ val dialog = newInstance(
+ existingFile,
+ newFile,
+ UserAccountManagerImpl
+ .fromContext(targetContext)
+ .user
+ )
+ dialog.showDialog(sut)
+
+ sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
+ Assert.assertEquals(decision, Decision.KEEP_BOTH)
+ returnCode = true
+ }
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
+ Espresso.onView(ViewMatchers.withId(R.id.keep_both_btn)).perform(ViewActions.click())
+
+ TestCase.assertTrue(returnCode)
+ }
+
+ @Test
+ fun keepExistingFile() {
+ returnCode = false
+
+ val newUpload = OCUpload(
+ FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
+ "/newFile.txt",
+ user.accountName
+ )
+
+ val existingFile = OCFile("/newFile.txt")
+ existingFile.fileLength = 1024000
+ existingFile.modificationTimestamp = 1582019340
+
+ val newFile = OCFile("/newFile.txt")
+ newFile.fileLength = 56000
+ newFile.modificationTimestamp = 1522019340
+ newFile.storagePath = FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt"
+
+ val storageManager = FileDataStorageManager(user, targetContext.contentResolver)
+ storageManager.saveNewFile(existingFile)
+
+ val intent = Intent(targetContext, ConflictsResolveActivity::class.java)
+ intent.putExtra(FileActivity.EXTRA_FILE, newFile)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
+ intent.putExtra(FileActivity.EXTRA_USER, user)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
+ intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true)
+
+ val sut = activityRule.launchActivity(intent)
+
+ val dialog = newInstance(
+ existingFile,
+ newFile,
+ UserAccountManagerImpl
+ .fromContext(targetContext)
+ .user
+ )
+ dialog.showDialog(sut)
+
+ sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
+ Assert.assertEquals(decision, Decision.KEEP_SERVER)
+ returnCode = true
+ }
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
+ Espresso.onView(ViewMatchers.withId(R.id.cancel_keep_existing_btn)).perform(ViewActions.click())
+
+ TestCase.assertTrue(returnCode)
+ }
+
+ @After
+ override fun after() {
+ storageManager.deleteAllFiles()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.kt b/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.kt
new file mode 100644
index 000000000000..f6777547c5b2
--- /dev/null
+++ b/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.kt
@@ -0,0 +1,165 @@
+/*
+ * 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.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.DialogFragment
+import com.nextcloud.client.account.User
+import com.nextcloud.utils.extensions.getParcelableArgument
+import com.nextcloud.utils.extensions.getSerializableArgument
+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 com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
+import java.io.File
+
+/**
+ * Dialog which will be displayed to user upon keep-in-sync file conflict.
+ */
+class ConflictsResolveConsentDialog : DialogFragment() {
+ private lateinit var binding: ConflictResolveConsentDialogBinding
+
+ private var existingFile: OCFile? = null
+ private var newFile: File? = null
+ private var listener: OnConflictDecisionMadeListener? = null
+ private var user: User? = null
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ try {
+ listener = context as OnConflictDecisionMadeListener
+ } catch (e: ClassCastException) {
+ throw ClassCastException("Activity of this dialog must implement OnConflictDecisionMadeListener")
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ val alertDialog = dialog as AlertDialog?
+
+ if (alertDialog == null) {
+ Toast.makeText(context, "Failed to create conflict dialog", Toast.LENGTH_LONG).show()
+ return
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ existingFile = savedInstanceState.getParcelableArgument(KEY_EXISTING_FILE, OCFile::class.java)
+ newFile = savedInstanceState.getSerializableArgument(KEY_NEW_FILE, File::class.java)
+ user = savedInstanceState.getParcelableArgument(KEY_USER, User::class.java)
+ } else if (arguments != null) {
+ existingFile = arguments?.getParcelableArgument(KEY_EXISTING_FILE, OCFile::class.java)
+ newFile = arguments?.getSerializableArgument(KEY_NEW_FILE, File::class.java)
+ user = arguments?.getParcelableArgument(KEY_USER, User::class.java)
+ } else {
+ Toast.makeText(context, "Failed to create conflict dialog", Toast.LENGTH_LONG).show()
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+
+ outState.putParcelable(KEY_EXISTING_FILE, existingFile)
+ outState.putSerializable(KEY_NEW_FILE, newFile)
+ outState.putParcelable(KEY_USER, user)
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ // Inflate the layout for the dialog
+ binding = ConflictResolveConsentDialogBinding.inflate(requireActivity().layoutInflater)
+
+ // TODO: 26-05-2021 change replace and keep both button text for multiple files
+ binding.replaceBtn.setOnClickListener {
+ listener?.conflictDecisionMade(ConflictsResolveDialog.Decision.KEEP_LOCAL)
+ }
+
+ binding.keepBothBtn.setOnClickListener {
+ listener?.conflictDecisionMade(ConflictsResolveDialog.Decision.KEEP_BOTH)
+ }
+
+ binding.moreDetailsBtn.setOnClickListener { }
+
+ binding.cancelKeepExistingBtn.setOnClickListener {
+ listener?.conflictDecisionMade(ConflictsResolveDialog.Decision.KEEP_SERVER)
+ }
+
+ // Build the dialog
+ // TODO: 26-05-2021 Handle multiple dialog message
+ val dialogMessage = String.format(
+ getString(R.string.conflict_dialog_message),
+ existingFile?.decryptedFileName
+ )
+ val builder = AlertDialog.Builder(requireActivity())
+ builder.setView(binding.root) // TODO: 26-05-2021 handle multiple dialog title
+ .setTitle(getString(R.string.conflict_dialog_title))
+ .setMessage(dialogMessage)
+
+
+ return builder.create()
+ }
+
+ fun showDialog(activity: AppCompatActivity) {
+ val prev = activity.supportFragmentManager.findFragmentByTag("dialog")
+ val ft = activity.supportFragmentManager.beginTransaction()
+ if (prev != null) {
+ ft.remove(prev)
+ }
+ ft.addToBackStack(null)
+
+ this.show(ft, "dialog")
+ }
+
+ override fun onCancel(dialog: DialogInterface) {
+ listener?.conflictDecisionMade(ConflictsResolveDialog.Decision.CANCEL)
+ }
+
+ companion object {
+ private const val KEY_NEW_FILE = "file"
+ private const val KEY_EXISTING_FILE = "ocfile"
+ private const val KEY_USER = "user"
+
+ @JvmStatic
+ fun newInstance(existingFile: OCFile?, newFile: OCFile?, user: User?): ConflictsResolveConsentDialog {
+ val dialog = ConflictsResolveConsentDialog()
+
+ val args = Bundle()
+ args.putParcelable(KEY_EXISTING_FILE, existingFile)
+ newFile?.let {
+ args.putSerializable(KEY_NEW_FILE, File(it.storagePath))
+ }
+ args.putParcelable(KEY_USER, user)
+ dialog.arguments = args
+
+ return dialog
+ }
+ }
+}
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 a03a8f0b69f2..27e8c1c304f3 100644
--- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
+++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
@@ -1157,6 +1157,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");
@@ -1300,6 +1320,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 f3a71e7a213c..663d40247a28 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 76b390518690..d7bd2c83a6fa 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
@@ -572,11 +572,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_strings.xml b/app/src/main/res/values-de/nmc_conflict_dialog_strings.xml
new file mode 100644
index 000000000000..a919012dfb20
--- /dev/null
+++ b/app/src/main/res/values-de/nmc_conflict_dialog_strings.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 1ce3f0da4f73..2f79b79712ed 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 89ed00a08bf2..46992e0a67c6 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -75,4 +75,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_strings.xml b/app/src/main/res/values/nmc_conflict_dialog_strings.xml
new file mode 100644
index 000000000000..78c8e470dd17
--- /dev/null
+++ b/app/src/main/res/values/nmc_conflict_dialog_strings.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 13c9a15b63a6..3ce5e2eafc68 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -432,6 +432,19 @@
- ?android:attr/colorBackground
+
+
+
+
+
+
+