0d70ba6993db

style: Unify non-settings surfaces (v2.14.26)

time
2026-08-14 18:03 UTC · 2 months ago
machine
koh2
agent
gpt-5.6-sol
session
non-settings visual consistency
parent
96f3e805402f
15 files VERSION+1 −1app/src/main/java/com/peachpasswords/ui/codex/CodexGenerateScreen.kt+2 −15app/src/main/java/com/peachpasswords/ui/components/PeachSectionHeader.kt+52 −0app/src/main/java/com/peachpasswords/ui/recovery/RecoveryWordEntryScreen.kt+2 −15app/src/main/java/com/peachpasswords/ui/updates/UpdateScreen.kt+2 −15app/src/main/java/com/peachpasswords/ui/vault/EntryDeckChrome.kt+12 −3app/src/main/java/com/peachpasswords/ui/vault/EntryEditScreen.kt+30 −13app/src/main/java/com/peachpasswords/ui/vault/ExportScreen.kt+4 −16app/src/main/java/com/peachpasswords/ui/vault/IdentitySuggestDropdown.kt+13 −7app/src/main/java/com/peachpasswords/ui/vault/ImportScreen.kt+9 −19app/src/main/java/com/peachpasswords/ui/vault/NotesModeScreen.kt+21 −5app/src/main/java/com/peachpasswords/ui/vault/PeachField.kt+32 −4app/src/main/java/com/peachpasswords/ui/vault/TrashScreen.kt+4 −14app/src/main/java/com/peachpasswords/ui/vault/VaultHealthScreen.kt+4 −11app/src/main/java/com/peachpasswords/ui/vault/VaultListScreen.kt+5 −1
VERSION+1 −1
@@ -1 +1 @@1-2.14.251+2.14.26

view file

app/src/main/java/com/peachpasswords/ui/codex/CodexGenerateScreen.kt+2 −15
@@ -36,7 +36,7 @@3636 import com.peachpasswords.codex.CodexStep3737 import com.peachpasswords.ui.components.PeachEmptyOrEndState3838 import com.peachpasswords.ui.components.PeachField39-import com.peachpasswords.ui.components.PeachTopBar39+import com.peachpasswords.ui.components.PeachSectionHeader4040 import com.peachpasswords.ui.components.SecureFlagEffect4141 import com.peachpasswords.ui.theme.LocalPeachAccent4242 import com.peachpasswords.ui.theme.PeachSpacing@@ -190,20 +190,7 @@190190 191191 @Composable192192 internal fun CodexTopBar(title: String, onBack: () -> Unit) {193-    PeachTopBar(194-        title = title,195-        leading = {196-            Text(197-                "‹",198-                color = peachColors.T1,199-                fontSize = 26.sp,200-                modifier = Modifier201-                    .clip(RoundedCornerShape(999.dp))202-                    .clickable(onClick = onBack)203-                    .padding(horizontal = PeachSpacing.sm),204-            )205-        },206-    )193+    PeachSectionHeader(section = title, onHome = onBack)207194 }208195 209196 @Composable

view file

app/src/main/java/com/peachpasswords/ui/components/PeachSectionHeader.kt+52 −0
@@ -0,0 +1,52 @@1+package com.peachpasswords.ui.components2+3+import androidx.compose.foundation.clickable4+import androidx.compose.foundation.layout.Arrangement5+import androidx.compose.foundation.layout.Box6+import androidx.compose.foundation.layout.Row7+import androidx.compose.foundation.layout.RowScope8+import androidx.compose.foundation.layout.Spacer9+import androidx.compose.foundation.layout.fillMaxWidth10+import androidx.compose.foundation.layout.height11+import androidx.compose.foundation.layout.width12+import androidx.compose.material3.Text13+import androidx.compose.runtime.Composable14+import androidx.compose.ui.Alignment15+import androidx.compose.ui.Modifier16+import androidx.compose.ui.unit.dp17+import androidx.compose.ui.unit.em18+import com.peachpasswords.ui.theme.PeachSpacing19+import com.peachpasswords.ui.theme.PeachType20+import com.peachpasswords.ui.theme.peachColors21+22+/** Quiet branded section identity used instead of the retired contained top bar. */23+@Composable24+fun PeachSectionHeader(25+    section: String,26+    onHome: () -> Unit,27+    modifier: Modifier = Modifier,28+    actions: (@Composable RowScope.() -> Unit)? = null,29+) {30+    Row(31+        modifier.fillMaxWidth().height(64.dp),32+        verticalAlignment = Alignment.CenterVertically,33+    ) {34+        Box(Modifier.clickable(onClickLabel = "Back to vault", onClick = onHome)) {35+            PeachWordmark()36+        }37+        Spacer(Modifier.width(PeachSpacing.md))38+        Text(39+            section.uppercase(),40+            color = peachColors.T2,41+            style = PeachType.labelMono.copy(letterSpacing = 0.08.em),42+        )43+        Spacer(Modifier.weight(1f))44+        if (actions != null) {45+            Row(46+                horizontalArrangement = Arrangement.spacedBy(PeachSpacing.xs),47+                verticalAlignment = Alignment.CenterVertically,48+                content = actions,49+            )50+        }51+    }52+}

