diff --git a/app/src/androidTest/java/com/nmc/android/ui/SettingsPreferenceIT.kt b/app/src/androidTest/java/com/nmc/android/ui/SettingsPreferenceIT.kt
new file mode 100644
index 000000000000..dde7af362273
--- /dev/null
+++ b/app/src/androidTest/java/com/nmc/android/ui/SettingsPreferenceIT.kt
@@ -0,0 +1,212 @@
+package com.nmc.android.ui
+
+import android.preference.ListPreference
+import android.preference.Preference
+import androidx.test.espresso.Espresso.onData
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.PreferenceMatchers
+import androidx.test.espresso.matcher.PreferenceMatchers.withKey
+import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import com.owncloud.android.AbstractIT
+import com.owncloud.android.R
+import com.owncloud.android.ui.AppVersionPreference
+import com.owncloud.android.ui.PreferenceCustomCategory
+import com.owncloud.android.ui.ThemeableSwitchPreference
+import com.owncloud.android.ui.activity.SettingsActivity
+import org.hamcrest.Matchers.allOf
+import org.hamcrest.Matchers.instanceOf
+import org.hamcrest.Matchers.`is`
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+class SettingsPreferenceIT : AbstractIT() {
+
+ @get:Rule
+ val activityRule = ActivityScenarioRule(SettingsActivity::class.java)
+
+ @Test
+ fun verifyPreferenceSectionCustomClass() {
+ activityRule.scenario.onActivity {
+ val preferenceAccountInfo = it.findPreference("account_info")
+ val preferenceGeneral = it.findPreference("general")
+ val preferenceDetails = it.findPreference("details")
+ val preferenceMore = it.findPreference("more")
+ val preferenceDataProtection = it.findPreference("data_protection")
+ val preferenceInfo = it.findPreference("info")
+
+ val preferenceCategoryList = listOf(
+ preferenceAccountInfo,
+ preferenceGeneral,
+ preferenceDetails,
+ preferenceMore,
+ preferenceDataProtection,
+ preferenceInfo
+ )
+
+ for (preference in preferenceCategoryList) {
+ assertEquals(PreferenceCustomCategory::class.java, preference.javaClass)
+ }
+ }
+ }
+
+ @Test
+ fun verifySwitchPreferenceCustomClass() {
+ activityRule.scenario.onActivity {
+ val preferenceShowHiddenFiles = it.findPreference("show_hidden_files")
+ assertEquals(ThemeableSwitchPreference::class.java, preferenceShowHiddenFiles.javaClass)
+ }
+ }
+
+ @Test
+ fun verifyAppVersionPreferenceCustomClass() {
+ activityRule.scenario.onActivity {
+ val preferenceAboutApp = it.findPreference("about_app")
+ assertEquals(AppVersionPreference::class.java, preferenceAboutApp.javaClass)
+ }
+ }
+
+ @Test
+ fun verifyPreferenceChildCustomLayout() {
+ activityRule.scenario.onActivity {
+ val userName = it.findPreference("user_name")
+ val storagePath = it.findPreference("storage_path")
+ val lock = it.findPreference("lock")
+ val showHiddenFiles = it.findPreference("show_hidden_files")
+ val syncedFolders = it.findPreference("syncedFolders")
+ val backup = it.findPreference("backup")
+ val mnemonic = it.findPreference("mnemonic")
+ val privacySettings = it.findPreference("privacy_settings")
+ val privacyPolicy = it.findPreference("privacy_policy")
+ val sourceCode = it.findPreference("sourcecode")
+ val help = it.findPreference("help")
+ val imprint = it.findPreference("imprint")
+
+ val preferenceList = listOf(
+ userName,
+ storagePath,
+ lock,
+ showHiddenFiles,
+ syncedFolders,
+ backup,
+ mnemonic,
+ privacySettings,
+ privacyPolicy,
+ sourceCode,
+ help,
+ imprint
+ )
+
+ for (preference in preferenceList) {
+ assertEquals(R.layout.custom_preference_layout, preference.layoutResource)
+ }
+
+ val aboutApp = it.findPreference("about_app")
+ assertEquals(R.layout.custom_app_preference_layout, aboutApp.layoutResource)
+
+ }
+ }
+
+ @Test
+ fun verifyPreferencesTitleText() {
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("account_info"),
+ PreferenceMatchers.withTitleText("Account Information")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("user_name"),
+ PreferenceMatchers.withTitleText("test")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("general"),
+ PreferenceMatchers.withTitleText("General")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(ListPreference::class.java)), withKey("storage_path"),
+ PreferenceMatchers.withTitleText("Data storage folder")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("details"),
+ PreferenceMatchers.withTitleText("Details")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(ListPreference::class.java)), withKey("lock"),
+ PreferenceMatchers.withTitleText("App passcode")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(ThemeableSwitchPreference::class.java)), withKey("show_hidden_files"),
+ PreferenceMatchers.withTitleText("Show hidden files")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("more"),
+ PreferenceMatchers.withTitleText("More")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("syncedFolders"),
+ PreferenceMatchers.withTitleText("Auto upload")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("backup"),
+ PreferenceMatchers.withTitleText("Back up contacts")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("mnemonic"),
+ PreferenceMatchers.withTitleText("E2E mnemonic")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("logger"),
+ PreferenceMatchers.withTitleText("Logs")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("data_protection"),
+ PreferenceMatchers.withTitleText("Data Privacy")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("privacy_settings"),
+ PreferenceMatchers.withTitleText("Privacy Settings")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("privacy_policy"),
+ PreferenceMatchers.withTitleText("Privacy Policy")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("sourcecode"),
+ PreferenceMatchers.withTitleText("Used OpenSource Software")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("service"),
+ PreferenceMatchers.withTitleText("Service")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("help"),
+ PreferenceMatchers.withTitleText("Help")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("imprint"),
+ PreferenceMatchers.withTitleText("Imprint")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(PreferenceCustomCategory::class.java)), withKey("info"),
+ PreferenceMatchers.withTitleText("Info")))
+ .check(matches(isCompletelyDisplayed()))
+ }
+
+ @Test
+ fun verifyPreferencesSummaryText() {
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("lock"),
+ PreferenceMatchers.withSummaryText("None")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("syncedFolders"),
+ PreferenceMatchers.withSummaryText("Manage folders for auto upload")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("backup"),
+ PreferenceMatchers.withSummaryText("Daily backup of your calendar & contacts")))
+ .check(matches(isCompletelyDisplayed()))
+
+ onData(allOf(`is`(instanceOf(Preference::class.java)), withKey("mnemonic"),
+ PreferenceMatchers.withSummaryText("To show mnemonic please enable device credentials.")))
+ .check(matches(isCompletelyDisplayed()))
+ }
+}
\ No newline at end of file
diff --git a/app/src/debug/res/values/log_config.xml b/app/src/debug/res/values/log_config.xml
new file mode 100644
index 000000000000..db470a2d25c4
--- /dev/null
+++ b/app/src/debug/res/values/log_config.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ true
+
\ No newline at end of file
diff --git a/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt b/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt
index 214750cbcffc..3a537887148c 100644
--- a/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt
+++ b/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt
@@ -85,6 +85,7 @@ class LogsActivity : ToolbarActivity() {
android.R.id.home -> finish()
R.id.action_delete_logs -> vm.deleteAll()
R.id.action_send_logs -> vm.send()
+ R.id.action_save_logs -> vm.save()
R.id.action_refresh_logs -> vm.load()
else -> retval = super.onOptionsItemSelected(item)
}
diff --git a/app/src/main/java/com/nextcloud/client/logger/ui/LogsSaveHandler.kt b/app/src/main/java/com/nextcloud/client/logger/ui/LogsSaveHandler.kt
new file mode 100644
index 000000000000..1daef16c5d6c
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/client/logger/ui/LogsSaveHandler.kt
@@ -0,0 +1,139 @@
+/*
+ * Nextcloud - Android Client
+ *
+ * SPDX-FileCopyrightText: 2025 TSI-mc
+ * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
+ */
+package com.nextcloud.client.logger.ui
+
+import android.app.DownloadManager
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import androidx.core.app.NotificationCompat
+import com.nextcloud.client.core.AsyncRunner
+import com.nextcloud.client.core.Cancellable
+import com.nextcloud.client.core.Clock
+import com.nextcloud.client.logger.LogEntry
+import com.owncloud.android.R
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.ui.notifications.NotificationUtils
+import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.FileExportUtils
+import java.io.File
+import java.io.FileWriter
+import java.security.SecureRandom
+import java.util.TimeZone
+
+// NMC-4888 task
+class LogsSaveHandler(private val context: Context, private val clock: Clock, private val runner: AsyncRunner) {
+
+ private companion object {
+ private const val LOGS_MIME_TYPE = "text/plain"
+ private const val LOGS_DATE_FORMAT = "yyyyMMdd_HHmmssZ"
+ private val notificationId = SecureRandom().nextInt()
+ }
+
+ private class Task(
+ private val logs: List,
+ private val file: File,
+ private val tz: TimeZone
+ ) : Function0 {
+
+ override fun invoke(): File {
+ file.parentFile?.mkdirs()
+ val fo = FileWriter(file, false)
+ logs.forEach {
+ fo.write(it.toString(tz))
+ fo.write("\n")
+ }
+ fo.close()
+ return file
+ }
+ }
+
+ private var task: Cancellable? = null
+
+ fun save(logs: List) {
+ if (task == null) {
+ val timestamp = DisplayUtils.getDateByPattern(System.currentTimeMillis(), context, LOGS_DATE_FORMAT)
+ val logFileName = "logs_${context.resources.getString(R.string.app_name)}_${timestamp}.txt"
+ val outFile = File(context.cacheDir, logFileName)
+ task = runner.postQuickTask(Task(logs, outFile, clock.tz), onResult = {
+ task = null
+ export(it)
+ })
+ }
+ }
+
+ fun stop() {
+ if (task != null) {
+ task?.cancel()
+ task = null
+ }
+ }
+
+ private fun export(file: File) {
+ task = null
+ try {
+ FileExportUtils().exportFile(
+ file.name,
+ LOGS_MIME_TYPE,
+ context.contentResolver,
+ null,
+ file
+ )
+ showSuccessNotification()
+ } catch (e: IllegalStateException) {
+ Log_OC.e("LogsSaveHandler", "Error saving logs to file", e)
+ showErrorNotification()
+ }
+ }
+
+ private fun showErrorNotification() {
+ showNotification(false, context.resources.getString(R.string.logs_export_failed))
+ }
+
+ private fun showSuccessNotification() {
+ showNotification(true, context.resources.getString(R.string.logs_export_success))
+ }
+
+ private fun showNotification(isSuccess: Boolean, message: String) {
+ val notificationBuilder = NotificationCompat.Builder(
+ context,
+ NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD
+ )
+ .setSmallIcon(R.drawable.notification_icon)
+ .setContentTitle(message)
+ .setAutoCancel(true)
+
+ // NMC Customization
+ notificationBuilder.color = context.resources.getColor(R.color.primary, null)
+
+ if (isSuccess) {
+ val actionIntent = Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).apply {
+ flags = FLAG_ACTIVITY_NEW_TASK
+ }
+ val actionPendingIntent = PendingIntent.getActivity(
+ context,
+ notificationId,
+ actionIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT or
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ notificationBuilder.addAction(
+ NotificationCompat.Action(
+ null,
+ context.getString(R.string.locate_folder),
+ actionPendingIntent
+ )
+ )
+ }
+
+ val notificationManager = context
+ .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.notify(notificationId, notificationBuilder.build())
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt b/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt
index c773758aa4b7..635fc89fa6d5 100644
--- a/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt
+++ b/app/src/main/java/com/nextcloud/client/logger/ui/LogsViewModel.kt
@@ -30,6 +30,7 @@ class LogsViewModel @Inject constructor(
private val asyncFilter = AsyncFilter(asyncRunner)
private val sender = LogsEmailSender(context, clock, asyncRunner)
+ private val logsSaver = LogsSaveHandler(context, clock, asyncRunner)
private var allEntries = emptyList()
private var logsSize = -1L
private var filterDurationMs = 0L
@@ -46,6 +47,12 @@ class LogsViewModel @Inject constructor(
}
}
+ fun save() {
+ entries.value?.let {
+ logsSaver.save(it)
+ }
+ }
+
fun load() {
if (isLoading.value != true) {
logsRepository.load(this::onLoaded)
diff --git a/app/src/main/java/com/nmc/android/ui/PrivacySettingsInterface.kt b/app/src/main/java/com/nmc/android/ui/PrivacySettingsInterface.kt
new file mode 100644
index 000000000000..860ffada08ab
--- /dev/null
+++ b/app/src/main/java/com/nmc/android/ui/PrivacySettingsInterface.kt
@@ -0,0 +1,13 @@
+package com.nmc.android.ui
+
+import android.content.Context
+
+/**
+ * interface to open privacy settings activity from nmc/1921-settings branch
+ * for implementation look nmc/1878-privacy branch
+ * this class will have the declaration for it since it has the PrivacySettingsActivity.java in place
+ * since we don't have privacy settings functionality in this branch so to handle the redirection we have used interface
+ */
+interface PrivacySettingsInterface {
+ fun openPrivacySettingsActivity(context: Context)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/owncloud/android/ui/AppVersionPreference.kt b/app/src/main/java/com/owncloud/android/ui/AppVersionPreference.kt
new file mode 100644
index 000000000000..1bcf709dce25
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/AppVersionPreference.kt
@@ -0,0 +1,51 @@
+package com.owncloud.android.ui
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.preference.Preference
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import com.owncloud.android.R
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.utils.StringUtils
+
+class AppVersionPreference : Preference {
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
+
+ override fun getView(convertView: View?, parent: ViewGroup?): View {
+ val v = super.getView(convertView, parent)
+ updatePreferenceView(v.findViewById(R.id.title), v.findViewById(R.id.summary))
+ return v
+ }
+
+ private fun updatePreferenceView(title: TextView, summary: TextView) {
+ val appVersion = appVersion
+ val titleColor: Int = context.resources.getColor(R.color.fontAppbar, null)
+ title.text = StringUtils.getColorSpan(
+ context.getString(R.string.app_name),
+ titleColor
+ )
+ summary.text = String.format(context.getString(R.string.about_version), appVersion)
+ }
+
+ private val appVersion: String
+ get() {
+ var temp: String
+ try {
+ val pkg = context.packageManager.getPackageInfo(context.packageName, 0)
+ temp = pkg.versionName ?: ""
+ } catch (e: PackageManager.NameNotFoundException) {
+ temp = ""
+ Log_OC.e(TAG, "Error while showing about dialog", e)
+ }
+ return temp
+ }
+
+ companion object {
+ private val TAG = AppVersionPreference::class.java.simpleName
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/owncloud/android/ui/PreferenceCustomCategory.kt b/app/src/main/java/com/owncloud/android/ui/PreferenceCustomCategory.kt
new file mode 100644
index 000000000000..ec6b920585e1
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/PreferenceCustomCategory.kt
@@ -0,0 +1,30 @@
+package com.owncloud.android.ui
+
+import android.content.Context
+import android.graphics.Typeface
+import android.preference.PreferenceCategory
+import android.util.AttributeSet
+import android.util.TypedValue
+import android.view.View
+import android.widget.TextView
+import com.owncloud.android.R
+
+class PreferenceCustomCategory : PreferenceCategory {
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context?, attrs: AttributeSet?,
+ defStyle: Int
+ ) : super(context, attrs, defStyle)
+
+ override fun onBindView(view: View) {
+ super.onBindView(view)
+ val titleView = view.findViewById(android.R.id.title)
+ titleView.setTextColor(context.resources.getColor(R.color.text_color))
+ titleView.setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ context.resources.getDimensionPixelSize(R.dimen.txt_size_16sp).toFloat()
+ )
+ titleView.setTypeface(null, Typeface.BOLD)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java b/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java
index 7fad98aa344f..1d98859a2650 100644
--- a/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java
+++ b/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java
@@ -8,6 +8,7 @@
package com.owncloud.android.ui;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.preference.SwitchPreference;
import android.util.AttributeSet;
import android.view.View;
@@ -15,10 +16,13 @@
import android.widget.Switch;
import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
import com.owncloud.android.utils.theme.ViewThemeUtils;
import javax.inject.Inject;
+import androidx.core.content.res.ResourcesCompat;
+
/**
* Themeable switch preference TODO Migrate to androidx
*/
@@ -51,11 +55,65 @@ protected void onBindView(View view) {
}
private void findSwitch(ViewGroup viewGroup) {
+ ColorStateList thumbColorStateList;
+ ColorStateList trackColorStateList;
+
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
- if (child instanceof Switch switchView) {
- viewThemeUtils.platform.colorSwitch(switchView);
+ if (child instanceof Switch) {
+ Switch switchView = (Switch) child;
+
+ int[][] states = new int[][]{
+ new int[]{android.R.attr.state_enabled, android.R.attr.state_checked}, // enabled and checked
+ new int[]{android.R.attr.state_enabled, -android.R.attr.state_checked}, // enabled and unchecked
+ new int[]{-android.R.attr.state_enabled} // disabled
+ };
+
+ int thumbColorCheckedEnabled = ResourcesCompat.getColor(
+ switchView.getContext().getResources(),
+ R.color.switch_thumb_checked_enabled,
+ switchView.getContext().getTheme());
+ int thumbColorUncheckedEnabled = ResourcesCompat.getColor(
+ switchView.getContext().getResources(),
+ R.color.switch_thumb_unchecked_enabled,
+ switchView.getContext().getTheme());
+ int thumbColorDisabled =
+ ResourcesCompat.getColor(
+ switchView.getContext().getResources(),
+ R.color.switch_thumb_disabled,
+ switchView.getContext().getTheme());
+
+ int[] thumbColors = new int[]{
+ thumbColorCheckedEnabled,
+ thumbColorUncheckedEnabled,
+ thumbColorDisabled
+ };
+
+ thumbColorStateList = new ColorStateList(states, thumbColors);
+
+ int trackColorCheckedEnabled = ResourcesCompat.getColor(
+ switchView.getContext().getResources(),
+ R.color.switch_track_checked_enabled,
+ switchView.getContext().getTheme());
+ int trackColorUncheckedEnabled = ResourcesCompat.getColor(
+ switchView.getContext().getResources(),
+ R.color.switch_track_unchecked_enabled,
+ switchView.getContext().getTheme());
+ int trackColorDisabled = ResourcesCompat.getColor(
+ switchView.getContext().getResources(),
+ R.color.switch_track_disabled,
+ switchView.getContext().getTheme());
+
+ int[] trackColors = new int[]{
+ trackColorCheckedEnabled,
+ trackColorUncheckedEnabled,
+ trackColorDisabled
+ };
+ trackColorStateList = new ColorStateList(states, trackColors);
+
+ switchView.setThumbTintList(thumbColorStateList);
+ switchView.setTrackTintList(trackColorStateList);
break;
} else if (child instanceof ViewGroup) {
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
index bcbed6b84d77..c5af20507d7a 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
@@ -18,8 +18,6 @@
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -40,6 +38,7 @@
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.URLUtil;
+import android.widget.ListView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.nextcloud.android.common.ui.util.extensions.WindowExtensionsKt;
@@ -50,11 +49,13 @@
import com.nextcloud.client.logger.ui.LogsActivity;
import com.nextcloud.client.network.ClientFactory;
import com.nextcloud.client.network.ConnectivityService;
+import com.nmc.android.ui.PrivacySettingsInterface;
import com.nextcloud.client.preferences.AppPreferences;
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.nextcloud.client.preferences.DarkMode;
import com.nextcloud.utils.extensions.ViewExtensionsKt;
import com.nextcloud.utils.mdm.MDMConfig;
+import com.owncloud.android.BuildConfig;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -75,17 +76,18 @@
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.EncryptionUtils;
import com.owncloud.android.utils.MimeTypeUtil;
+import com.owncloud.android.utils.StringUtils;
import com.owncloud.android.utils.theme.CapabilityUtils;
import com.owncloud.android.utils.theme.ViewThemeUtils;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import javax.inject.Inject;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
@@ -144,6 +146,17 @@ public class SettingsActivity extends PreferenceActivity
@Inject ViewThemeUtils viewThemeUtils;
@Inject ConnectivityService connectivityService;
+ /**
+ * Things to note about both the branches.
+ * 1. nmc/1921-settings branch:
+ * --> interface won't be initialised
+ * --> calling of interface method will be done here
+ * 2. nmc/1878-privacy
+ * --> interface will be initialised
+ * --> calling of interface method won't be done here
+ */
+ private PrivacySettingsInterface privacySettingsInterface;
+
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -164,12 +177,15 @@ public void onCreate(Bundle savedInstanceState) {
getDelegate().onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
+ ListView listView = getListView();
+ listView.setDivider(ResourcesCompat.getDrawable(getResources(), R.drawable.item_divider, null));
+
setupActionBar();
// Register context menu for list of preferences.
registerForContextMenu(getListView());
- String appVersion = getAppVersion();
+ int titleColor = getResources().getColor(R.color.fontAppbar, null);
PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference("preference_screen");
user = accountManager.getUser();
@@ -177,26 +193,40 @@ public void onCreate(Bundle savedInstanceState) {
// retrieve user's base uri
setupBaseUri();
+ // Account Information
+ setupAccountInfoCategory(titleColor);
+
// General
- setupGeneralCategory();
+ setupGeneralCategory(titleColor);
// Synced folders
- setupAutoUploadCategory(preferenceScreen);
+ setupAutoUploadCategory(titleColor, preferenceScreen);
// Details
- setupDetailsCategory(preferenceScreen);
+ setupDetailsCategory(titleColor, preferenceScreen);
// Sync
- setupSyncCategory();
+ setupSyncCategory(titleColor);
// More
- setupMoreCategory();
+ setupMoreCategory(titleColor);
// About
- setupAboutCategory(appVersion);
+ // Not required in NMC
+ // setupAboutCategory(appVersion);
+
+ // Data Privacy
+ setupDataPrivacyCategory(titleColor);
+
+ //Service
+ setUpServiceCategory(titleColor);
+
+ //Info
+ setUpInfoCategory(titleColor);
+ // Not required for NMC
// Dev
- setupDevCategory(preferenceScreen);
+ // setupDevCategory(preferenceScreen);
// workaround for mismatched color when app dark mode and system dark mode don't agree
setListBackground();
@@ -363,21 +393,107 @@ public void onBackPressed() {
startActivity(i);
}
- private void setupSyncCategory() {
+ private void setupSyncCategory(int titleColor) {
final PreferenceCategory preferenceCategorySync = (PreferenceCategory) findPreference("sync");
- viewThemeUtils.files.themePreferenceCategory(preferenceCategorySync);
+ preferenceCategorySync.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_sync),
+ titleColor));
+ setupAutoUploadPreference(preferenceCategorySync, titleColor);
+ // setupInternalTwoWaySyncPreference(titleColor);
+ }
+
+ /**
+ * NMC customization
+ */
+ private void setupDataPrivacyCategory(int titleColor) {
+ PreferenceCategory preferenceCategoryAbout = (PreferenceCategory) findPreference("data_protection");
+ preferenceCategoryAbout.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_data_privacy),
+ titleColor));
+
+ //privacy settings
+ Preference privacySettingPreference = findPreference("privacy_settings");
+ if (privacySettingPreference != null) {
+ privacySettingPreference.setTitle(StringUtils.getColorSpan(getString(R.string.privacy_settings),
+ titleColor));
+ privacySettingPreference.setOnPreferenceClickListener(preference -> {
+ //implementation and logic will be available in nmc/1878-privacy
+ if (privacySettingsInterface != null) {
+ privacySettingsInterface.openPrivacySettingsActivity(SettingsActivity.this);
+ }
+ return true;
+ });
+ }
+
+ // privacy policy
+ Preference privacyPolicyPreference = findPreference("privacy_policy");
+
+ if (privacyPolicyPreference != null) {
+ privacyPolicyPreference.setTitle(StringUtils.getColorSpan(getString(R.string.privacy_policy),
+ titleColor));
+ if (URLUtil.isValidUrl(getString(R.string.privacy_url))) {
+ privacyPolicyPreference.setOnPreferenceClickListener(preference -> {
+ try {
+ Uri privacyUrl = Uri.parse(getString(R.string.privacy_url));
+ String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(privacyUrl.getLastPathSegment());
+
+ Intent intent;
+ if (MimeTypeUtil.isPDF(mimeType)) {
+ intent = new Intent(Intent.ACTION_VIEW, privacyUrl);
+ DisplayUtils.startIntentIfAppAvailable(intent, this, R.string.no_pdf_app_available);
+ } else {
+ intent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
+ intent.putExtra(ExternalSiteWebView.EXTRA_TITLE,
+ getResources().getString(R.string.privacy_policy));
+ intent.putExtra(ExternalSiteWebView.EXTRA_URL, privacyUrl.toString());
+ intent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
+ }
+
+ startActivity(intent);
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Could not parse privacy policy url");
+ preferenceCategoryAbout.removePreference(privacyPolicyPreference);
+ }
+ return true;
+ });
+ } else {
+ preferenceCategoryAbout.removePreference(privacyPolicyPreference);
+ }
+ }
+
+ // source code
+ Preference sourcecodePreference = findPreference("sourcecode");
+ if (sourcecodePreference != null) {
+ sourcecodePreference.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_open_source),
+ titleColor));
+ if (URLUtil.isValidUrl(getString(R.string.sourcecode_url))) {
+ sourcecodePreference.setOnPreferenceClickListener(preference -> {
+ Intent intent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
+ intent.putExtra(ExternalSiteWebView.EXTRA_TITLE,
+ getResources().getString(R.string.prefs_open_source));
+ intent.putExtra(ExternalSiteWebView.EXTRA_URL, getResources().getString(R.string.sourcecode_url));
+ intent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
+ startActivity(intent);
+ return true;
+ });
+ } else {
+ preferenceCategoryAbout.removePreference(sourcecodePreference);
+ }
+ }
+ }
- setupAutoUploadPreference(preferenceCategorySync);
- setupInternalTwoWaySyncPreference();
+ private void setUpInfoCategory(int titleColor) {
+ PreferenceCategory preferenceCategoryAbout = (PreferenceCategory) findPreference("info");
+ preferenceCategoryAbout.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_info),
+ titleColor));
}
- private void setupMoreCategory() {
+ private void setupMoreCategory(int titleColor) {
final PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more");
- viewThemeUtils.files.themePreferenceCategory(preferenceCategoryMore);
+ preferenceCategoryMore.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_more),
+ titleColor));
setupCalendarPreference(preferenceCategoryMore);
- setupBackupPreference();
+ setupBackupPreference(titleColor);
setupE2EPreference(preferenceCategoryMore);
@@ -387,40 +503,19 @@ private void setupMoreCategory() {
removeE2E(preferenceCategoryMore);
- setupHelpPreference(preferenceCategoryMore);
-
setupRecommendPreference(preferenceCategoryMore);
- setupLoggingPreference(preferenceCategoryMore);
-
- setupImprintPreference(preferenceCategoryMore);
+ setupLoggingPreference(preferenceCategoryMore, titleColor);
loadExternalSettingLinks(preferenceCategoryMore);
}
- private void setupImprintPreference(PreferenceCategory preferenceCategoryMore) {
- boolean imprintEnabled = getResources().getBoolean(R.bool.imprint_enabled);
- Preference pImprint = findPreference("imprint");
- if (pImprint != null) {
- if (imprintEnabled) {
- pImprint.setOnPreferenceClickListener(preference -> {
- String imprintWeb = getString(R.string.url_imprint);
-
- if (!imprintWeb.isEmpty()) {
- DisplayUtils.startLinkIntent(this, imprintWeb);
- }
- //ImprintDialog.newInstance(true).show(preference.get, "IMPRINT_DIALOG");
- return true;
- });
- } else {
- preferenceCategoryMore.removePreference(pImprint);
- }
- }
- }
+ private void setupLoggingPreference(PreferenceCategory preferenceCategoryMore, int titleColor) {
- private void setupLoggingPreference(PreferenceCategory preferenceCategoryMore) {
Preference pLogger = findPreference("logger");
if (pLogger != null) {
+ pLogger.setTitle(StringUtils.getColorSpan(getString(R.string.logs_title),
+ titleColor));
if (MDMConfig.INSTANCE.isLogEnabled(this)) {
pLogger.setOnPreferenceClickListener(preference -> {
Intent loggerIntent = new Intent(getApplicationContext(), LogsActivity.class);
@@ -577,23 +672,10 @@ private void showRemoveE2EAlertDialog(PreferenceCategory preferenceCategoryMore,
.show();
}
- private void setupHelpPreference(PreferenceCategory preferenceCategoryMore) {
- boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled);
- Preference pHelp = findPreference("help");
- if (pHelp != null) {
- if (helpEnabled) {
- pHelp.setOnPreferenceClickListener(preference -> {
- DisplayUtils.startLinkIntent(this, R.string.url_help);
- return true;
- });
- } else {
- preferenceCategoryMore.removePreference(pHelp);
- }
- }
- }
-
- private void setupAutoUploadPreference(PreferenceCategory preferenceCategoryMore) {
+ private void setupAutoUploadPreference(PreferenceCategory preferenceCategoryMore, int titleColor) {
Preference autoUpload = findPreference("syncedFolders");
+ autoUpload.setTitle(StringUtils.getColorSpan(getString(R.string.drawer_synced_folders),
+ titleColor));
if (getResources().getBoolean(R.bool.syncedFolder_light)) {
preferenceCategoryMore.removePreference(autoUpload);
} else {
@@ -605,8 +687,10 @@ private void setupAutoUploadPreference(PreferenceCategory preferenceCategoryMore
}
}
- private void setupInternalTwoWaySyncPreference() {
+ private void setupInternalTwoWaySyncPreference(int titleColor) {
Preference twoWaySync = findPreference("internal_two_way_sync");
+ twoWaySync.setTitle(StringUtils.getColorSpan(getString(R.string.internal_two_way_sync),
+ titleColor));
twoWaySync.setOnPreferenceClickListener(preference -> {
Intent intent = new Intent(this, InternalTwoWaySyncActivity.class);
@@ -615,13 +699,12 @@ private void setupInternalTwoWaySyncPreference() {
});
}
- private void setupBackupPreference() {
+ private void setupBackupPreference(int titleColor) {
Preference pContactsBackup = findPreference("backup");
if (pContactsBackup != null) {
boolean showCalendarBackup = getResources().getBoolean(R.bool.show_calendar_backup);
- pContactsBackup.setTitle(showCalendarBackup
- ? getString(R.string.backup_title)
- : getString(R.string.contact_backup_title));
+ // NMC Customization
+ pContactsBackup.setTitle(StringUtils.getColorSpan(getString(R.string.actionbar_contacts), titleColor));
pContactsBackup.setSummary(showCalendarBackup
? getString(R.string.prefs_daily_backup_summary)
: getString(R.string.prefs_daily_contact_backup_summary));
@@ -655,9 +738,10 @@ private void setupCalendarPreference(PreferenceCategory preferenceCategoryMore)
}
}
- private void setupDetailsCategory(PreferenceScreen preferenceScreen) {
+ private void setupDetailsCategory(int titleColor, PreferenceScreen preferenceScreen) {
PreferenceCategory preferenceCategoryDetails = (PreferenceCategory) findPreference("details");
- viewThemeUtils.files.themePreferenceCategory(preferenceCategoryDetails);
+ preferenceCategoryDetails.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_details),
+ titleColor));
boolean fPassCodeEnabled = getResources().getBoolean(R.bool.passcode_enabled);
boolean fDeviceCredentialsEnabled = getResources().getBoolean(R.bool.device_credentials_enabled);
@@ -666,13 +750,13 @@ private void setupDetailsCategory(PreferenceScreen preferenceScreen) {
boolean fSyncedFolderLightEnabled = getResources().getBoolean(R.bool.syncedFolder_light);
boolean fShowMediaScanNotifications = preferences.isShowMediaScanNotifications();
- setupLockPreference(preferenceCategoryDetails, fPassCodeEnabled, fDeviceCredentialsEnabled);
+ setupLockPreference(preferenceCategoryDetails, fPassCodeEnabled, fDeviceCredentialsEnabled, titleColor);
- setupHiddenFilesPreference(preferenceCategoryDetails, fShowHiddenFilesEnabled);
+ setupHiddenFilesPreference(preferenceCategoryDetails, fShowHiddenFilesEnabled, titleColor);
setupShowEcosystemAppsPreference(preferenceCategoryDetails, fShowEcosystemAppsEnabled);
- setupShowMediaScanNotifications(preferenceCategoryDetails, fShowMediaScanNotifications);
+ setupShowMediaScanNotifications(preferenceCategoryDetails, fShowMediaScanNotifications, titleColor);
if (!fPassCodeEnabled && !fDeviceCredentialsEnabled && !fShowHiddenFilesEnabled && fSyncedFolderLightEnabled
&& fShowMediaScanNotifications) {
@@ -681,18 +765,20 @@ private void setupDetailsCategory(PreferenceScreen preferenceScreen) {
}
private void setupShowMediaScanNotifications(PreferenceCategory preferenceCategoryDetails,
- boolean fShowMediaScanNotifications) {
- ThemeableSwitchPreference mShowMediaScanNotifications =
- (ThemeableSwitchPreference) findPreference(PREFERENCE_SHOW_MEDIA_SCAN_NOTIFICATIONS);
-
+ boolean fShowMediaScanNotifications, int titleColor) {
+ SwitchPreference mShowMediaScanNotifications = (SwitchPreference) findPreference(PREFERENCE_SHOW_MEDIA_SCAN_NOTIFICATIONS);
+ mShowMediaScanNotifications.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_enable_media_scan_notifications),
+ titleColor));
if (fShowMediaScanNotifications) {
preferenceCategoryDetails.removePreference(mShowMediaScanNotifications);
}
}
private void setupHiddenFilesPreference(PreferenceCategory preferenceCategoryDetails,
- boolean fShowHiddenFilesEnabled) {
+ boolean fShowHiddenFilesEnabled, int titleColor) {
showHiddenFiles = (ThemeableSwitchPreference) findPreference("show_hidden_files");
+ showHiddenFiles.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_show_hidden_files),
+ titleColor));
if (fShowHiddenFilesEnabled) {
showHiddenFiles.setOnPreferenceClickListener(preference -> {
preferences.setShowHiddenFilesEnabled(showHiddenFiles.isChecked());
@@ -718,9 +804,11 @@ private void setupShowEcosystemAppsPreference(PreferenceCategory preferenceCateg
private void setupLockPreference(PreferenceCategory preferenceCategoryDetails,
boolean passCodeEnabled,
- boolean deviceCredentialsEnabled) {
+ boolean deviceCredentialsEnabled, int titleColor) {
boolean enforceProtection = MDMConfig.INSTANCE.enforceProtection(this);
lock = (ListPreferenceDialog) findPreference(PREFERENCE_LOCK);
+ lock.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_lock),
+ titleColor));
int optionSize = 3;
if (enforceProtection) {
optionSize = 2;
@@ -776,10 +864,11 @@ private void setupLockPreference(PreferenceCategory preferenceCategoryDetails,
}
}
- private void setupAutoUploadCategory(PreferenceScreen preferenceScreen) {
+ private void setupAutoUploadCategory(int titleColor, PreferenceScreen preferenceScreen) {
final PreferenceCategory preferenceCategorySyncedFolders =
(PreferenceCategory) findPreference("synced_folders_category");
- viewThemeUtils.files.themePreferenceCategory(preferenceCategorySyncedFolders);
+ preferenceCategorySyncedFolders.setTitle(StringUtils.getColorSpan(getString(R.string.drawer_synced_folders),
+ titleColor));
if (!getResources().getBoolean(R.bool.syncedFolder_light)) {
preferenceScreen.removePreference(preferenceCategorySyncedFolders);
@@ -788,6 +877,8 @@ private void setupAutoUploadCategory(PreferenceScreen preferenceScreen) {
final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(this);
final SwitchPreference pUploadOnWifiCheckbox = (SwitchPreference) findPreference("synced_folder_on_wifi");
+ pUploadOnWifiCheckbox.setTitle(StringUtils.getColorSpan(getString(R.string.auto_upload_on_wifi),
+ titleColor));
pUploadOnWifiCheckbox.setChecked(
arbitraryDataProvider.getBooleanValue(user, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI));
@@ -813,6 +904,73 @@ private void setupAutoUploadCategory(PreferenceScreen preferenceScreen) {
}
}
+ private void setUpServiceCategory(int titleColor) {
+ PreferenceCategory preferenceCategoryService = (PreferenceCategory) findPreference("service");
+ preferenceCategoryService.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_service),
+ titleColor));
+ setupHelpPreference(titleColor);
+ setupDeleteAccountPreference(titleColor);
+ setupImprintPreference(titleColor);
+ }
+
+ private void setupHelpPreference(int titleColor) {
+ Preference pHelp = findPreference("help");
+ if (pHelp != null) {
+ pHelp.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_help),
+ titleColor));
+ pHelp.setOnPreferenceClickListener(preference -> {
+ String helpWeb = getString(R.string.url_help);
+ if (!helpWeb.isEmpty()) {
+ openLinkInWebView(helpWeb, R.string.prefs_help);
+ }
+ return true;
+ });
+
+ }
+ }
+
+ private void setupDeleteAccountPreference(int titleColor) {
+ Preference pHelp = findPreference("delete_account");
+ if (pHelp != null) {
+ pHelp.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_delete_account),
+ titleColor));
+ pHelp.setOnPreferenceClickListener(preference -> {
+ String helpWeb = getString(R.string.url_delete_account);
+ if (!helpWeb.isEmpty()) {
+ openLinkInWebView(helpWeb, R.string.prefs_delete_account);
+ }
+ return true;
+ });
+
+ }
+ }
+
+ private void setupImprintPreference(int titleColor) {
+ Preference pImprint = findPreference("imprint");
+ if (pImprint != null) {
+ pImprint.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_imprint),
+ titleColor));
+ pImprint.setOnPreferenceClickListener(preference -> {
+ String imprintWeb = getString(R.string.url_imprint_nmc);
+ if (!imprintWeb.isEmpty()) {
+ openLinkInWebView(imprintWeb, R.string.prefs_imprint);
+ }
+ //ImprintDialog.newInstance(true).show(preference.get, "IMPRINT_DIALOG");
+ return true;
+ });
+ }
+
+ }
+
+ private void openLinkInWebView(String url, @StringRes int title) {
+ Intent externalWebViewIntent = new Intent(getApplicationContext(), ExternalSiteWebView.class);
+ externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE,
+ getResources().getString(title));
+ externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, url);
+ externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
+ startActivity(externalWebViewIntent);
+ }
+
private void enableLock(String lock) {
pendingLock = LOCK_NONE;
if (LOCK_PASSCODE.equals(lock)) {
@@ -846,10 +1004,20 @@ private void disableLock(String lock) {
}
}
- private void setupGeneralCategory() {
- final PreferenceCategory preferenceCategoryGeneral = (PreferenceCategory) findPreference("general");
- viewThemeUtils.files.themePreferenceCategory(preferenceCategoryGeneral);
+ private void setupAccountInfoCategory(int titleColor) {
+ PreferenceCategory preferenceCategoryAccountInfo = (PreferenceCategory) findPreference("account_info");
+ preferenceCategoryAccountInfo.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_account_info),
+ titleColor));
+
+ Preference autoUpload = findPreference("user_name");
+ autoUpload.setTitle(StringUtils.getColorSpan(accountManager.getUser().toOwnCloudAccount().getDisplayName(),
+ titleColor));
+ }
+ private void setupGeneralCategory(int titleColor) {
+ PreferenceCategory preferenceCategoryGeneral = (PreferenceCategory) findPreference("general");
+ preferenceCategoryGeneral.setTitle(StringUtils.getColorSpan(getString(R.string.prefs_category_general),
+ titleColor));
readStoragePath();
prefDataLoc = findPreference(AppPreferencesImpl.DATA_STORAGE_LOCATION);
@@ -862,52 +1030,12 @@ private void setupGeneralCategory() {
});
}
- ListPreference themePref = (ListPreference) findPreference("darkMode");
-
- List themeEntries = new ArrayList<>(3);
- themeEntries.add(getString(R.string.prefs_value_theme_light));
- themeEntries.add(getString(R.string.prefs_value_theme_dark));
- themeEntries.add(getString(R.string.prefs_value_theme_system));
-
- List themeValues = new ArrayList<>(3);
- themeValues.add(DarkMode.LIGHT.name());
- themeValues.add(DarkMode.DARK.name());
- themeValues.add(DarkMode.SYSTEM.name());
-
- themePref.setEntries(themeEntries.toArray(new String[0]));
- themePref.setEntryValues(themeValues.toArray(new String[0]));
-
- if (TextUtils.isEmpty(themePref.getEntry())) {
- themePref.setValue(DarkMode.SYSTEM.name());
- themePref.setSummary(TextUtils.isEmpty(themePref.getEntry()) ? DarkMode.SYSTEM.name() : themePref.getEntry());
- }
-
- themePref.setOnPreferenceChangeListener((preference, newValue) -> {
- DarkMode mode = DarkMode.valueOf((String) newValue);
- preferences.setDarkThemeMode(mode);
- MainApp.setAppTheme(mode);
- setListBackground();
-
- return true;
- });
}
private void setListBackground() {
getListView().setBackgroundColor(ContextCompat.getColor(this, R.color.bg_default));
}
- private String getAppVersion() {
- String temp;
- try {
- PackageInfo pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
- temp = pkg.versionName;
- } catch (NameNotFoundException e) {
- temp = "";
- Log_OC.e(TAG, "Error while showing about dialog", e);
- }
- return temp;
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
finish();
diff --git a/app/src/main/java/com/owncloud/android/utils/StringUtils.java b/app/src/main/java/com/owncloud/android/utils/StringUtils.java
index d4339f0003eb..3f67854ef0dd 100644
--- a/app/src/main/java/com/owncloud/android/utils/StringUtils.java
+++ b/app/src/main/java/com/owncloud/android/utils/StringUtils.java
@@ -7,6 +7,11 @@
*/
package com.owncloud.android.utils;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ForegroundColorSpan;
+
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -55,6 +60,15 @@ String searchAndColor(@Nullable String text, @Nullable String searchText,
}
}
+ public static Spannable getColorSpan(@NonNull String title, @ColorInt int color) {
+ Spannable text = new SpannableString(title);
+ text.setSpan(new ForegroundColorSpan(color),
+ 0,
+ text.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ return text;
+ }
+
public static
@NonNull
String removePrefix(@NonNull String s, @NonNull String prefix) {
diff --git a/app/src/main/res/drawable/item_divider.xml b/app/src/main/res/drawable/item_divider.xml
new file mode 100644
index 000000000000..9f742e91d67c
--- /dev/null
+++ b/app/src/main/res/drawable/item_divider.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/custom_app_preference_layout.xml b/app/src/main/res/layout/custom_app_preference_layout.xml
new file mode 100644
index 000000000000..5c8ab83fae4c
--- /dev/null
+++ b/app/src/main/res/layout/custom_app_preference_layout.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/custom_preference_layout.xml b/app/src/main/res/layout/custom_preference_layout.xml
new file mode 100644
index 000000000000..1f6991c06e56
--- /dev/null
+++ b/app/src/main/res/layout/custom_preference_layout.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/activity_logs.xml b/app/src/main/res/menu/activity_logs.xml
index 08a14cf62093..0e6e6dc40559 100644
--- a/app/src/main/res/menu/activity_logs.xml
+++ b/app/src/main/res/menu/activity_logs.xml
@@ -27,10 +27,17 @@
android:orderInCategory="200"
android:icon="@drawable/ic_send"/>
+
+
diff --git a/app/src/main/res/values-de/nmc_logs_strings.xml b/app/src/main/res/values-de/nmc_logs_strings.xml
new file mode 100644
index 000000000000..223e2215231c
--- /dev/null
+++ b/app/src/main/res/values-de/nmc_logs_strings.xml
@@ -0,0 +1,12 @@
+
+
+
+ Protokolle speichern
+ Protokolle erfolgreich gespeichert
+ Fehler beim Speichern der Protokolle
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index bc5f9fc46acb..ef4e9e77e0ac 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -13,7 +13,8 @@
Senden/Teilen
Kachelansicht
Listenansicht
- Kontakte und Kalender wiederherstellen
+ Kontakte & Kalender wiederherstellen
+ Kontakte sichern
Neuer Ordner
Verschieben oder kopieren
Öffnen mit
@@ -710,6 +711,7 @@
Ende-zu-Ende-Verschlüsselung ist eingerichtet!
E2E-Gedächtnisstütze
Um die Gedächtnisstütze anzuzeigen, aktivieren Sie bitte Geräte-Zugangsdaten
+ 12-Wort-Schlüssel anzeigen (Passphrase)
Benachrichtigungen der Mediensuche anzeigen
Über neu gefundene Medienordner informieren
GNU General Public Lizenz, version 2
@@ -1074,6 +1076,15 @@
Wir konnten die Datei auf dem Server nicht finden. Ein anderer Benutzer hat möglicherweise die Datei gelöscht.
Ordnername
Fehlgeschlagene lokale Dateien erneut hochladen
+ Kontoinformationen
+ Datenschutz
+ Datenschutz-Einstellungen
+ Datenschutzbestimmungen
+ Konto endgültig löschen
+ Verwendete OpenSource Software
+ Info
+ Bedienung
+ Die Ende-zu-Ende Verschlüsselung wurde bereits auf einem anderen Gerät eingerichtet. Bitte geben Sie Ihre Passphrase ein, damit die Dateien synchronisiert und entschlüsselt werden.
Hochladeordner auswählen
Konnte %1$s nicht hochladen
Hochladen fehlgeschlagen, bitte erneut anmelden
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index db1e1d218038..c5134bdaad77 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -39,4 +39,68 @@
@android:color/white
#101418
+
+
+ #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 36d7459ecdaf..90c40fb1a4ad 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -89,4 +89,93 @@
#A5A5A5
#F7F9FF
+
+
+ #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_logs_strings.xml b/app/src/main/res/values/nmc_logs_strings.xml
new file mode 100644
index 000000000000..c71e7a804eb3
--- /dev/null
+++ b/app/src/main/res/values/nmc_logs_strings.xml
@@ -0,0 +1,12 @@
+
+
+
+ Save logs
+ Logs saved successfully
+ Failed to save logs
+
\ No newline at end of file
diff --git a/app/src/main/res/values/setup.xml b/app/src/main/res/values/setup.xml
index afed2dafe23a..4c492d82600a 100644
--- a/app/src/main/res/values/setup.xml
+++ b/app/src/main/res/values/setup.xml
@@ -99,6 +99,10 @@
"https://play.google.com/store/apps/details?id=com.nextcloud.client"
https://nextcloud.com/install
+ https://www.telekom.de/hilfe/vertrag-rechnung/login-daten-passwoerter/telekom-login-loeschen
+
+ https://www.telekom.de/impressum
false
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3341599e790d..f021f09ad0e9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -117,6 +117,7 @@
Calendar and contacts sync set up
Daily backup of your calendar and contacts
Daily backup of your contacts
+ Displays your 12 word key (passhprase)
Manage folders for auto upload
Help
Recommend to a friend
@@ -125,6 +126,7 @@
Dark
Follow system
Theme
+ End-to-end encryption was already set up on another client. Please enter your mnemonic to allow this client to sync and decrypt the files.
Enable two way sync
Interval
@@ -644,6 +646,7 @@
Grid view
List view
+ Back up contacts
Manage space
Settings, database and server certificates from %1$s\'s data will be deleted permanently. \n\nDownloaded files will be kept untouched.\n\nThis process can take a while.
@@ -1217,6 +1220,7 @@
Storage permissions
%1$s needs file management permissions to upload files. You can choose full access to all files, or read-only access to photos and videos.
%1$s works best with permissions to access storage. You can choose full access to all files, or read-only access to photos and videos.
+ Account Information
No results found for your query
Start your search
Type in the search bar above to find files, contacts, calendar events, and more across your account.
@@ -1275,6 +1279,13 @@
Not possible without internet connection
Scan page
Done
+ Info
+ Data Privacy
+ Privacy Settings
+ Privacy Policy
+ Delete account permanently
+ Used OpenSource Software
+ Service
Generating PDF…
Error starting document scan
PDF generation failed
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 63a1902c5264..2544e448a08b 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,5 +1,4 @@
-
-
-
+ android:key="preference_screen">
+
+
+
+
+
+
+
-
-
-
-
-
-
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/prefs_data_storage_location_summary"
+ android:title="@string/prefs_data_storage_location" />
+
-
-
-
+
+
+
+
+
+
+
+
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/prefs_show_ecosystem_apps_summary"
+ android:title="@string/prefs_show_ecosystem_apps" />
-
-
-
-
+ android:title="@string/prefs_enable_media_scan_notifications" />
+
+
-
+ android:key="syncedFolders"
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/prefs_sycned_folders_summary"
+ android:title="@string/drawer_synced_folders" />
-
-
+
+
+
+
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/prefs_daily_backup_summary"
+ android:title="@string/backup_title" />
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/setup_e2e"
+ android:title="@string/prefs_setup_e2e" />
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/prefs_keys_exist_summary"
+ android:title="@string/prefs_keys_exist" />
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/prefs_mnemonic_summary"
+ android:title="@string/prefs_e2e_mnemonic" />
+ android:layout="@layout/custom_preference_layout"
+ android:summary="@string/remove_e2e"
+ android:title="@string/prefs_remove_e2e" />
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+ android:id="@+id/privacy_policy"
+ android:key="privacy_policy"
+ android:layout="@layout/custom_preference_layout"
+ android:title="@string/privacy_policy" />
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
diff --git a/app/src/release/res/values/log_config.xml b/app/src/release/res/values/log_config.xml
new file mode 100644
index 000000000000..11b54b011564
--- /dev/null
+++ b/app/src/release/res/values/log_config.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ false
+
\ No newline at end of file