3492ddd79dbd

peach on android is dark-only: light palette, theme-mode branching, the inverted values-night light resources and the theme setting all gone (v2.5.6)

time
2026-07-26 18:46 UTC · 2 months ago
machine
koh2
agent
claude-opus-5
session
android theme and dead settings
parent
49be2ef5e42e
18 files VERSION+1 −1app/build.gradle+2 −2app/src/main/java/com/peachpasswords/MainActivity.kt+9 −31app/src/main/java/com/peachpasswords/ui/settings/CardIcon.kt+1 −6app/src/main/java/com/peachpasswords/ui/settings/SettingsCardBodies.kt+1 −42app/src/main/java/com/peachpasswords/ui/settings/SettingsScreen.kt+1 −5app/src/main/java/com/peachpasswords/ui/settings/SettingsStack.kt+4 −8app/src/main/java/com/peachpasswords/ui/settings/SettingsViewModel.kt+1 −4app/src/main/java/com/peachpasswords/ui/theme/PeachColorsLight.kt+0 −26app/src/main/java/com/peachpasswords/ui/theme/PeachPalette.kt+4 −44app/src/main/java/com/peachpasswords/ui/theme/PeachStackColors.kt+0 −3app/src/main/java/com/peachpasswords/ui/theme/PeachTheme.kt+16 −42app/src/main/java/com/peachpasswords/vault/VaultSettings.kt+0 −2app/src/main/res/values-night/colors.xml+0 −24app/src/main/res/values/colors.xml+0 −12app/src/main/res/values/styles.xml+3 −1app/src/test/java/com/peachpasswords/ui/theme/PeachPaletteTest.kt+6 −33app/src/test/java/com/peachpasswords/ui/vault/ExportRoundTripTest.kt+1 −2
VERSION+1 −1
@@ -1 +1 @@1-2.5.51+2.5.6

view file

app/build.gradle+2 −2
@@ -16,8 +16,8 @@1616         applicationId "com.peachpasswords"1717         minSdk 261818         targetSdk 3519-        versionCode 24010520-        versionName "2.5.5"19+        versionCode 24010620+        versionName "2.5.6"2121 2222         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"2323         vectorDrawables {

view file

app/src/main/java/com/peachpasswords/MainActivity.kt+9 −31
@@ -1,14 +1,12 @@11 package com.peachpasswords22 33 import android.content.Intent4-import android.content.res.Configuration54 import android.graphics.Color as AndroidColor65 import android.graphics.drawable.ColorDrawable76 import android.os.Bundle87 import android.view.WindowManager98 import androidx.activity.compose.setContent109 import androidx.activity.enableEdgeToEdge11-import androidx.compose.foundation.isSystemInDarkTheme1210 import androidx.compose.runtime.SideEffect1311 import androidx.compose.ui.unit.dp1412 import androidx.compose.ui.unit.Density@@ -75,19 +73,9 @@7573         if (intent.getBooleanExtra(EXTRA_OPEN_UPDATE, false)) updates.requestOpen()7674         forwardNewEntryRequest(intent)7775 78-        // Match the splash/window fill to the resolved theme's --bg so launch79-        // never flashes the wrong colour before Compose draws. Resolved from the80-        // persisted setting synchronously (system mode reads the device night mode).81-        val initialTheme = vault.settings.value.theme82-        val initialDark = when (initialTheme) {83-            "light" -> false84-            "system" -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) ==85-                Configuration.UI_MODE_NIGHT_YES86-            else -> true87-        }88-        window.setBackgroundDrawable(89-            ColorDrawable(AndroidColor.parseColor(if (initialDark) "#0C0A06" else "#EFEEE9")),90-        )76+        // Match the window fill to --bg so launch never flashes a lighter colour77+        // before Compose draws, whatever the device's own day/night mode is.78+        window.setBackgroundDrawable(ColorDrawable(AndroidColor.parseColor("#0C0A06")))9179 9280         enableEdgeToEdge()9381 @@ -111,28 +99,18 @@11199 112100         setContent {113101             val settings by vault.settings.collectAsState()114-            val darkTheme = when (settings.theme) {115-                "light" -> false116-                "system" -> isSystemInDarkTheme()117-                else -> true118-            }119-            // enableEdgeToEdge() above only knows the system's own day/night120-            // mode at launch. This app's theme can be forced independent of121-            // that (settings.theme == "dark"/"light"), so on a mismatch —122-            // e.g. system in light mode, app forced dark — the status bar123-            // icons render in the system's assumed color (dark-on-dark) and124-            // become invisible against the app's actual background, reading125-            // as if the app extends behind/under the status bar. Keep the126-            // system bar icon appearance in sync with the resolved theme.102+            // enableEdgeToEdge() picks bar icon appearance from the device's own103+            // day/night mode. Peach is always dark, so on a device in light mode104+            // the icons would render dark-on-dark and vanish against our105+            // background — reading as if the app ran under the status bar.127106             SideEffect {128107                 WindowCompat.getInsetsController(window, window.decorView).apply {129-                    isAppearanceLightStatusBars = !darkTheme130-                    isAppearanceLightNavigationBars = !darkTheme108+                    isAppearanceLightStatusBars = false109+                    isAppearanceLightNavigationBars = false131110                 }132111             }133112             val accent = ACCENT_COLORS[settings.accentColor] ?: DEFAULT_ACCENT134113             PeachTheme(135-                darkTheme = darkTheme,136114                 accent = accent,137115                 reduceMotion = settings.reduceMotion,138116             ) {