view file

app/src/main/java/com/peachpasswords/ui/recovery/RecoveryWordEntryScreen.kt+2 −15
@@ -58,7 +58,7 @@5858 import com.peachpasswords.ui.components.SecureFlagEffect5959 import com.peachpasswords.ui.components.PeachEmptyOrEndState6060 import com.peachpasswords.ui.components.PeachField61-import com.peachpasswords.ui.components.PeachTopBar61+import com.peachpasswords.ui.components.PeachSectionHeader6262 import com.peachpasswords.ui.lock.MIN_PASSWORD_LENGTH6363 import com.peachpasswords.ui.security.StrengthBar6464 import com.peachpasswords.ui.security.scorePassword@@ -189,20 +189,7 @@189189                 .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md)190190                 .verticalScroll(rememberScrollState()),191191         ) {192-            PeachTopBar(193-                title = "Recovery",194-                leading = {195-                    Icon(196-                        Icons.AutoMirrored.Rounded.ArrowBack,197-                        contentDescription = "back",198-                        tint = peachColors.T0,199-                        modifier = Modifier200-                            .size(22.dp)201-                            .clip(RoundedCornerShape(PeachSpacing.sm))202-                            .clickable(onClick = onBack),203-                    )204-                },205-            )192+            PeachSectionHeader(section = "recovery", onHome = onBack)206193             Spacer(Modifier.height(PeachSpacing.lg))207194             when (state.step) {208195                 RecoveryStep.WORDS -> WordStep(state, vm, onBack)

view file

app/src/main/java/com/peachpasswords/ui/updates/UpdateScreen.kt+2 −15
@@ -44,7 +44,7 @@4444 import androidx.hilt.navigation.compose.hiltViewModel4545 import androidx.lifecycle.ViewModel4646 import androidx.lifecycle.viewModelScope47-import com.peachpasswords.ui.components.PeachTopBar47+import com.peachpasswords.ui.components.PeachSectionHeader4848 import com.peachpasswords.ui.theme.LocalPeachAccent4949 import com.peachpasswords.ui.theme.PeachSpacing5050 import com.peachpasswords.ui.theme.PeachType@@ -220,20 +220,7 @@220220                 .systemBarsPadding()221221                 .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),222222         ) {223-            PeachTopBar(224-                title = "Update",225-                leading = {226-                    Icon(227-                        Icons.AutoMirrored.Rounded.ArrowBack,228-                        contentDescription = "back",229-                        tint = peachColors.T0,230-                        modifier = Modifier231-                            .size(22.dp)232-                            .clip(RoundedCornerShape(PeachSpacing.sm))233-                            .clickable(onClick = onBack),234-                    )235-                },236-            )223+            PeachSectionHeader(section = "update", onHome = onBack)237224             Spacer(Modifier.height(PeachSpacing.lg))238225 239226             Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {

view file

app/src/main/java/com/peachpasswords/ui/vault/EntryDeckChrome.kt+12 −3
@@ -86,7 +86,10 @@8686         verticalAlignment = Alignment.CenterVertically,8787     ) {8888         DeckAction(Icons.Rounded.Search, "search", accent, onSearch)89-        DeckAction(Icons.Rounded.Add, "new", peachColors.T0, onAdd)89+        // Material's Add path has substantially less visual mass than the90+        // outlined glyphs beside it, so it needs a larger box to read as the91+        // same optical size.92+        DeckAction(Icons.Rounded.Add, "new", peachColors.T0, onAdd, iconSize = 28.dp)9093         DeckAction(Icons.Outlined.Description, "Notes", if (notesSelected) accent else peachColors.T0, onNotes)9194         DeckAction(Icons.Outlined.Settings, "settings", peachColors.T0, onSettings)9295         DeckAction(Icons.Outlined.Lock, "Lock vault", accent, onLock)@@ -94,11 +97,17 @@9497 }9598 9699 @Composable97-private fun DeckAction(icon: ImageVector, label: String, tint: Color, onClick: () -> Unit) {100+private fun DeckAction(101+    icon: ImageVector,102+    label: String,103+    tint: Color,104+    onClick: () -> Unit,105+    iconSize: androidx.compose.ui.unit.Dp = 22.dp,106+) {98107     Box(99108         Modifier.size(48.dp).clickable(onClick = onClick),100109         contentAlignment = Alignment.Center,101110     ) {102-        Icon(icon, contentDescription = label, tint = tint, modifier = Modifier.size(22.dp))111+        Icon(icon, contentDescription = label, tint = tint, modifier = Modifier.size(iconSize))103112     }104113 }

view file

app/src/main/java/com/peachpasswords/ui/vault/EntryEditScreen.kt+30 −13
@@ -127,23 +127,34 @@127127 128128                     Field("title", f.title, vm::setTitle)129129                     if (f.type == "login") {130-                        Field("url", f.url, vm::setUrl)130+                        PeachFieldStack {131+                            Field("url", f.url, vm::setUrl, joined = true, divider = true)132+                            IdentitySuggestField(133+                                "username", f.username, usernameSuggestions, vm::setUsername,134+                                joined = true,135+                                divider = true,136+                            )137+                            IdentitySuggestField(138+                                "email", f.email, emailSuggestions, vm::setEmail,139+                                joined = true,140+                                divider = true,141+                            )142+                            PasswordField(143+                                value = f.password,144+                                show = f.showPassword,145+                                generatorOpen = f.generatorOpen,146+                                onChange = vm::setPassword,147+                                onToggleShow = vm::toggleShowPassword,148+                                onToggleGenerator = vm::toggleGenerator,149+                                joined = true,150+                            )151+                        }131152                         AdditionalUrlsEditor(132153                             urls = f.additionalUrls,133154                             onChange = vm::setAdditionalUrl,134155                             onAdd = vm::addAdditionalUrl,135156                             onRemove = vm::removeAdditionalUrl,136157                         )137-                        IdentitySuggestField("username", f.username, usernameSuggestions, vm::setUsername)138-                        IdentitySuggestField("email", f.email, emailSuggestions, vm::setEmail)139-                        PasswordField(140-                            value = f.password,141-                            show = f.showPassword,142-                            generatorOpen = f.generatorOpen,143-                            onChange = vm::setPassword,144-                            onToggleShow = vm::toggleShowPassword,145-                            onToggleGenerator = vm::toggleGenerator,146-                        )147158                         GeneratorDrawer(148159                             open = f.generatorOpen,149160                             length = f.genLength,@@ -235,7 +246,7 @@235246         Surface(236247             modifier = Modifier.weight(1f).clickable(onClick = onCancel),237248             color = peachColors.S1,238-            shape = RoundedCornerShape(12.dp),249+            shape = RoundedCornerShape(PeachRadius.StackCard),239250             border = BorderStroke(1.dp, peachColors.T3),240251         ) {241252             Text("cancel", color = peachColors.T1, style = PeachType.bodyMono, modifier = Modifier.padding(18.dp), textAlign = TextAlign.Center)@@ -243,7 +254,7 @@243254         Surface(244255             modifier = Modifier.weight(1f).clickable(enabled = canSave, onClick = onSave),245256             color = if (canSave) accent else peachColors.S2,246-            shape = RoundedCornerShape(12.dp),257+            shape = RoundedCornerShape(PeachRadius.StackCard),247258         ) {248259             Text(saveLabel, color = if (canSave) peachColors.Bg else peachColors.T2, style = PeachType.bodyMono, modifier = Modifier.padding(18.dp), textAlign = TextAlign.Center)249260         }@@ -324,6 +335,8 @@324335     singleLine: Boolean = true,325336     transformation: VisualTransformation = VisualTransformation.None,326337     trailing: (@Composable () -> Unit)? = null,338+    joined: Boolean = false,339+    divider: Boolean = false,327340 ) {328341     PeachField(329342         label = label,@@ -333,6 +346,8 @@333346         mono = true,334347         visualTransformation = transformation,335348         trailing = trailing,349+        joined = joined,350+        divider = divider,336351     )337352 }338353 @@ -344,12 +359,14 @@344359     onChange: (String) -> Unit,345360     onToggleShow: () -> Unit,346361     onToggleGenerator: () -> Unit,362+    joined: Boolean = false,347363 ) {348364     Field(349365         label = "password",350366         value = value,351367         onChange = onChange,352368         transformation = if (show) VisualTransformation.None else PasswordVisualTransformation(),369+        joined = joined,353370         trailing = {354371             Text(if (show) "hide" else "show", color = LocalPeachAccent.current,355372                 fontFamily = PeachType.Mono, fontSize = 9.sp,

view file

app/src/main/java/com/peachpasswords/ui/vault/ExportScreen.kt+4 −16
@@ -49,7 +49,7 @@4949 import com.peachpasswords.license.LicenseRepository5050 import com.peachpasswords.ui.components.PeachEmptyOrEndState5151 import com.peachpasswords.ui.components.PeachField as DesignPeachField52-import com.peachpasswords.ui.components.PeachTopBar52+import com.peachpasswords.ui.components.PeachSectionHeader5353 import com.peachpasswords.ui.components.SecureFlagEffect5454 import com.peachpasswords.ui.theme.LocalPeachAccent5555 import com.peachpasswords.ui.theme.PeachSpacing@@ -165,21 +165,9 @@165165                 .systemBarsPadding()166166                 .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),167167         ) {168-            PeachTopBar(169-                title = "Export",170-                leading = {171-                    Icon(172-                        Icons.AutoMirrored.Rounded.ArrowBack,173-                        contentDescription = "back",174-                        tint = peachColors.T0,175-                        modifier = Modifier176-                            .size(22.dp)177-                            .clip(RoundedCornerShape(PeachSpacing.sm))178-                            .clickable {179-                                if (route != ExportRoute.CHOOSE) route = ExportRoute.CHOOSE else onBack()180-                            },181-                    )182-                },168+            PeachSectionHeader(169+                section = "export",170+                onHome = { if (route != ExportRoute.CHOOSE) route = ExportRoute.CHOOSE else onBack() },183171             )184172 185173             Spacer(Modifier.size(PeachSpacing.lg))

view file

app/src/main/java/com/peachpasswords/ui/vault/IdentitySuggestDropdown.kt+13 −7
@@ -97,18 +97,23 @@9797     value: String,9898     suggestions: List<String>,9999     onChange: (String) -> Unit,100+    joined: Boolean = false,101+    divider: Boolean = false,100102 ) {101103     val accent = LocalPeachAccent.current102104     var focused by remember { mutableStateOf(false) }103105 104-    Column(Modifier.fillMaxWidth().padding(bottom = 14.dp)) {105-        Text(label.uppercase(), color = peachColors.T1, fontFamily = PeachType.Mono, fontSize = 8.sp)106+    Column(107+        Modifier.fillMaxWidth()108+            .then(if (joined) Modifier else Modifier.padding(bottom = 14.dp))109+            .then(110+                if (joined) Modifier.padding(horizontal = 18.dp, vertical = 14.dp)111+                else Modifier.border(1.dp, peachColors.T3, RoundedCornerShape(16.dp)).padding(horizontal = 18.dp, vertical = 14.dp),112+            ),113+    ) {114+        Text(label.uppercase(), color = peachColors.T2, fontFamily = PeachType.Mono, fontSize = 9.sp)106115         Spacer(Modifier.height(6.dp))107-        Box(108-            Modifier.fillMaxWidth()109-                .border(1.dp, peachColors.T3, RoundedCornerShape(10.dp))110-                .padding(horizontal = 12.dp, vertical = 12.dp),111-        ) {116+        Box(Modifier.fillMaxWidth()) {112117             BasicTextField(113118                 value = value,114119                 onValueChange = onChange,@@ -130,4 +135,5 @@130135             onDismiss = { focused = false },131136         )132137     }138+    if (joined && divider) Box(Modifier.fillMaxWidth().height(1.dp).background(peachColors.T3))133139 }

view file

app/src/main/java/com/peachpasswords/ui/vault/ImportScreen.kt+9 −19
@@ -50,7 +50,7 @@5050 import androidx.lifecycle.viewModelScope5151 import com.peachpasswords.ui.components.PeachEmptyOrEndState5252 import com.peachpasswords.ui.components.PeachField as DesignPeachField53-import com.peachpasswords.ui.components.PeachTopBar53+import com.peachpasswords.ui.components.PeachSectionHeader5454 import com.peachpasswords.ui.lock.canSubmitCreateVault5555 import com.peachpasswords.ui.security.scorePassword5656 import com.peachpasswords.ui.security.strengthColor@@ -410,24 +410,14 @@410410                 .systemBarsPadding()411411                 .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),412412         ) {413-            PeachTopBar(414-                title = "Import",415-                leading = {416-                    Icon(417-                        Icons.AutoMirrored.Rounded.ArrowBack,418-                        contentDescription = "back",419-                        tint = peachColors.T0,420-                        modifier = Modifier421-                            .size(22.dp)422-                            .clip(RoundedCornerShape(PeachSpacing.sm))423-                            .clickable {424-                                when {425-                                    state !is ImportUiState.Idle -> vm.back(onBack)426-                                    route != ImportRoute.CHOOSE -> route = ImportRoute.CHOOSE427-                                    else -> onBack()428-                                }429-                            },430-                    )413+            PeachSectionHeader(414+                section = "import",415+                onHome = {416+                    when {417+                        state !is ImportUiState.Idle -> vm.back(onBack)418+                        route != ImportRoute.CHOOSE -> route = ImportRoute.CHOOSE419+                        else -> onBack()420+                    }431421                 },432422             )433423 

view file

app/src/main/java/com/peachpasswords/ui/vault/NotesModeScreen.kt+21 −5
@@ -4,6 +4,7 @@44 import androidx.compose.animation.core.animateFloatAsState55 import androidx.compose.animation.core.tween66 import androidx.compose.foundation.background7+import androidx.compose.foundation.border78 import androidx.compose.foundation.clickable89 import androidx.compose.foundation.combinedClickable910 import androidx.compose.foundation.ExperimentalFoundationApi@@ -60,6 +61,7 @@6061 import com.peachpasswords.ui.PeachNav6162 import com.peachpasswords.ui.components.SecureFlagEffect6263 import com.peachpasswords.ui.theme.PeachSpacing64+import com.peachpasswords.ui.theme.PeachRadius6365 import com.peachpasswords.vault.VaultEntry6466 import com.peachpasswords.ui.theme.LocalPeachAccent6567 import com.peachpasswords.ui.theme.peachColors@@ -192,7 +194,12 @@192194             // as the browser's own tags, so formatting survives a phone edit.193195             if (editing) {194196                 Row(195-                    Modifier.fillMaxWidth().padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.sm),197+                    Modifier.fillMaxWidth()198+                        .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.sm)199+                        .clip(RoundedCornerShape(PeachRadius.Pill))200+                        .background(peachColors.S1)201+                        .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.Pill))202+                        .padding(PeachSpacing.xs),196203                     horizontalArrangement = Arrangement.spacedBy(PeachSpacing.xs),197204                     verticalAlignment = Alignment.CenterVertically,198205                 ) {@@ -212,7 +219,14 @@212219             }213220 214221             // Content area.215-            Box(Modifier.weight(1f).fillMaxWidth().padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.sm)) {222+            Box(223+                Modifier.weight(1f).fillMaxWidth()224+                    .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.sm)225+                    .clip(RoundedCornerShape(PeachRadius.StackCard))226+                    .background(peachColors.SurfaceCard)227+                    .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.StackCard))228+                    .padding(PeachSpacing.lg),229+            ) {216230                 if (body.text.isEmpty()) {217231                     Text(218232                         "Start writing…",@@ -289,7 +303,8 @@289303                 Surface(290304                     modifier = Modifier.fillMaxWidth().padding(horizontal = PeachSpacing.lg),291305                     color = peachColors.S1,292-                    shape = RoundedCornerShape(PeachSpacing.lg),306+                    shape = RoundedCornerShape(PeachRadius.StackCard),307+                    border = androidx.compose.foundation.BorderStroke(1.dp, peachColors.T3),293308                     tonalElevation = 1.dp,294309                 ) {295310                     Row(@@ -399,8 +414,9 @@399414     val accent = LocalPeachAccent.current400415     Row(401416         Modifier.fillMaxWidth()402-            .clip(RoundedCornerShape(8.dp))403-            .background(if (selected) accent.copy(alpha = 0.14f) else peachColors.S1)417+            .clip(RoundedCornerShape(PeachRadius.StackCard))418+            .background(if (selected) accent.copy(alpha = 0.14f) else peachColors.SurfaceCard)419+            .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.StackCard))404420             .combinedClickable(405421                 onClick = onClick,406422                 onLongClickLabel = "Select note",

view file

app/src/main/java/com/peachpasswords/ui/vault/PeachField.kt+32 −4
@@ -2,6 +2,9 @@22 33 import androidx.compose.foundation.interaction.MutableInteractionSource44 import androidx.compose.foundation.interaction.collectIsFocusedAsState5+import androidx.compose.foundation.background6+import androidx.compose.foundation.border7+import androidx.compose.foundation.layout.Box58 import androidx.compose.foundation.layout.Column69 import androidx.compose.foundation.layout.Row710 import androidx.compose.foundation.layout.Spacer@@ -9,6 +12,7 @@912 import androidx.compose.foundation.layout.height1013 import androidx.compose.foundation.layout.padding1114 import androidx.compose.foundation.layout.width15+import androidx.compose.foundation.shape.RoundedCornerShape1216 import androidx.compose.foundation.text.BasicTextField1317 import androidx.compose.foundation.text.KeyboardOptions1418 import androidx.compose.material3.Text@@ -30,6 +34,8 @@3034 import com.peachpasswords.ui.theme.LocalPeachAccent3135 import com.peachpasswords.ui.theme.peachColors3236 import com.peachpasswords.ui.theme.PeachType37+import com.peachpasswords.ui.theme.PeachRadius38+import com.peachpasswords.ui.theme.PeachSpacing3339 3440 /**3541  * The Peach text field used across the entry-edit screens: a bare underline (no@@ -52,12 +58,23 @@5258     visualTransformation: VisualTransformation = VisualTransformation.None,5359     labelTrailing: (@Composable () -> Unit)? = null,5460     trailing: (@Composable () -> Unit)? = null,61+    joined: Boolean = false,62+    divider: Boolean = false,5563 ) {5664     val accent = LocalPeachAccent.current5765     val interaction = remember { MutableInteractionSource() }5866     val focused by interaction.collectIsFocusedAsState()59-    val hairline = peachColors.T360-    Column(modifier.fillMaxWidth().padding(bottom = 14.dp)) {67+    Column(68+        modifier.fillMaxWidth()69+            .then(if (joined) Modifier else Modifier.padding(bottom = PeachSpacing.sm))70+            .then(71+                if (joined) Modifier.padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md)72+                else Modifier73+                    .background(peachColors.SurfaceCard, RoundedCornerShape(PeachRadius.StackCard))74+                    .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.StackCard))75+                    .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),76+            ),77+    ) {6178         Row(verticalAlignment = Alignment.CenterVertically) {6279             Text(6380                 label.uppercase(),@@ -89,8 +106,8 @@89106                 modifier = Modifier90107                     .weight(1f)91108                     .drawBehind {92-                        drawRect(93-                            color = if (focused) accent else hairline,109+                        if (focused) drawRect(110+                            color = accent,94111                             topLeft = Offset(0f, size.height - 1.dp.toPx()),95112                             size = Size(size.width, 1.dp.toPx()),96113                         )@@ -103,4 +120,15 @@103120             }104121         }105122     }123+    if (joined && divider) Box(Modifier.fillMaxWidth().height(1.dp).background(peachColors.T3))124+}125+126+@Composable127+fun PeachFieldStack(modifier: Modifier = Modifier, content: @Composable () -> Unit) {128+    Column(129+        modifier.fillMaxWidth()130+            .padding(bottom = PeachSpacing.sm)131+            .background(peachColors.SurfaceCard, RoundedCornerShape(PeachRadius.StackCard))132+            .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.StackCard)),133+    ) { content() }106134 }

view file

app/src/main/java/com/peachpasswords/ui/vault/TrashScreen.kt+4 −14
@@ -40,7 +40,7 @@4040 import androidx.lifecycle.viewModelScope4141 import com.peachpasswords.ui.components.FaviconInitials4242 import com.peachpasswords.ui.components.PeachEmptyOrEndState43-import com.peachpasswords.ui.components.PeachTopBar43+import com.peachpasswords.ui.components.PeachSectionHeader4444 import com.peachpasswords.ui.theme.LocalPeachAccent4545 import com.peachpasswords.ui.theme.PeachSpacing4646 import com.peachpasswords.ui.theme.PeachType@@ -91,19 +91,9 @@9191                 .systemBarsPadding()9292                 .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),9393         ) {94-            PeachTopBar(95-                title = "Trash",96-                leading = {97-                    Icon(98-                        Icons.AutoMirrored.Rounded.ArrowBack,99-                        contentDescription = "back",100-                        tint = peachColors.T0,101-                        modifier = Modifier102-                            .size(22.dp)103-                            .clip(RoundedCornerShape(PeachSpacing.sm))104-                            .clickable(onClick = onBack),105-                    )106-                },94+            PeachSectionHeader(95+                section = "trash",96+                onHome = onBack,10797                 actions = {10898                     if (deleted.isNotEmpty()) {10999                         GhostPill("Empty trash", peachColors.Breach) { confirmEmptyAll = true }

view file

app/src/main/java/com/peachpasswords/ui/vault/VaultHealthScreen.kt+4 −11
@@ -46,7 +46,7 @@4646 import com.peachpasswords.ui.components.FaviconInitials4747 import com.peachpasswords.ui.components.PeachEmptyOrEndState4848 import com.peachpasswords.ui.components.PeachMark49-import com.peachpasswords.ui.components.PeachTopBar49+import com.peachpasswords.ui.components.PeachSectionHeader5050 import com.peachpasswords.ui.theme.LocalPeachAccent5151 import com.peachpasswords.ui.theme.PeachSpacing5252 import com.peachpasswords.ui.theme.peachColors@@ -135,16 +135,9 @@135135                 .systemBarsPadding()136136                 .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),137137         ) {138-            PeachTopBar(139-                title = "vault health",140-                leading = {141-                    Icon(142-                        Icons.AutoMirrored.Rounded.ArrowBack,143-                        contentDescription = "back",144-                        tint = peachColors.T0,145-                        modifier = Modifier.size(22.dp).clip(RoundedCornerShape(PeachSpacing.sm)).clickable(onClick = onBack),146-                    )147-                },138+            PeachSectionHeader(139+                section = "vault health",140+                onHome = onBack,148141                 actions = {149142                     GhostPill("check now", accent) { vm.recompute() }150143                 },

view file

app/src/main/java/com/peachpasswords/ui/vault/VaultListScreen.kt+5 −1
@@ -318,7 +318,11 @@318318                         containerColor = LocalPeachAccent.current,319319                         contentColor = peachColors.Bg,320320                     ) {321-                        Icon(Icons.Rounded.Add, contentDescription = if (noteOnly) "new note" else "new entry")321+                        Icon(322+                            Icons.Rounded.Add,323+                            contentDescription = if (noteOnly) "new note" else "new entry",324+                            modifier = Modifier.size(28.dp),325+                        )322326                     }323327                 }324328             }

view file