From dc15b927363c1c077cf9cb7453fa9df50406d4d3 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 4 Nov 2026 11:26:27 +0100 Subject: fix(app): address the autofill picker review - Run the first search during composition with the saved query and strict switch, so a recreated picker no longer flashes the results for the initial query under the restored text. - Scroll the result list back to the top on every new result, as the old picker did. - Fall back to the file name when a row has neither identifier nor account part, instead of an empty label. DirectoryStructure never returns both null today, so no test can reach it. Co-Authored-By: Claude Opus 5.5 --- .../java/app/passwordstore/ui/autofill/AutofillFilterScreen.kt | 7 ++++++- .../main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt | 8 +++++--- app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterScreen.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterScreen.kt index 49e19799..acbacd40 100644 --- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterScreen.kt +++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close @@ -24,6 +25,7 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -67,6 +69,9 @@ fun AutofillFilterScreen( modifier: Modifier = Modifier, ) { val fillInto = stringResource(R.string.oreo_autofill_select_and_fill_into) + val listState = rememberLazyListState() + // As the old picker did: every new result starts at its best match. + LaunchedEffect(rows) { listState.scrollToItem(0) } Surface(modifier.fillMaxSize()) { Column(Modifier.padding(vertical = SpacingLarge)) { Image( @@ -115,7 +120,7 @@ fun AutofillFilterScreen( // One lazy item per row: a cleared search lists the whole store. The surface wraps // a short list and is capped by the box for a long one. GroupedSurface(Modifier.fillMaxWidth()) { - LazyColumn { + LazyColumn(state = listState) { items(rows, key = { it.path }) { row -> EntryRow( name = row.label, diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt index 44994646..880ab2eb 100644 --- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt +++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt @@ -18,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -133,9 +134,6 @@ class AutofillFilterView : AppCompatActivity() { val isWeb = formOrigin is FormOrigin.Web val initialQuery = formOrigin.getPrettyIdentifier(applicationContext, untrusted = false) - // Before anything is composed, so the ViewModel's default root listing (folders included) is - // never shown. The LaunchedEffect below repeats it with equal arguments, which emits nothing. - search(initialQuery, isWeb) val root = PasswordRepository.getRepositoryDirectory() val directoryStructure = AutofillPreferences.directoryStructure(this) // ponytail: cold flow, so each return to STARTED walks the store again; fine for a picker open @@ -159,6 +157,10 @@ class AutofillFilterView : AppCompatActivity() { var strict by rememberSaveable { mutableStateOf(isWeb) } var match by rememberSaveable { mutableStateOf(true) } var clear by rememberSaveable { mutableStateOf(false) } + // During the first composition, before rows is collected, so the ViewModel's default root + // listing (folders included) is never shown, and with the restored query and switch after + // recreation. The LaunchedEffect repeats it with equal arguments, which emits nothing. + remember { search(query, strict) } LaunchedEffect(query, strict) { search(query, strict) } val shown by rows.collectAsStateWithLifecycle?>(initialValue = null) AutofillFilterScreen( diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt index 44030d73..ac2d0948 100644 --- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt +++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt @@ -33,6 +33,6 @@ fun autofillRows( listOfNotNull(account, structure.getPathToIdentifierFor(relative)) .joinToString(" ยท ") .ifEmpty { null } - ListRow(file.absolutePath, identifier ?: account.orEmpty(), subtitle, 0) + ListRow(file.absolutePath, identifier ?: account ?: file.nameWithoutExtension, subtitle, 0) } .toImmutableList() -- cgit v1.2.3