f3653a69dc9c
fix: Restore complete Vault List layout (v2.14.23)
- time
- 2026-08-14 16:38 UTC · 2 months ago
- machine
- koh2
- agent
- gpt-5.6-sol
- session
- vault list restoration
- parent
- ad56fa5783bb
↓ peach-android-f3653a69.tar.gzatlas at this save
files changed2 files
VERSION+1 −1app/src/main/java/com/peachpasswords/ui/vault/VaultListScreen.kt+52 −58app/src/main/java/com/peachpasswords/ui/vault/VaultListScreen.kt+52 −58
@@ -44,7 +44,9 @@4444 import androidx.compose.material.icons.rounded.Close4545 import androidx.compose.material.icons.rounded.Search4646 import androidx.compose.material.icons.rounded.Settings47+import androidx.compose.material3.SmallFloatingActionButton4748 import androidx.compose.material.icons.outlined.Lock49+import androidx.compose.material3.FloatingActionButton4850 import androidx.compose.material3.Icon4951 import androidx.compose.material3.TextButton5052 import androidx.compose.material3.Snackbar@@ -67,7 +69,6 @@6769 import androidx.compose.ui.geometry.Offset6870 import androidx.compose.ui.geometry.Size6971 import androidx.compose.ui.graphics.Color70-import androidx.compose.ui.graphics.Brush7172 import androidx.compose.ui.graphics.SolidColor7273 import androidx.compose.ui.graphics.StrokeCap7374 import androidx.compose.ui.graphics.drawscope.Stroke@@ -80,7 +81,6 @@8081 import androidx.compose.ui.input.pointer.positionChange8182 import androidx.compose.ui.focus.FocusRequester8283 import androidx.compose.ui.focus.focusRequester83-import androidx.compose.ui.focus.onFocusChanged8484 import androidx.compose.ui.platform.LocalContext8585 import androidx.compose.ui.platform.LocalDensity8686 import androidx.compose.ui.text.TextStyle@@ -170,7 +170,6 @@170170 val undoEvent by vm.undoEvent.collectAsState()171171 val proNotice by vm.proNotice.collectAsState()172172 val snackbarHostState = remember { SnackbarHostState() }173- var searchActive by remember { mutableStateOf(initialSearchActive) }174173 // Pull-to-refresh drives a manual sync round against paired devices.175174 val syncVm: SyncViewModel = hiltViewModel()176175 val syncStatus by syncVm.status.collectAsState()@@ -210,9 +209,7 @@210209 211210 ShellBackground(modifier) {212211 Box(Modifier.fillMaxSize()) {213- Column(214- Modifier.fillMaxSize().then(if (isMultiSelect) Modifier else Modifier.statusBarsPadding()),215- ) {212+ Column(Modifier.fillMaxSize()) {216213 if (isMultiSelect) {217214 MultiSelectTopBar(218215 count = selectedIds.size,@@ -228,6 +225,16 @@228225 },229226 onDismiss = vm::dismissProNotice,230227 )228+ SearchBar(229+ value = search,230+ onChange = vm::setSearch,231+ count = if (search.isNotBlank()) "${entries.size}/$total" else pluralEntries(total),232+ onCollapse = onBack,233+ topInset = !isMultiSelect,234+ requestFocus = initialSearchActive,235+ syncStatus = syncStatus,236+ pairedCount = pairedDevices.size,237+ )231238 if (allTags.isNotEmpty()) {232239 TagFilterStrip(233240 allTags = allTags,@@ -237,7 +244,11 @@237244 }238245 SortBar(239246 active = sort,247+ noteOnly = noteOnly,248+ onSettings = { onNavigate(PeachNav.Settings) },240249 onSort = vm::setSort,250+ onToggleNote = vm::toggleNoteFilter,251+ onTrash = { onNavigate(PeachNav.Trash) },241252 )242253 Box(Modifier.fillMaxWidth().weight(1f)) {243254 PeachPullToRefresh(@@ -284,47 +295,37 @@284295 modifier = Modifier.animateItem(),285296 )286297 }287- // Trailing space so the last row clears the contextual288- // action tier and search surface.289- item { Spacer(Modifier.height(148.dp)) }298+ item { Spacer(Modifier.height(88.dp)) }290299 }291300 }301+ Column(302+ modifier = Modifier.align(Alignment.BottomEnd)303+ .padding(PeachSpacing.lg)304+ .navigationBarsPadding(),305+ horizontalAlignment = Alignment.CenterHorizontally,306+ verticalArrangement = Arrangement.spacedBy(PeachSpacing.md),307+ ) {308+ SmallFloatingActionButton(309+ onClick = vm::lock,310+ containerColor = peachColors.S1,311+ contentColor = LocalPeachAccent.current,312+ ) { Icon(Icons.Outlined.Lock, contentDescription = "Lock vault") }313+ FloatingActionButton(314+ onClick = {315+ if (noteOnly) vm.createNote { id -> onNavigate(PeachNav.NotesMode(id)) }316+ else onNavigate(PeachNav.EntryEdit(null))317+ },318+ containerColor = LocalPeachAccent.current,319+ contentColor = peachColors.Bg,320+ ) {321+ Icon(Icons.Rounded.Add, contentDescription = if (noteOnly) "new note" else "new entry")322+ }323+ }292324 }293325 }294- Column(295- Modifier.align(Alignment.BottomCenter)296- .fillMaxWidth()297- .background(Brush.verticalGradient(listOf(Color.Transparent, peachColors.Bg), startY = 0f))298- .padding(top = PeachSpacing.lg)299- .navigationBarsPadding(),300- ) {301- if (!searchActive) {302- VaultActionCluster(303- noteOnly = noteOnly,304- onToggleNote = vm::toggleNoteFilter,305- onTrash = { onNavigate(PeachNav.Trash) },306- onSettings = { onNavigate(PeachNav.Settings) },307- onAdd = {308- if (noteOnly) vm.createNote { id -> onNavigate(PeachNav.NotesMode(id)) }309- else onNavigate(PeachNav.EntryEdit(null))310- },311- onLock = vm::lock,312- )313- }314- SearchBar(315- value = search,316- onChange = vm::setSearch,317- count = if (search.isNotBlank()) "${entries.size}/$total" else pluralEntries(total),318- onCollapse = onBack,319- requestFocus = initialSearchActive,320- onFocusChange = { searchActive = it },321- syncStatus = syncStatus,322- pairedCount = pairedDevices.size,323- )324- }325326 SnackbarHost(326327 hostState = snackbarHostState,327- modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 148.dp).navigationBarsPadding(),328+ modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),328329 ) { data ->329330 Snackbar(330331 containerColor = peachColors.SurfaceElevated,@@ -387,8 +388,8 @@387388 onChange: (String) -> Unit,388389 count: String,389390 onCollapse: (() -> Unit)? = null,391+ topInset: Boolean = false,390392 requestFocus: Boolean = false,391- onFocusChange: (Boolean) -> Unit = {},392393 syncStatus: SyncOutcomeSummary? = null,393394 pairedCount: Int = 0,394395 ) {@@ -397,7 +398,7 @@397398 LaunchedEffect(requestFocus) {398399 if (requestFocus) focusRequester.requestFocus()399400 }400- Column(Modifier.fillMaxWidth()) {401+ Column(Modifier.fillMaxWidth().then(if (topInset) Modifier.statusBarsPadding() else Modifier)) {401402 Row(402403 Modifier403404 .fillMaxWidth()@@ -441,8 +442,7 @@441442 textStyle = PeachType.searchInput.copy(color = peachColors.T0),442443 cursorBrush = SolidColor(accent),443444 modifier = Modifier.fillMaxWidth()444- .focusRequester(focusRequester)445- .onFocusChanged { onFocusChange(it.isFocused) },445+ .focusRequester(focusRequester),446446 )447447 }448448 if (syncStatus != null) {@@ -461,7 +461,11 @@461461 @Composable462462 private fun SortBar(463463 active: SortOrder,464+ noteOnly: Boolean,465+ onSettings: () -> Unit,464466 onSort: (SortOrder) -> Unit,467+ onToggleNote: () -> Unit,468+ onTrash: () -> Unit,465469 ) {466470 val hairline = peachColors.T3467471 // One row, matching the browser's single combined sort+actions bar — the@@ -488,23 +492,21 @@488492 onSelected = { key ->489493 SortOrder.entries.firstOrNull { it.name == key }?.let(onSort)490494 },491- modifier = Modifier.fillMaxWidth(),495+ modifier = Modifier.weight(1f),492496 )497+ ActionCluster(noteOnly, onSettings, onToggleNote, onTrash)493498 }494499 }495500 496501 @Composable497-private fun VaultActionCluster(502+private fun ActionCluster(498503 noteOnly: Boolean,499504 onSettings: () -> Unit,500505 onToggleNote: () -> Unit,501506 onTrash: () -> Unit,502- onAdd: () -> Unit,503- onLock: () -> Unit,504507 ) {505508 val accent = LocalPeachAccent.current506509 Surface(507- modifier = Modifier.padding(horizontal = PeachSpacing.xl),508510 color = peachColors.S1,509511 contentColor = peachColors.T1,510512 shape = RoundedCornerShape(999.dp),@@ -535,19 +537,11 @@535537 icon = { Icon(Icons.Outlined.Delete, contentDescription = "trash") },536538 onClick = onTrash,537539 )538- ClusterIcon(539- icon = { Icon(Icons.Rounded.Add, contentDescription = if (noteOnly) "new note" else "new entry") },540- onClick = onAdd,541- )542540 // Settings last: it is the only app-level action in the cluster,543541 // and the extension likewise keeps it out of the content actions.544542 ClusterIcon(545543 icon = { Icon(Icons.Outlined.Settings, contentDescription = "settings") },546544 onClick = onSettings,547- )548- ClusterIcon(549- icon = { Icon(Icons.Outlined.Lock, contentDescription = "Lock vault", tint = accent) },550- onClick = onLock,551545 )552546 }553547 }