diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ac2a4665..4a4351e6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -105,7 +105,6 @@
+ android:label="@string/recovery_code_title" />
+ android:permission="com.stevesoltys.seedvault.RESTORE_BACKUP">
diff --git a/app/src/main/java/com/stevesoltys/seedvault/App.kt b/app/src/main/java/com/stevesoltys/seedvault/App.kt
index 053af85f..9389eb05 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/App.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/App.kt
@@ -20,6 +20,7 @@ import android.os.UserManager
import android.provider.Settings
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
import androidx.work.WorkManager
+import com.google.android.material.color.DynamicColors
import com.stevesoltys.seedvault.crypto.cryptoModule
import com.stevesoltys.seedvault.header.headerModule
import com.stevesoltys.seedvault.metadata.MetadataManager
@@ -114,6 +115,7 @@ open class App : Application() {
override fun onCreate() {
super.onCreate()
+ DynamicColors.applyToActivitiesIfAvailable(this)
startKoin()
if (isDebugBuild()) {
StrictMode.setThreadPolicy(
diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreProgressFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreProgressFragment.kt
index 21b2f228..1f32eb76 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreProgressFragment.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreProgressFragment.kt
@@ -14,12 +14,12 @@ import android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
-import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat.getColor
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.ui.AppBackupState.FAILED_NOT_INSTALLED
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
@@ -99,7 +99,7 @@ class RestoreProgressFragment : Fragment() {
// check if any restore failed, because the app is not installed
val failed = viewModel.restoreProgress.value?.any { it.state == FAILED_NOT_INSTALLED }
if (failed != true) return // nothing left to do if there's no failures due to not installed
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.restore_restoring_error_title)
.setMessage(R.string.restore_restoring_error_message)
.setPositiveButton(android.R.string.ok) { dialog, _ ->
diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt
index 926dab69..014f198c 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt
@@ -19,11 +19,11 @@ import android.widget.TextView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.activity.result.contract.ActivityResultContract
-import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.restore.RestoreViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
@@ -96,7 +96,7 @@ class InstallProgressFragment : Fragment(), InstallItemListener {
adapter.setFinished()
button.isEnabled = true
if (!hasShownFailDialog && installResult.hasFailed) {
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(R.drawable.ic_warning)
.setTitle(R.string.restore_installing_error_title)
.setMessage(R.string.restore_installing_error_message)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SchedulingFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SchedulingFragment.kt
index 4309ecf2..ea901b4b 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/settings/SchedulingFragment.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SchedulingFragment.kt
@@ -8,6 +8,8 @@ package com.stevesoltys.seedvault.settings
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
+import androidx.preference.ListPreference
+import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
@@ -16,6 +18,7 @@ import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.plugins.StoragePluginManager
+import com.stevesoltys.seedvault.settings.preference.M3ListPreference
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
@@ -42,6 +45,21 @@ class SchedulingFragment : PreferenceFragmentCompat(),
}
}
+ override fun onDisplayPreferenceDialog(preference: Preference?) {
+ when (preference) {
+ is ListPreference -> {
+ val dialogFragment = M3ListPreference.newInstance(preference.getKey())
+ dialogFragment.setTargetFragment(this, 0)
+ dialogFragment.show(
+ parentFragmentManager,
+ M3ListPreference.PREFERENCE_DIALOG_FRAGMENT_TAG
+ )
+ }
+
+ else -> super.onDisplayPreferenceDialog(preference)
+ }
+ }
+
override fun onStart() {
super.onStart()
diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsActivity.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsActivity.kt
index 436a040b..6697e3f4 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsActivity.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsActivity.kt
@@ -34,6 +34,7 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
setContentView(R.layout.activity_fragment_container)
+ setSupportActionBar(requireViewById(R.id.toolbar))
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
// always start with settings fragment as a base (when fresh start)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt
index e7a98ff2..e4096d20 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt
@@ -19,12 +19,12 @@ import android.view.MenuItem
import android.view.View
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
-import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.Preference.OnPreferenceChangeListener
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import androidx.work.WorkInfo
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.plugins.StoragePluginManager
@@ -77,7 +77,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
when (enabled) {
true -> return@OnPreferenceChangeListener trySetBackupEnabled(true)
false -> {
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(R.drawable.ic_warning)
.setTitle(R.string.settings_backup_dialog_title)
.setMessage(R.string.settings_backup_dialog_message)
@@ -123,7 +123,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
apkBackup.onPreferenceChangeListener = OnPreferenceChangeListener { _, newValue ->
val enable = newValue as Boolean
if (enable) return@OnPreferenceChangeListener true
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(R.drawable.ic_warning)
.setTitle(R.string.settings_backup_apk_dialog_title)
.setMessage(R.string.settings_backup_apk_dialog_message)
@@ -313,7 +313,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
private fun onEnablingStorageBackup() {
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(R.drawable.ic_warning)
.setTitle(R.string.settings_backup_storage_dialog_title)
.setMessage(R.string.settings_backup_storage_dialog_message)
@@ -341,7 +341,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
private fun showCodeRegenerationNeededDialog() {
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(R.drawable.ic_vpn_key)
.setTitle(R.string.settings_backup_new_code_dialog_title)
.setMessage(R.string.settings_backup_new_code_dialog_message)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/preference/M3ListPreference.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/preference/M3ListPreference.kt
new file mode 100644
index 00000000..45e5cc9d
--- /dev/null
+++ b/app/src/main/java/com/stevesoltys/seedvault/settings/preference/M3ListPreference.kt
@@ -0,0 +1,45 @@
+/*
+ * SPDX-FileCopyrightText: 2024 The Calyx Institute
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.stevesoltys.seedvault.settings.preference
+
+import android.app.Dialog
+import android.os.Bundle
+import androidx.preference.ListPreferenceDialogFragmentCompat
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+
+class M3ListPreference : ListPreferenceDialogFragmentCompat() {
+
+ companion object {
+ const val PREFERENCE_DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG"
+
+ fun newInstance(key: String?): M3ListPreference {
+ val fragment = M3ListPreference()
+ val bundle = Bundle(1)
+ bundle.putString(ARG_KEY, key)
+ fragment.arguments = bundle
+ return fragment
+ }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val builder = MaterialAlertDialogBuilder(requireContext())
+ .setTitle(preference.dialogTitle)
+ .setIcon(preference.dialogIcon)
+ .setPositiveButton(preference.positiveButtonText, this)
+ .setNegativeButton(preference.negativeButtonText, this)
+
+ val contentView = onCreateDialogView(requireContext())
+ if (contentView != null) {
+ onBindDialogView(contentView)
+ builder.setView(contentView)
+ } else {
+ builder.setMessage(preference.dialogMessage)
+ }
+
+ onPrepareDialogBuilder(builder)
+ return builder.create()
+ }
+}
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt
index 5a0e4607..6cd76ba5 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt
@@ -21,20 +21,20 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import android.view.WindowManager.LayoutParams.FLAG_SECURE
import android.widget.ArrayAdapter
-import android.widget.AutoCompleteTextView
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
-import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat.getMainExecutor
import androidx.fragment.app.Fragment
import cash.z.ecc.android.bip39.Mnemonics
import cash.z.ecc.android.bip39.Mnemonics.ChecksumException
import cash.z.ecc.android.bip39.Mnemonics.InvalidWordException
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.textfield.MaterialAutoCompleteTextView
import com.google.android.material.textfield.TextInputLayout
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.isDebugBuild
@@ -118,7 +118,7 @@ class RecoveryCodeInputFragment : Fragment() {
for (i in 0 until WORD_NUM) {
val wordLayout = getWordLayout(i)
- val editText = wordLayout.editText as AutoCompleteTextView
+ val editText = wordLayout.editText as MaterialAutoCompleteTextView
editText.onFocusChangeListener = OnFocusChangeListener { _, focus ->
if (!focus) wordLayout.isErrorEnabled = false
}
@@ -207,7 +207,7 @@ class RecoveryCodeInputFragment : Fragment() {
}
private fun onExistingCodeChecked(verified: Boolean) {
- AlertDialog.Builder(requireContext()).apply {
+ MaterialAlertDialogBuilder(requireContext()).apply {
if (verified) {
setTitle(R.string.recovery_code_verification_ok_title)
setMessage(R.string.recovery_code_verification_ok_message)
@@ -237,7 +237,7 @@ class RecoveryCodeInputFragment : Fragment() {
}
private fun generateNewCode() {
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(R.drawable.ic_warning)
.setTitle(R.string.recovery_code_verification_new_dialog_title)
.setMessage(R.string.recovery_code_verification_new_dialog_message)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt
index 3542235c..1e0b78e1 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt
@@ -16,7 +16,7 @@ import android.net.Uri
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree
import androidx.annotation.CallSuper
-import androidx.appcompat.app.AlertDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.plugins.saf.StorageRootResolver
import com.stevesoltys.seedvault.ui.BackupActivity
@@ -89,7 +89,7 @@ class StorageActivity : BackupActivity() {
private fun onInvalidLocation(errorMsg: String) {
if (viewModel.isRestoreOperation) {
- val dialog = AlertDialog.Builder(this)
+ val dialog = MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.restore_invalid_location_title))
.setMessage(errorMsg)
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionAdapter.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionAdapter.kt
index 91f6551d..4c3c716b 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionAdapter.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionAdapter.kt
@@ -15,9 +15,9 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
-import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.RecyclerView.Adapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.ui.storage.StorageOption.SafOption
import com.stevesoltys.seedvault.ui.storage.StorageOptionAdapter.StorageOptionViewHolder
@@ -91,7 +91,7 @@ internal class StorageOptionAdapter(
}
private fun showWarningDialog(context: Context, item: StorageOption) {
- AlertDialog.Builder(context)
+ MaterialAlertDialogBuilder(context)
.setTitle(R.string.storage_internal_warning_title)
.setMessage(R.string.storage_internal_warning_message)
.setPositiveButton(R.string.storage_internal_warning_choose_other) { dialog, _ ->
diff --git a/app/src/main/res/drawable/ic_app_settings.xml b/app/src/main/res/drawable/ic_app_settings.xml
index be2e27ef..567eb667 100644
--- a/app/src/main/res/drawable/ic_app_settings.xml
+++ b/app/src/main/res/drawable/ic_app_settings.xml
@@ -1,7 +1,7 @@
diff --git a/app/src/main/res/drawable/ic_call.xml b/app/src/main/res/drawable/ic_call.xml
index b67ffd6b..8d9dfc5d 100644
--- a/app/src/main/res/drawable/ic_call.xml
+++ b/app/src/main/res/drawable/ic_call.xml
@@ -6,7 +6,7 @@
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_restore_app_selection.xml b/app/src/main/res/layout/fragment_restore_app_selection.xml
index 36f68bf5..07f215d3 100644
--- a/app/src/main/res/layout/fragment_restore_app_selection.xml
+++ b/app/src/main/res/layout/fragment_restore_app_selection.xml
@@ -16,7 +16,8 @@
+ android:layout_height="wrap_content"
+ android:background="@color/background">
+
diff --git a/app/src/main/res/layout/recovery_code_input.xml b/app/src/main/res/layout/recovery_code_input.xml
index da9adf30..c3ef42e6 100644
--- a/app/src/main/res/layout/recovery_code_input.xml
+++ b/app/src/main/res/layout/recovery_code_input.xml
@@ -23,8 +23,9 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside">
-
-
-
-
-
-
-
-
-
-
-
-
- @android:color/system_accent1_100
-
- @android:color/system_neutral1_900
+ @android:color/system_accent1_100
@android:color/system_neutral1_900
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 30dbd156..77b9a59b 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -6,22 +6,14 @@
- @android:color/system_accent1_600
-
- @android:color/system_neutral1_50
-
- @color/primary
+ @android:color/system_accent1_600
@android:color/system_neutral1_50
-
- @color/primary
-
- @color/primary
-
- @*android:color/error_color_device_default_dark
+
+ #ff7043
- @color/accent
+ @color/accent_primary
#20ffffff
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index f5e767a9..ef5a92b2 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -2,30 +2,19 @@
SPDX-FileCopyrightText: 2020 The Calyx Institute
SPDX-License-Identifier: Apache-2.0
-->
-
+
-
-
-
-
-
@@ -85,7 +74,7 @@
- gravity
-
-
+
+
diff --git a/storage/demo/src/main/java/de/grobox/storagebackuptester/settings/SettingsFragment.kt b/storage/demo/src/main/java/de/grobox/storagebackuptester/settings/SettingsFragment.kt
index 1028fa83..940a8331 100644
--- a/storage/demo/src/main/java/de/grobox/storagebackuptester/settings/SettingsFragment.kt
+++ b/storage/demo/src/main/java/de/grobox/storagebackuptester/settings/SettingsFragment.kt
@@ -19,6 +19,7 @@ import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import de.grobox.storagebackuptester.MainViewModel
import de.grobox.storagebackuptester.R
import de.grobox.storagebackuptester.restore.DemoSnapshotFragment
@@ -133,7 +134,7 @@ class SettingsFragment : BackupContentFragment() {
}
private fun onRestoreClicked() {
- AlertDialog.Builder(requireContext())
+ MaterialAlertDialogBuilder(requireContext())
.setIcon(android.R.drawable.stat_sys_warning)
.setTitle("Warning")
.setMessage("This will override data and should only be used on a clean phone. Not the one you just made the backup on.")
diff --git a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/backup/BackupContentAdapter.kt b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/backup/BackupContentAdapter.kt
index 854df079..50d8fd35 100644
--- a/storage/lib/src/main/java/org/calyxos/backup/storage/ui/backup/BackupContentAdapter.kt
+++ b/storage/lib/src/main/java/org/calyxos/backup/storage/ui/backup/BackupContentAdapter.kt
@@ -12,9 +12,9 @@ import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
-import androidx.appcompat.widget.SwitchCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
+import com.google.android.material.materialswitch.MaterialSwitch
import org.calyxos.backup.storage.R
import org.calyxos.backup.storage.api.EXTERNAL_STORAGE_PROVIDER_AUTHORITY
@@ -65,7 +65,7 @@ internal class BackupContentAdapter(private val listener: ContentClickListener)
}
internal inner class MediaHolder(view: View) : ViewHolder(view) {
- private val switch: SwitchCompat = view.findViewById(R.id.switchView)
+ private val switch: MaterialSwitch = view.findViewById(R.id.switchView)
override fun bind(item: BackupContentItem) {
super.bind(item)
diff --git a/storage/lib/src/main/res/layout/item_media.xml b/storage/lib/src/main/res/layout/item_media.xml
index 7c357472..71db589b 100644
--- a/storage/lib/src/main/res/layout/item_media.xml
+++ b/storage/lib/src/main/res/layout/item_media.xml
@@ -42,7 +42,7 @@
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/content_videos" />
-