view file

app/src/main/java/com/peachpasswords/ui/settings/CardIcon.kt+1 −6
@@ -20,7 +20,7 @@2020  * SVGs (viewBox 0 0 16 16, stroke 1.25, round caps/joins). Stroked in2121  * currentColor so each card tints them with its own foreground.2222  */23-enum class StackIcon { Spark, Shield, Lock, Sync, Sun, Keys, Bubble }23+enum class StackIcon { Spark, Shield, Lock, Sync, Sun, Bubble }2424 2525 private val ICON_PATHS: Map<StackIcon, List<String>> = mapOf(2626     StackIcon.Shield to listOf(@@ -40,11 +40,6 @@4040     StackIcon.Sun to listOf(4141         "M8 5.2a2.8 2.8 0 1 0 0 5.6 2.8 2.8 0 0 0 0-5.6Z",4242         "M8 1.8v1.3M8 12.9v1.3M1.8 8h1.3M12.9 8h1.3M3.6 3.6l.9.9M11.5 11.5l.9.9M12.4 3.6l-.9.9M4.5 11.5l-.9.9",43-    ),44-    StackIcon.Keys to listOf(45-        "M3 5h3a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Z",46-        "M10 7h3a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1Z",47-        "M7 7h2M7 9h2",4843     ),4944     StackIcon.Spark to listOf(5045         "M8 1.8 9.2 6l4.1 1.2-4.1 1.2L8 12.6 6.8 8.4 2.7 7.2 6.8 6 8 1.8Z",

view file

app/src/main/java/com/peachpasswords/ui/settings/SettingsCardBodies.kt+1 −42
@@ -96,7 +96,6 @@9696         CardId.Protection -> ProtectionBody(fg, vm, settings, onNavigate)9797         CardId.Vault -> VaultBody(fg, vm, settings, entriesCount, onNavigate)9898         CardId.Sync -> SyncBody(fg, onNavigate)99-        CardId.Shortcuts -> ShortcutsBody(fg)10099         CardId.Pro -> ProBody(fg, vm)101100         CardId.Feedback -> {102101             // The closest thing Peach has to an About surface, and where the brief@@ -260,16 +259,7 @@260259 @OptIn(ExperimentalLayoutApi::class)261260 @Composable262261 private fun AppearanceBody(fg: Color, vm: SettingsViewModel, s: VaultSettings) {263-    SubLabel("THEME", fg, top = 0.dp)264-    RowLine(fg) {265-        Name("Theme", fg)266-        val (label, next) = when (s.theme) {267-            "dark" -> "Switch to light" to "light"268-            else -> "Switch to dark" to "dark"269-        }270-        SubtleButton(label, fg) { vm.setTheme(next) }271-    }272-    SubLabel("ACCENT", fg)262+    SubLabel("ACCENT", fg, top = 0.dp)273263     FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {274264         ACCENT_COLORS.forEach { (name, color) ->275265             Box(@@ -283,14 +273,6 @@283273             )284274         }285275     }286-    SubLabel("TEXT SIZE", fg)287-    RowLine(fg) {288-        Name("Size", fg)289-        Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {290-            Pill("Default", s.textSize == "medium", fg) { vm.setTextSize("medium") }291-            Pill("Large", s.textSize == "large", fg) { vm.setTextSize("large") }292-        }293-    }294276     SubLabel("MOTION", fg)295277     RowLine(fg) {296278         Name("Reduce motion", fg)@@ -919,29 +901,6 @@919901     SyncStatus.Offline -> "offline"920902     is SyncStatus.Error -> status.message921903     is SyncStatus.LastSynced -> "synced ${syncTimeLabel(status.timestamp)}"922-}923-924-/* ──────────────────────────────  Shortcuts  ──────────────────────────────── */925-926-@Composable927-private fun ShortcutsBody(fg: Color) {928-    val bindings = listOf(929-        "Copy password" to "⌘C", "Copy username" to "⌘⇧C", "Open entry" to "↵",930-        "Edit entry" to "E", "New entry" to "⌘N", "Search" to "/",931-    )932-    SubLabel("KEYBINDINGS", fg, top = 0.dp)933-    Hint("Shortcuts apply when a hardware keyboard is attached. Defaults shown below.", fg)934-    Spacer(Modifier.height(8.dp))935-    bindings.forEach { (label, key) ->936-        RowLine(fg) {937-            Name(label, fg)938-            Box(939-                Modifier.clip(RoundedCornerShape(4.dp)).background(fg.copy(alpha = 0.06f))940-                    .border(1.dp, fg.copy(alpha = 0.32f), RoundedCornerShape(4.dp))941-                    .padding(horizontal = 7.dp, vertical = 2.dp),942-            ) { Text(key, color = fg, fontFamily = PeachType.Mono, fontSize = 10.sp) }943-        }944-    }945904 }946905 947906 /* ────────────────────────────────  Pro  ─────────────────────────────────── */

view file

app/src/main/java/com/peachpasswords/ui/settings/SettingsScreen.kt+1 −5
@@ -189,11 +189,7 @@189189         }190190     }191191 192-    // The Settings stack always renders dark, regardless of the app theme193-    // (spec §5.5/§8): force a dark PeachTheme around it — this also darkens the194-    // ShellBackground base (which keys off MaterialTheme) — while keeping the195-    // user's chosen accent and reduce-motion preference.196-    PeachTheme(darkTheme = true, accent = accent, reduceMotion = reduceMotion) {192+    PeachTheme(accent = accent, reduceMotion = reduceMotion) {197193     ShellBackground {198194         Column(199195             Modifier

view file

app/src/main/java/com/peachpasswords/ui/settings/SettingsStack.kt+4 −8
@@ -3,8 +3,8 @@33 import androidx.compose.ui.graphics.Color44 import com.peachpasswords.ui.theme.PeachStackColors55 6-/** The seven settings categories, in deck order (Pro on top). */7-enum class CardId { Pro, Protection, Vault, Sync, Appearance, Shortcuts, Feedback }6+/** The six settings categories, in deck order (Pro on top). */7+enum class CardId { Pro, Protection, Vault, Sync, Appearance, Feedback }88 99 /**1010  * Static visual identity for one stack card. The [lede] is the only field that@@ -42,15 +42,11 @@4242         PeachStackColors.AppearBgStart, PeachStackColors.AppearBgEnd, PeachStackColors.AppearFg,4343     ),4444     StackCardSpec(45-        CardId.Shortcuts, "VI · KEYS", "Shortcuts", StackIcon.Keys,46-        PeachStackColors.ShortcutBgStart, PeachStackColors.ShortcutBgEnd, PeachStackColors.ShortcutFg,47-    ),48-    StackCardSpec(49-        CardId.Feedback, "VII · ECHO", "Feedback", StackIcon.Bubble,45+        CardId.Feedback, "VI · ECHO", "Feedback", StackIcon.Bubble,5046         PeachStackColors.FeedbackBgStart, PeachStackColors.FeedbackBgEnd, PeachStackColors.FeedbackFg,5147     ),5248 )5349 5450 /** Fan replay order for the Pro celebration — every non-Pro card, then home. */5551 val CELEBRATION_FAN: List<CardId> =56-    listOf(CardId.Protection, CardId.Vault, CardId.Sync, CardId.Appearance, CardId.Shortcuts, CardId.Feedback)52+    listOf(CardId.Protection, CardId.Vault, CardId.Sync, CardId.Appearance, CardId.Feedback)

view file

app/src/main/java/com/peachpasswords/ui/settings/SettingsViewModel.kt+1 −4
@@ -276,9 +276,7 @@276276         viewModelScope.launch { vault.updateSettings(block(vault.settings.value)) }277277     }278278 279-    fun setTheme(theme: String) = mutate { it.copy(theme = theme) }280279     fun setAccent(name: String) = mutate { it.copy(accentColor = name) }281-    fun setTextSize(size: String) = mutate { it.copy(textSize = size) }282280     fun setReduceMotion(on: Boolean) = mutate { it.copy(reduceMotion = on) }283281     fun setBreachMonitoring(on: Boolean) = mutate { it.copy(breachMonitoring = on) }284282     fun setBiometrics(on: Boolean) = mutate { it.copy(biometricsEnabled = on) }@@ -333,8 +331,7 @@333331         CardId.Vault ->334332             "$entriesCount ${if (entriesCount == 1) "entry" else "entries"} · backups, history, cleanup"335333         CardId.Sync -> if (_isPro.value) "your devices, one vault" else "Pro · encrypted device sync"336-        CardId.Appearance -> "${s.theme} · ${s.accentColor} · ${s.textSize}"337-        CardId.Shortcuts -> "bindings · what your fingers know"334+        CardId.Appearance -> "${s.accentColor} · ${if (s.reduceMotion) "still" else "in motion"}"338335         CardId.Feedback -> "tell us what would make it better"339336     }340337 }

