From e6c3a2e2bdffa2e7464dd8f8510c0691b717b635 Mon Sep 17 00:00:00 2001
From: Philipp Heckel <pheckel@datto.com>
Date: Mon, 7 Feb 2022 18:35:36 -0500
Subject: [PATCH] Styles for dark mode to match guidelines, closes #119

---
 .../io/heckel/ntfy/msg/NotificationService.kt |  3 +-
 .../heckel/ntfy/service/SubscriberService.kt  |  3 +-
 app/src/main/java/io/heckel/ntfy/ui/Colors.kt | 28 ++++++++++++++++
 .../java/io/heckel/ntfy/ui/DetailActivity.kt  | 16 ++++-----
 .../java/io/heckel/ntfy/ui/DetailAdapter.kt   |  3 +-
 .../java/io/heckel/ntfy/ui/MainActivity.kt    | 15 +++++----
 .../java/io/heckel/ntfy/ui/MainAdapter.kt     |  4 +--
 .../java/io/heckel/ntfy/ui/UserFragment.kt    | 14 +++++---
 app/src/main/java/io/heckel/ntfy/util/Util.kt | 11 +++----
 app/src/main/res/layout/activity_main.xml     |  7 ++--
 .../main/res/layout/fragment_add_dialog.xml   | 12 +++++--
 app/src/main/res/values-night/styles.xml      | 33 +++++++++++++++++++
 app/src/main/res/values/colors.xml            | 17 ++++++----
 app/src/main/res/values/strings.xml           |  4 +--
 app/src/main/res/values/styles.xml            | 22 ++++++++++---
 15 files changed, 140 insertions(+), 52 deletions(-)
 create mode 100644 app/src/main/java/io/heckel/ntfy/ui/Colors.kt
 create mode 100644 app/src/main/res/values-night/styles.xml

diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
index b858973..c3b5554 100644
--- a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
+++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
@@ -12,6 +12,7 @@ import io.heckel.ntfy.R
 import io.heckel.ntfy.db.*
 import io.heckel.ntfy.db.Notification
 import io.heckel.ntfy.log.Log
+import io.heckel.ntfy.ui.Colors
 import io.heckel.ntfy.ui.DetailActivity
 import io.heckel.ntfy.ui.MainActivity
 import io.heckel.ntfy.util.*
@@ -52,7 +53,7 @@ class NotificationService(val context: Context) {
         val channelId = toChannelId(notification.priority)
         val builder = NotificationCompat.Builder(context, channelId)
             .setSmallIcon(R.drawable.ic_notification)
-            .setColor(ContextCompat.getColor(context, R.color.primaryColor))
+            .setColor(ContextCompat.getColor(context, Colors.notificationIcon))
             .setContentTitle(title)
             .setOnlyAlertOnce(true) // Do not vibrate or play sound if already showing (updates!)
             .setAutoCancel(true) // Cancel when notification is clicked
diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt
index d12d493..bc03680 100644
--- a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt
+++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt
@@ -19,6 +19,7 @@ import io.heckel.ntfy.db.Subscription
 import io.heckel.ntfy.log.Log
 import io.heckel.ntfy.msg.ApiService
 import io.heckel.ntfy.msg.NotificationDispatcher
+import io.heckel.ntfy.ui.Colors
 import io.heckel.ntfy.ui.MainActivity
 import io.heckel.ntfy.util.topicUrl
 import kotlinx.coroutines.CoroutineScope
@@ -292,7 +293,7 @@ class SubscriberService : Service() {
         }
         return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
             .setSmallIcon(R.drawable.ic_notification_instant)
-            .setColor(ContextCompat.getColor(this, R.color.primaryColor))
+            .setColor(ContextCompat.getColor(this, Colors.notificationIcon))
             .setContentTitle(title)
             .setContentText(text)
             .setContentIntent(pendingIntent)
diff --git a/app/src/main/java/io/heckel/ntfy/ui/Colors.kt b/app/src/main/java/io/heckel/ntfy/ui/Colors.kt
new file mode 100644
index 0000000..c36165b
--- /dev/null
+++ b/app/src/main/java/io/heckel/ntfy/ui/Colors.kt
@@ -0,0 +1,28 @@
+package io.heckel.ntfy.ui
+
+import android.content.Context
+import io.heckel.ntfy.R
+import io.heckel.ntfy.util.isDarkThemeOn
+
+class Colors {
+    companion object {
+        const val refreshProgressIndicator = R.color.teal
+        const val notificationIcon = R.color.teal
+
+        fun itemSelectedBackground(context: Context): Int {
+            return if (isDarkThemeOn(context)) R.color.gray_dark else R.color.gray_light
+        }
+
+        fun statusBarNormal(context: Context): Int {
+            return if (isDarkThemeOn(context)) R.color.black_light else R.color.teal
+        }
+
+        fun statusBarActionMode(context: Context): Int {
+            return if (isDarkThemeOn(context)) R.color.black_light else R.color.teal_dark
+        }
+
+        fun dangerText(context: Context): Int {
+            return if (isDarkThemeOn(context)) R.color.red_light else R.color.red_dark
+        }
+    }
+}
diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
index 756473b..4bb3e54 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
@@ -106,7 +106,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
         // Swipe to refresh
         mainListContainer = findViewById(R.id.detail_notification_list_container)
         mainListContainer.setOnRefreshListener { refresh() }
-        mainListContainer.setColorSchemeResources(R.color.primaryColor)
+        mainListContainer.setColorSchemeResources(Colors.refreshProgressIndicator)
 
         // Update main list based on viewModel (& its datasource/livedata)
         val noEntriesText: View = findViewById(R.id.detail_no_notifications)
@@ -477,7 +477,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
         dialog.setOnShowListener {
             dialog
                 .getButton(AlertDialog.BUTTON_POSITIVE)
-                .setTextColor(ContextCompat.getColor(this, R.color.primaryDangerButtonColor))
+                .setTextAppearance(R.style.DangerText)
         }
         dialog.show()
     }
