aboutsummaryrefslogtreecommitdiffstats
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt38
-rw-r--r--app/src/test/java/app/passwordstore/ui/autofill/AutofillModelTest.kt73
2 files changed, 111 insertions, 0 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt
new file mode 100644
index 00000000..44030d73
--- /dev/null
+++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillModel.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.ui.autofill
+
+import app.passwordstore.ui.list.ListRow
+import app.passwordstore.util.settings.DirectoryStructure
+import java.io.File
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.toImmutableList
+
+/**
+ * The autofill picker's rows for [files] (entries under [root], already ranked), in their order.
+ * The name is the origin identifier per [structure], the part that must match the site or app, so
+ * it stands out as the old picker's bold part did; the subtitle holds the account part and the
+ * folders above the identifier. Without an identifier the account part is the name.
+ */
+fun autofillRows(
+ files: List<File>,
+ root: File,
+ structure: DirectoryStructure,
+): ImmutableList<ListRow> =
+ files
+ .map { file ->
+ val relative = file.relativeTo(root)
+ val identifier = structure.getIdentifierFor(relative)
+ val account = structure.getAccountPartFor(relative)
+ val subtitle =
+ if (identifier == null) null
+ else
+ listOfNotNull(account, structure.getPathToIdentifierFor(relative))
+ .joinToString(" · ")
+ .ifEmpty { null }
+ ListRow(file.absolutePath, identifier ?: account.orEmpty(), subtitle, 0)
+ }
+ .toImmutableList()
diff --git a/app/src/test/java/app/passwordstore/ui/autofill/AutofillModelTest.kt b/app/src/test/java/app/passwordstore/ui/autofill/AutofillModelTest.kt
new file mode 100644
index 00000000..8907aa54
--- /dev/null
+++ b/app/src/test/java/app/passwordstore/ui/autofill/AutofillModelTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.ui.autofill
+
+import app.passwordstore.util.settings.DirectoryStructure
+import java.io.File
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class AutofillModelTest {
+
+ private val root = File("/store")
+
+ private fun rows(structure: DirectoryStructure, vararg paths: String) =
+ autofillRows(paths.map { File(root, it) }, root, structure).map {
+ Triple(it.path, it.label, it.subtitle)
+ }
+
+ @Test
+ fun fileBasedNamesTheIdentifier() {
+ assertEquals(
+ listOf(
+ Triple("/store/work/example.org/john@doe.org.gpg", "example.org", "john@doe.org · work"),
+ Triple("/store/example.org/john.gpg", "example.org", "john"),
+ Triple("/store/example.org.gpg", "example.org", null),
+ ),
+ rows(
+ DirectoryStructure.FileBased,
+ "work/example.org/john@doe.org.gpg",
+ "example.org/john.gpg",
+ "example.org.gpg",
+ ),
+ )
+ }
+
+ @Test
+ fun directoryBasedFallsBackToTheAccountPart() {
+ assertEquals(
+ listOf(
+ Triple(
+ "/store/example.org/john@doe.org/password.gpg",
+ "example.org",
+ "john@doe.org/password",
+ ),
+ Triple("/store/Temporary PIN.gpg", "Temporary PIN", null),
+ ),
+ rows(
+ DirectoryStructure.DirectoryBased,
+ "example.org/john@doe.org/password.gpg",
+ "Temporary PIN.gpg",
+ ),
+ )
+ }
+
+ @Test
+ fun encryptedUsernameShowsTheFolders() {
+ assertEquals(
+ listOf(Triple("/store/work/example.org.gpg", "example.org", "work")),
+ rows(DirectoryStructure.EncryptedUsername, "work/example.org.gpg"),
+ )
+ }
+
+ @Test
+ fun rowsKeepTheRankingOrder() {
+ assertEquals(
+ listOf("b.org", "a.org"),
+ rows(DirectoryStructure.FileBased, "b.org.gpg", "a.org.gpg").map { it.second },
+ )
+ }
+}