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/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
index c149e25c0869..6a8542dd3dd9 100644
--- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
+++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
@@ -29,6 +29,7 @@
import com.nextcloud.ui.SetStatusDialogFragment;
import com.nextcloud.ui.composeActivity.ComposeActivity;
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
+import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog;
import com.nmc.android.ui.LauncherActivity;
import com.owncloud.android.MainApp;
import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -366,6 +367,9 @@ abstract class ComponentsModule {
@ContributesAndroidInjector
abstract ConflictsResolveDialog conflictsResolveDialog();
+ @ContributesAndroidInjector
+ abstract ConflictsResolveConsentDialog conflictsResolveConsentDialog();
+
@ContributesAndroidInjector
abstract CreateFolderDialogFragment createFolderDialogFragment();
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..6e5123cf82c8
--- /dev/null
+++ b/app/src/main/java/com/nmc/android/ui/conflict/ConflictsResolveConsentDialog.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.client.di.Injectable
+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.FileDataStorageManager
+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
+import javax.inject.Inject
+
+/**
+ * Dialog which will be displayed to user upon keep-in-sync file conflict.
+ */
+class ConflictsResolveConsentDialog : DialogFragment(), Injectable {
+ 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
+
+ @Inject
+ lateinit var fileDataStorageManager: FileDataStorageManager
+
+ 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),
+ fileDataStorageManager.getFileByEncryptedRemotePath(existingFile?.remotePath).fileName
+ )
+ 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/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt
index 18f3686c9da1..82fdc0e9d5f0 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
@@ -21,6 +21,7 @@ import com.nextcloud.client.jobs.upload.UploadNotificationManager
import com.nextcloud.model.HTTPStatusCodes
import com.nextcloud.utils.extensions.getParcelableArgument
import com.nextcloud.utils.extensions.logFileSize
+import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog
import com.owncloud.android.R
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
@@ -30,7 +31,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
@@ -115,7 +115,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(
@@ -206,7 +208,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()
@@ -221,9 +223,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()
+ }
}
}
@@ -253,6 +261,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
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 bb8cfbf10752..0608de35a753 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -431,6 +431,19 @@
- ?android:attr/colorBackground
+
+
+
+
+
+
+