@@ -512,7 +512,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
         dialog.setOnShowListener {
             dialog
                 .getButton(AlertDialog.BUTTON_POSITIVE)
-                .setTextColor(ContextCompat.getColor(this, R.color.primaryDangerButtonColor))
+                .setTextAppearance(R.style.DangerText)
         }
         dialog.show()
     }
@@ -619,7 +619,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
         dialog.setOnShowListener {
             dialog
                 .getButton(AlertDialog.BUTTON_POSITIVE)
-                .setTextColor(ContextCompat.getColor(this, R.color.primaryDangerButtonColor))
+                .setTextAppearance(R.style.DangerText)
         }
         dialog.show()
     }
@@ -634,8 +634,8 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
         redrawList()
 
         // Fade status bar color
-        val fromColor = ContextCompat.getColor(this, R.color.primaryColor)
-        val toColor = ContextCompat.getColor(this, R.color.primaryDarkColor)
+        val fromColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
+        val toColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
         fadeStatusBarColor(window, fromColor, toColor)
     }
 
@@ -650,8 +650,8 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
         redrawList()
 
         // Fade status bar color
-        val fromColor = ContextCompat.getColor(this, R.color.primaryDarkColor)
-        val toColor = ContextCompat.getColor(this, R.color.primaryColor)
+        val fromColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
+        val toColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
         fadeStatusBarColor(window, fromColor, toColor)
     }
 
diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt
index 1df33ff..0b54915 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/DetailAdapter.kt
@@ -96,8 +96,7 @@ class DetailAdapter(private val activity: Activity, private val repository: Repo
                 tagsView.visibility = View.GONE
             }
             if (selected.contains(notification.id)) {
-                val backgroundColor = if (isDarkThemeOn(context, repository)) R.color.primaryDarkSelectedRowColor else R.color.primaryLightSelectedRowColor
-                itemView.setBackgroundResource(backgroundColor);
+                itemView.setBackgroundResource(Colors.itemSelectedBackground(context))
             }
             renderPriority(context, notification)
             maybeRenderAttachment(context, notification)
diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
index 7e27002..a5155f7 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
@@ -23,6 +23,7 @@ import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.RecyclerView
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 import androidx.work.*
+import com.google.android.material.floatingactionbutton.FloatingActionButton
 import io.heckel.ntfy.BuildConfig
 import io.heckel.ntfy.R
 import io.heckel.ntfy.app.Application
@@ -56,7 +57,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
     private lateinit var mainList: RecyclerView
     private lateinit var mainListContainer: SwipeRefreshLayout
     private lateinit var adapter: MainAdapter
-    private lateinit var fab: View
+    private lateinit var fab: FloatingActionButton
 
     // Other stuff
     private var actionMode: ActionMode? = null
