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
↓ peach-android-3492ddd7.tar.gzatlas at this save
files changed18 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 −2app/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 {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 ) {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",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 ─────────────────────────────────── */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 Modifierapp/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)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 }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-}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 )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)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 }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,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>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>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>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 }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)