view file

app/src/main/java/com/peachpasswords/ui/theme/PeachColorsLight.kt+0 −26
@@ -1,26 +0,0 @@1-package com.peachpasswords.ui.theme2-3-import androidx.compose.ui.graphics.Color4-5-object PeachColorsLight {6-    val Bg = Color(0xFFEFEEE9)7-    val S1 = Color(0xFFF0E9DF)8-    val S2 = Color(0xFFF5EDE2)9-    val S3 = Color(0xFFEEE7DD)10-    val T0 = Color(0xFF1A1208)11-    val T1 = Color(0xFF3D2E18)12-    val T2 = Color(0xFFA8A099)13-    val T3 = Color(0xFFDDD5CB)14-    val T4 = Color(0x0F1A1208)15-    val SurfaceCard = Color(0xFFF0E9DF)16-    val SurfaceElevated = Color(0xF7F5EDE2)17-    val SettingsGroupBg = Color(0xB3F5EDE2)18-19-    val TextLabel = Color(0xFF79766F)20-    val TextLink = Color(0xFFB87155)21-    val TextDim = Color(0xFF9E9890)22-    val BorderSubtle = Color(0xFFE8E2D8)23-    val BorderStrong = Color(0xFFC4BAB0)24-    val BreachBg = Color(0xFFF1E5D9)25-    val BreachText = Color(0xFFDA6931)26-}