@@ -88,7 +89,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
         // Swipe to refresh
         mainListContainer = findViewById(R.id.main_subscriptions_list_container)
         mainListContainer.setOnRefreshListener { refreshAllSubscriptions() }
-        mainListContainer.setColorSchemeResources(R.color.primaryColor)
+        mainListContainer.setColorSchemeResources(Colors.refreshProgressIndicator)
 
         // Update main list based on viewModel (& its datasource/livedata)
         val noEntries: View = findViewById(R.id.main_no_subscriptions)
@@ -512,7 +513,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
         dialog.setOnShowListener {
             dialog
                 .getButton(AlertDialog.BUTTON_POSITIVE)
-                .setTextColor(ContextCompat.getColor(this, R.color.primaryDangerButtonColor))
+                .setTextAppearance(R.style.DangerText)
         }
         dialog.show()
     }
@@ -539,8 +540,8 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
             })
 
         // Fade status bar color
-        val fromColor = ContextCompat.getColor(this, R.color.primaryColor)
-        val toColor = ContextCompat.getColor(this, R.color.primaryDarkColor)
+        val fromColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
+        val toColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
         fadeStatusBarColor(window, fromColor, toColor)
     }
 
@@ -568,8 +569,8 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
             })
 
         // Fade status bar color
-        val fromColor = ContextCompat.getColor(this, R.color.primaryDarkColor)
-        val toColor = ContextCompat.getColor(this, R.color.primaryColor)
+        val fromColor = ContextCompat.getColor(this, Colors.statusBarActionMode(this))
+        val toColor = ContextCompat.getColor(this, Colors.statusBarNormal(this))
         fadeStatusBarColor(window, fromColor, toColor)
     }
 
diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt
index 5e69616..1ce5c33 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt
@@ -5,7 +5,6 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.TextView
-import androidx.appcompat.app.AppCompatDelegate
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
@@ -102,8 +101,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs
             itemView.setOnClickListener { onClick(subscription) }
             itemView.setOnLongClickListener { onLongClick(subscription); true }
             if (selected.contains(subscription.id)) {
-                val backgroundColor = if (isDarkThemeOn(context, repository)) R.color.primaryDarkSelectedRowColor else R.color.primaryLightSelectedRowColor
-                itemView.setBackgroundResource(backgroundColor)
+                itemView.setBackgroundResource(Colors.itemSelectedBackground(context))
             }
         }
     }
diff --git a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt
index 1e17806..4f4daed 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt
@@ -3,6 +3,7 @@ package io.heckel.ntfy.ui
 import android.app.AlertDialog
 import android.app.Dialog
 import android.content.Context
+import android.os.Build
 import android.os.Bundle
 import android.text.Editable
 import android.text.TextWatcher
@@ -15,7 +16,6 @@ import androidx.fragment.app.DialogFragment
 import com.google.android.material.textfield.TextInputEditText
 import io.heckel.ntfy.R
 import io.heckel.ntfy.db.User