view file at the parent

app/src/main/java/com/peachpasswords/ui/theme/PeachPalette.kt+4 −44
@@ -5,13 +5,10 @@55 import androidx.compose.ui.graphics.Color66 77 /**8- * A resolved set of Peach colour tokens for one theme (dark or light).8+ * A resolved set of Peach colour tokens. Peach is dark-only, so [peachDark] is9+ * the sole factory; the indirection survives because it also carries the live10+ * accent, which the [PeachColors] singleton cannot.911  *10- * Composables read tokens from [peachColors] (i.e. [LocalPeachColors].current)11- * instead of the dark-only [PeachColors] object, so a surface re-colours when12- * the active theme changes. Field names mirror [PeachColors] exactly — the call13- * site migration is a pure `PeachColors.X` → `peachColors.X` substitution.14- *1512  * Accent-derived tints (glow, border, dim …) are NOT stored here: they are the1613  * `Color.peachGlow()` family in AccentColors.kt, computed from the current accent1714  * at the call site so they re-derive whenever the user changes their accent.@@ -45,8 +42,6 @@4542     // Shell top fade4643     val ShellTopSolid: Color,4744     val ShellTopFade: Color,48-    // Meta49-    val isDark: Boolean,5045 )5146 5247 /**@@ -61,7 +56,7 @@6156 val peachColors: PeachPalette6257     @Composable get() = LocalPeachColors.current6358 64-/** Dark palette: the canonical tokens from [PeachColors], unchanged. */59+/** The Peach palette: the canonical tokens from [PeachColors] plus the live accent. */6560 fun peachDark(accent: Color = DEFAULT_ACCENT): PeachPalette = PeachPalette(6661     Bg = PeachColors.Bg,6762     S1 = PeachColors.S1,@@ -86,39 +81,4 @@8681     SyncErr = PeachColors.SyncErr,8782     ShellTopSolid = PeachColors.ShellTopSolid,8883     ShellTopFade = PeachColors.ShellTopFade,89-    isDark = true,90-)91-92-/**93- * Light palette. Tokens that exist in [PeachColorsLight] are copied verbatim.94- * Five semantic tokens have no light counterpart in PeachColorsLight; their95- * values are [INFERRED] — darker, fully-opaque variants chosen for contrast on96- * the warm parchment bg (#EFEEE9) rather than the dark singleton's translucent97- * forms, which wash out on a light surface.98- */99-fun peachLight(accent: Color = DEFAULT_ACCENT): PeachPalette = PeachPalette(100-    Bg = PeachColorsLight.Bg,101-    S1 = PeachColorsLight.S1,102-    S2 = PeachColorsLight.S2,103-    S3 = PeachColorsLight.S3,104-    SurfaceCard = PeachColorsLight.SurfaceCard,105-    SurfaceElevated = PeachColorsLight.SurfaceElevated,106-    SettingsGroupBg = PeachColorsLight.SettingsGroupBg,107-    T0 = PeachColorsLight.T0,108-    T1 = PeachColorsLight.T1,109-    T2 = PeachColorsLight.T2,110-    T3 = PeachColorsLight.T3,111-    T4 = PeachColorsLight.T4,112-    Accent = accent,113-    Breach = PeachColorsLight.BreachText,            // light error already defined as BreachText114-    BreachBg = PeachColorsLight.BreachBg,115-    BreachBorder = Color(0x33B83C2E),                // [INFERRED] subtle red hairline on light116-    HealthOk = Color(0xFF3A8A3A),                    // [INFERRED] darker green for light contrast117-    TotpTag = Color(0xFF3A6AAA),                     // [INFERRED] darker blue for light contrast118-    SyncOk = Color(0xFF3A7A3A),                      // [INFERRED] darker green for light contrast119-    SyncBusy = Color(0xFF8A7020),                    // [INFERRED] darker amber for light contrast120-    SyncErr = PeachColorsLight.BreachText,           // mirror Breach, as in the dark palette121-    ShellTopSolid = Color(0xFFFFFFFF),               // [INFERRED] light top fades to white122-    ShellTopFade = Color(0xF2EFEEE9),                // [INFERRED] over the parchment bg123-    isDark = false,12484 )

view file

app/src/main/java/com/peachpasswords/ui/theme/PeachStackColors.kt+0 −3
@@ -21,9 +21,6 @@2121     val AppearBgEnd = Color(0xFF281D10)2222     val AppearFg = Color(0xFFF4E9D2)2323 24-    val ShortcutBgStart = Color(0xFF3A3A45)25-    val ShortcutBgEnd = Color(0xFF1A1A22)26-    val ShortcutFg = Color(0xFFE4E0D6)2724 2825     val ProBgStart = Color(0xFFC2884A)2926     val ProBgEnd = Color(0xFF6E3E1A)

view file

app/src/main/java/com/peachpasswords/ui/theme/PeachTheme.kt+16 −42
@@ -2,7 +2,6 @@22 33 import androidx.compose.material3.MaterialTheme44 import androidx.compose.material3.darkColorScheme5-import androidx.compose.material3.lightColorScheme65 import androidx.compose.runtime.Composable76 import androidx.compose.runtime.CompositionLocalProvider87 import androidx.compose.runtime.compositionLocalOf@@ -19,49 +18,27 @@1918 /** When true, decorative/long-running animations should be skipped or shortened. */2019 val LocalReduceMotion = staticCompositionLocalOf { false }2120 22-/** True when the active scheme is dark — some surfaces tune themselves off this. */23-val LocalPeachDark = staticCompositionLocalOf { true }24-2521 @Composable2622 fun PeachTheme(27-    darkTheme: Boolean = true,2823     accent: Color = DEFAULT_ACCENT,2924     reduceMotion: Boolean = false,3025     content: @Composable () -> Unit,3126 ) {32-    val colors = if (darkTheme) {33-        darkColorScheme(34-            primary = accent,35-            onPrimary = PeachColors.Bg,36-            secondary = PeachColors.SyncBusy,37-            onSecondary = PeachColors.Bg,38-            background = PeachColors.Bg,39-            onBackground = PeachColors.T0,40-            surface = PeachColors.S1,41-            onSurface = PeachColors.T0,42-            surfaceVariant = PeachColors.S2,43-            onSurfaceVariant = PeachColors.T1,44-            outline = PeachColors.T3,45-            error = PeachColors.Breach,46-            onError = PeachColors.Bg,47-        )48-    } else {49-        lightColorScheme(50-            primary = accent,51-            onPrimary = PeachColorsLight.Bg,52-            secondary = PeachColorsLight.TextLink,53-            onSecondary = PeachColorsLight.Bg,54-            background = PeachColorsLight.Bg,55-            onBackground = PeachColorsLight.T0,56-            surface = PeachColorsLight.S1,57-            onSurface = PeachColorsLight.T0,58-            surfaceVariant = PeachColorsLight.S2,59-            onSurfaceVariant = PeachColorsLight.T1,60-            outline = PeachColorsLight.BorderSubtle,61-            error = PeachColorsLight.BreachText,62-            onError = PeachColorsLight.Bg,63-        )64-    }27+    val colors = darkColorScheme(28+        primary = accent,29+        onPrimary = PeachColors.Bg,30+        secondary = PeachColors.SyncBusy,31+        onSecondary = PeachColors.Bg,32+        background = PeachColors.Bg,33+        onBackground = PeachColors.T0,34+        surface = PeachColors.S1,35+        onSurface = PeachColors.T0,36+        surfaceVariant = PeachColors.S2,37+        onSurfaceVariant = PeachColors.T1,38+        outline = PeachColors.T3,39+        error = PeachColors.Breach,40+        onError = PeachColors.Bg,41+    )6542 6643     val typography = androidx.compose.material3.Typography(6744         bodyLarge = TextStyle(@@ -82,13 +59,10 @@8259         ),8360     )8461 85-    val palette = if (darkTheme) peachDark(accent) else peachLight(accent)86-8762     CompositionLocalProvider(8863         LocalPeachAccent provides accent,8964         LocalReduceMotion provides reduceMotion,90-        LocalPeachDark provides darkTheme,91-        LocalPeachColors provides palette,65+        LocalPeachColors provides peachDark(accent),9266     ) {9367         MaterialTheme(colorScheme = colors, typography = typography, content = content)9468     }

view file

app/src/main/java/com/peachpasswords/vault/VaultSettings.kt+0 −2
@@ -4,11 +4,9 @@44 55 @Serializable66 data class VaultSettings(7-    val theme: String = "dark",87     val accentColor: String = "peach",98     val breachMonitoring: Boolean = true,109     val autoLockMinutes: Int? = null,11-    val textSize: String = "medium",1210     val reduceMotion: Boolean = false,1311     val biometricsEnabled: Boolean = false,1412     val trashRetentionDays: Int? = null,

view file

app/src/main/res/values-night/colors.xml+0 −24
@@ -1,24 +0,0 @@1-<?xml version="1.0" encoding="utf-8"?>2-<resources>3-    <color name="bg">#EFEEE9</color>4-    <color name="s1">#F0E9DF</color>5-    <color name="s2">#F5EDE2</color>6-    <color name="s3">#EEE7DD</color>7-    <color name="surface_card">#FFF0E9DF</color>8-    <color name="surface_elevated">#F7F5EDE2</color>9-    <color name="settings_group_bg">#B3F5EDE2</color>10-11-    <color name="t0">#1A1208</color>12-    <color name="t1">#3D2E18</color>13-    <color name="t2">#A8A099</color>14-    <color name="t3">#DDD5CB</color>15-    <color name="t4">#0F1A1208</color>16-17-    <color name="text_label">#79766F</color>18-    <color name="text_link">#B87155</color>19-    <color name="text_dim">#9E9890</color>20-    <color name="border_subtle">#E8E2D8</color>21-    <color name="border_strong">#C4BAB0</color>22-    <color name="breach_bg_light">#F1E5D9</color>23-    <color name="breach_text_light">#DA6931</color>24-</resources>

view file at the parent

app/src/main/res/values/colors.xml+0 −12
@@ -48,10 +48,6 @@4848     <color name="appear_bg_end">#FF281D10</color>4949     <color name="appear_fg">#FFF4E9D2</color>5050 51-    <color name="shortcut_bg_start">#FF3A3A45</color>52-    <color name="shortcut_bg_end">#FF1A1A22</color>53-    <color name="shortcut_fg">#FFE4E0D6</color>54-5551     <color name="pro_bg_start">#FFC2884A</color>5652     <color name="pro_bg_end">#FF6E3E1A</color>5753     <color name="pro_fg">#FFFFF1DD</color>@@ -72,12 +68,4 @@7268     <color name="accent_clay">#FFF08660</color>7369     <color name="accent_slate">#FF80BEDE</color>7470     <color name="accent_stone">#FFC8B8A8</color>75-76-    <color name="text_label">#79766F</color>77-    <color name="text_link">#B87155</color>78-    <color name="text_dim">#9E9890</color>79-    <color name="border_subtle">#E8E2D8</color>80-    <color name="border_strong">#C4BAB0</color>81-    <color name="breach_bg_light">#F1E5D9</color>82-    <color name="breach_text_light">#DA6931</color>8371 </resources>

view file

app/src/main/res/values/styles.xml+3 −1
@@ -6,7 +6,9 @@66         <item name="postSplashScreenTheme">@style/Theme.Peach</item>77     </style>88 9-    <style name="Theme.Peach" parent="Theme.MaterialComponents.DayNight.NoActionBar">9+    <!-- Not DayNight: Peach is dark-only, so the platform theme must not follow10+         the device's day/night mode for the attrs Compose does not override. -->11+    <style name="Theme.Peach" parent="Theme.MaterialComponents.NoActionBar">1012         <item name="android:windowBackground">@color/bg</item>1113         <item name="android:statusBarColor">@android:color/transparent</item>1214         <item name="android:navigationBarColor">@android:color/transparent</item>

view file

app/src/test/java/com/peachpasswords/ui/theme/PeachPaletteTest.kt+6 −33
@@ -2,56 +2,29 @@22 33 import androidx.compose.ui.graphics.Color44 import org.junit.Assert.assertEquals5-import org.junit.Assert.assertFalse6-import org.junit.Assert.assertNotEquals7-import org.junit.Assert.assertTrue85 import org.junit.Test96 107 /**11- * Light-theme regression lock (F brief). The light theme is wired through12- * [peachDark] / [peachLight] + [LocalPeachColors]; these pin the palette factories13- * so a future change can't silently reintroduce the dark-only singleton or turn14- * the warm parchment background into flat white.8+ * Peach is dark-only. These pin the single palette factory so a future change9+ * can't drift the near-black background or drop the live accent back to the10+ * dark-only [PeachColors] singleton.1511  */1612 class PeachPaletteTest {1713 18-    @Test fun dark_palette_is_marked_dark() {19-        assertTrue(peachDark().isDark)20-    }21-22-    @Test fun light_palette_is_marked_light() {23-        assertFalse(peachLight().isDark)24-    }25-26-    @Test fun light_background_is_warm_parchment_not_white() {27-        assertEquals(Color(0xFFEFEEE9), peachLight().Bg)28-        assertNotEquals(Color.White, peachLight().Bg)29-    }30-31-    @Test fun dark_background_is_near_black() {14+    @Test fun background_is_near_black() {3215         assertEquals(Color(0xFF0C0A06), peachDark().Bg)3316     }3417 35-    @Test fun text_inverts_between_themes() {36-        // Dark T0 is light parchment text; light T0 is near-black ink.18+    @Test fun text_is_warm_parchment_on_that_background() {3719         assertEquals(Color(0xFFF0E8D8), peachDark().T0)38-        assertEquals(Color(0xFF1A1208), peachLight().T0)39-        assertNotEquals(peachDark().T0, peachLight().T0)4020     }4121 42-    @Test fun accent_is_carried_into_both_palettes() {22+    @Test fun accent_is_carried_into_the_palette() {4323         val custom = Color(0xFF123456)4424         assertEquals(custom, peachDark(custom).Accent)45-        assertEquals(custom, peachLight(custom).Accent)4625     }4726 4827     @Test fun default_accent_used_when_unspecified() {4928         assertEquals(DEFAULT_ACCENT, peachDark().Accent)50-        assertEquals(DEFAULT_ACCENT, peachLight().Accent)51-    }52-53-    @Test fun light_and_dark_surfaces_differ() {54-        assertNotEquals(peachDark().S1, peachLight().S1)55-        assertNotEquals(peachDark().SurfaceElevated, peachLight().SurfaceElevated)5629     }5730 }

view file

app/src/test/java/com/peachpasswords/ui/vault/ExportRoundTripTest.kt+1 −2
@@ -62,7 +62,7 @@6262     }6363 6464     @Test fun peachscript_round_trips_settings_and_license_metadata() {65-        val settings = VaultSettings(theme = "light", accentColor = "sage", reduceMotion = true)65+        val settings = VaultSettings(accentColor = "sage", reduceMotion = true)6666         val blob = PeachScriptExport.buildEncrypted(6767             entries = listOf(entry()),6868             backupPassword = "backup-pass-12",@@ -75,7 +75,6 @@7575 7676         assertTrue(ok is PeachScriptImport.DecryptResult.Success)7777         ok as PeachScriptImport.DecryptResult.Success78-        assertEquals("light", ok.settings.theme)7978         assertEquals("sage", ok.settings.accentColor)8079         assertTrue(ok.settings.reduceMotion)8180         assertEquals("PPK-test-license", ok.licenseKey)

view file