-import kotlin.random.Random
 
 class UserFragment : DialogFragment() {
     private var user: User? = null
@@ -97,9 +97,15 @@ class UserFragment : DialogFragment() {
 
             // Delete button should be red
             if (user != null) {
-                dialog
-                    .getButton(AlertDialog.BUTTON_NEUTRAL)
-                    .setTextColor(ContextCompat.getColor(requireContext(), R.color.primaryDangerButtonColor))
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                    dialog
+                        .getButton(AlertDialog.BUTTON_NEUTRAL)
+                        .setTextAppearance(R.style.DangerText)
+                } else {
+                    dialog
+                        .getButton(AlertDialog.BUTTON_NEUTRAL)
+                        .setTextColor(ContextCompat.getColor(requireContext(), Colors.dangerText(requireContext())))
+                }
             }
 
             // Validate input when typing
diff --git a/app/src/main/java/io/heckel/ntfy/util/Util.kt b/app/src/main/java/io/heckel/ntfy/util/Util.kt
index 5736476..4220041 100644
--- a/app/src/main/java/io/heckel/ntfy/util/Util.kt
+++ b/app/src/main/java/io/heckel/ntfy/util/Util.kt
@@ -3,17 +3,14 @@ package io.heckel.ntfy.util
 import android.animation.ArgbEvaluator
 import android.animation.ValueAnimator
 import android.content.Context
-import android.content.Intent
 import android.content.res.Configuration
 import android.content.res.Configuration.UI_MODE_NIGHT_YES
 import android.net.Uri
 import android.os.Build
 import android.os.PowerManager
 import android.provider.OpenableColumns
-import android.provider.Settings
 import android.view.Window
 import androidx.appcompat.app.AppCompatDelegate
-import io.heckel.ntfy.R
 import io.heckel.ntfy.db.Notification
 import io.heckel.ntfy.db.Repository
 import io.heckel.ntfy.db.Subscription
@@ -206,17 +203,17 @@ fun isIgnoringBatteryOptimizations(context: Context): Boolean {
 }
 
 // Returns true if dark mode is on, see https://stackoverflow.com/a/60761189/1440785
-fun Context.isDarkThemeOn(): Boolean {
+fun Context.systemDarkThemeOn(): Boolean {
     return resources.configuration.uiMode and
             Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
 }
 
-fun isDarkThemeOn(context: Context, repository: Repository): Boolean {
-    val darkMode = repository.getDarkMode()
+fun isDarkThemeOn(context: Context): Boolean {
+    val darkMode = Repository.getInstance(context).getDarkMode()
     if (darkMode == AppCompatDelegate.MODE_NIGHT_YES) {
         return true
     }
-    if (darkMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && context.isDarkThemeOn()) {
+    if (darkMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && context.systemDarkThemeOn()) {
         return true
     }
     return false
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 06d345a..e825332 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -139,11 +139,12 @@
             android:id="@+id/fab"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_margin="16dp"
+            android:layout_margin="24dp"
             android:contentDescription="@string/main_add_button_description"
             android:src="@drawable/ic_add_black_24dp"
-            app:tint="@color/primaryLightTextColor"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent" app:backgroundTint="@color/primaryColor"/>
+            app:layout_constraintEnd_toEndOf="parent"
+            style="@style/FloatingActionButton"
+    />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_add_dialog.xml b/app/src/main/res/layout/fragment_add_dialog.xml
index 29da8cd..7ee8a8c 100644
--- a/app/src/main/res/layout/fragment_add_dialog.xml
+++ b/app/src/main/res/layout/fragment_add_dialog.xml
@@ -139,7 +139,12 @@
                 android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_error_text"
                 android:paddingStart="4dp"
                 app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_instant_delivery_description" android:paddingEnd="4dp" android:textColor="@color/primaryDangerButtonColor" app:layout_constraintStart_toEndOf="@id/add_dialog_subscribe_error_text_image" android:layout_marginTop="5dp" tools:visibility="gone"/>
+                app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_instant_delivery_description"
+                android:paddingEnd="4dp"
+                android:textAppearance="@style/DangerText"
+                app:layout_constraintStart_toEndOf="@id/add_dialog_subscribe_error_text_image"
+                android:layout_marginTop="5dp"
+                tools:visibility="gone"/>
     </androidx.constraintlayout.widget.ConstraintLayout>
     </ScrollView>
     <ScrollView
@@ -197,7 +202,10 @@
                 android:layout_height="wrap_content" android:id="@+id/add_dialog_login_error_text"
                 android:paddingStart="4dp"
                 app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintTop_toBottomOf="@id/add_dialog_login_password" android:paddingEnd="4dp" android:textColor="@color/primaryDangerButtonColor" app:layout_constraintStart_toEndOf="@id/add_dialog_login_error_text_image"/>
+                app:layout_constraintTop_toBottomOf="@id/add_dialog_login_password"
+                android:paddingEnd="4dp"
+                android:textAppearance="@style/DangerText"
+                app:layout_constraintStart_toEndOf="@id/add_dialog_login_error_text_image"/>
         <ProgressBar
                 style="?android:attr/progressBarStyle"
                 android:layout_width="25dp"
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..2a7f99c
--- /dev/null
+++ b/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,33 @@
+<resources>
+    <!--
+        This file contains only overrides for the dark theme.
+        Also see "ui/Colors.kt" for colors that have to be defined in code.
+
+        Resources:
+        - https://material.io/design/color/dark-theme.html
+        - https://material.io/develop/android/theming/dark
+        - https://developer.android.com/codelabs/basic-android-kotlin-training-change-app-theme#4
+        - https://developer.android.com/guide/topics/ui/look-and-feel/themes
+   -->
+
+    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <item name="colorPrimary">@color/teal_light</item>
+        <item name="colorAccent">@color/teal_light</item> <!-- checkboxes, text fields -->
+        <item name="android:colorBackground">@color/black_light</item> <!-- background -->
+        <item name="android:statusBarColor">@color/black_light</item>
+        <item name="actionModeBackground">@color/black_light</item>
+
+        <!-- Action bar background & text color -->
+        <item name="colorSurface">@color/gray_dark</item>
+        <item name="colorOnSurface">@color/white</item>
+    </style>
+
+    <style name="DangerText" parent="@android:style/TextAppearance">
+        <item name="android:textColor">@color/red_light</item>
+    </style>
+
+    <style name="FloatingActionButton" parent="@style/Widget.MaterialComponents.FloatingActionButton">
+        <item name="tint">@color/black_light</item>
+        <item name="backgroundTint">@color/teal_light</item>
+    </style>
+</resources>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 6ba7967..a03ba0e 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,13 +1,16 @@
 <!--?xml version="1.0" encoding="UTF-8"?-->
 <resources>
-    <color name="primaryColor">#338574</color>
-    <color name="primaryDangerButtonColor">#C30000</color>
+  <color name="black">#ff000000</color>
+  <color name="black_light">#121212</color> <!-- Main dark mode surface color, as per style guide -->
+  <color name="white">#ffffffff</color>
 
-    <color name="primaryLightColor">#338574</color>
-    <color name="primaryLightTextColor">#FFFFFF</color>
-    <color name="primaryLightSelectedRowColor">#EEEEEE</color>
+  <color name="teal">#338574</color> <!-- Primary color (light mode) -->
+  <color name="teal_light">#65b5a3</color> <!-- Primary color (dark mode) -->
+  <color name="teal_dark">#2a6e60</color> <!-- Action bar background in action mode (light mode) -->
+  <color name="red_light">#fe4d2e</color> <!-- Danger text (dark mode) -->
+  <color name="red_dark">#c30000</color> <!-- Danger text (light mode) -->
 
-    <color name="primaryDarkColor">#2A6E60</color>
-    <color name="primaryDarkSelectedRowColor">#444444</color>
+  <color name="gray_light">#eeeeee</color> <!-- Light theme item selection -->
+  <color name="gray_dark">#282828</color> <!-- Dark mode action bar & item selection -->
 </resources>
 
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8118894..9b6b231 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -188,8 +188,8 @@
     <string name="notification_dialog_cancel">Cancel</string>
     <string name="notification_dialog_save">Save</string>
     <string name="notification_dialog_enabled_toast_message">Notifications re-enabled</string>
-    <string name="notification_dialog_muted_forever_toast_message">Notifications are now paused</string>
-    <string name="notification_dialog_muted_until_toast_message">Notifications are paused until %1$s</string>
+    <string name="notification_dialog_muted_forever_toast_message">Notifications paused</string>
+    <string name="notification_dialog_muted_until_toast_message">Notifications paused until %1$s</string>
     <string name="notification_dialog_show_all">Show all notifications</string>
     <string name="notification_dialog_30min">30 minutes</string>
     <string name="notification_dialog_1h">1 hour</string>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 1a3091e..ff2c19f 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,10 +1,22 @@
 <resources>
-    <!-- DayNight mode for easy dark mode, see https://material.io/develop/android/theming/dark -->
+    <!-- Main app theme; dark theme styles see values-night/styles.xml -->
     <style name="AppTheme"  parent="Theme.MaterialComponents.DayNight.DarkActionBar">
-        <item name="colorPrimary">@color/primaryColor</item>
-        <item name="colorAccent">@color/primaryLightColor</item>
-        <item name="android:statusBarColor">@color/primaryColor</item>
-        <item name="actionModeBackground">@color/primaryDarkColor</item>
+        <item name="colorPrimary">@color/teal</item>
+        <item name="colorAccent">@color/teal</item> <!-- checkboxes, text fields -->
+        <item name="android:colorBackground">@color/white</item> <!-- background -->
+        <item name="android:statusBarColor">@color/teal</item>
+        <item name="actionModeBackground">@color/teal_dark</item>
+    </style>
+
+    <!-- Danger buttons & text -->
+    <style name="DangerText" parent="@android:style/TextAppearance">
+        <item name="android:textColor">@color/red_dark</item>
+    </style>
+
+    <!-- Floating action button -->
+    <style name="FloatingActionButton" parent="@style/Widget.MaterialComponents.FloatingActionButton">
+        <item name="tint">@color/white</item>
+        <item name="backgroundTint">@color/teal</item>
     </style>
 
     <!-- Rounded corners in images, see https://stackoverflow.com/a/61960983/1440785 -->