53183c79f084

fix: Match browser add-entry tag behavior (v2.3.15)

time
2026-06-26 01:23 UTC · 4 months ago
machine
koh2
parent
fb79f4f138ac
3 files app/build.gradle+2 −2app/src/main/java/com/peachpasswords/ui/vault/TagChipEditor.kt+19 −12app/src/test/java/com/peachpasswords/ui/vault/EntryEditScreenTest.kt+17 −0
app/build.gradle+2 −2
@@ -16,8 +16,8 @@1616         applicationId "com.peachpasswords"1717         minSdk 261818         targetSdk 3519-        versionCode 23140020-        versionName "2.3.14"19+        versionCode 23150020+        versionName "2.3.15"2121 2222         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"2323         vectorDrawables {

view file

app/src/main/java/com/peachpasswords/ui/vault/TagChipEditor.kt+19 −12
@@ -38,22 +38,34 @@3838 import com.peachpasswords.ui.theme.PeachType3939 4040 /** Max tags per entry. */41-private const val MAX_TAGS = 1041+internal const val MAX_TAGS = 104242 4343 /** Max characters per tag. */44-private const val MAX_TAG_LEN = 3244+internal const val MAX_TAG_LEN = 324545 46+/** Browser AddView shows up to five tag suggestions. */47+internal const val MAX_TAG_SUGGESTIONS = 548+4649 /** Normalise raw tag input to the canonical form (trimmed, lowercase, length-capped). */4750 internal fun normalizeTag(raw: String): String =4851     raw.trim().lowercase().take(MAX_TAG_LEN)4952 53+internal fun tagSuggestionsFor(input: String, allTags: List<String>, tags: List<String>): List<String> {54+    val needle = input.trim().lowercase()55+    return allTags.asSequence()56+        .filter { it !in tags }57+        .filter { needle.isEmpty() || (it.contains(needle) && it != needle) }58+        .take(MAX_TAG_SUGGESTIONS)59+        .toList()60+}61+5062 /**5163  * Tag chip editor for EntryEditScreen. Self-contained: owns its own draft-input5264  * state; the committed tag list and suggestion source come from the caller.5365  *54- * - Commits on space or enter (also strips spaces typed mid-word into commits).66+ * - Commits on comma or enter, matching browser AddView.5567  * - Enforces max 10 tags, 32 chars, lowercase, trimmed, de-duplicated.56- * - Shows up to 4 autocomplete suggestions drawn from [allTags] minus current tags.68+ * - Shows up to 5 autocomplete suggestions drawn from [allTags] minus current tags.5769  */5870 @OptIn(ExperimentalLayoutApi::class)5971 @Composable@@ -75,11 +87,7 @@7587 7688     val suggestions = remember(draft, allTags, tags) {7789         val needle = draft.trim().lowercase()78-        allTags.asSequence()79-            .filter { it !in tags }80-            .filter { needle.isEmpty() || (it.contains(needle) && it != needle) }81-            .take(4)82-            .toList()90+        tagSuggestionsFor(needle, allTags, tags)8391     }8492 8593     Column(Modifier.fillMaxWidth().padding(bottom = 14.dp)) {@@ -108,9 +116,8 @@108116                     BasicTextField(109117                         value = draft,110118                         onValueChange = { input ->111-                            // Space acts as a delimiter: commit the segment before it.112-                            if (input.endsWith(" ") || input.contains(' ')) {113-                                val parts = input.split(' ')119+                            if (input.endsWith(",") || input.contains(',')) {120+                                val parts = input.split(',')114121                                 parts.dropLast(1).forEach { commit(it) }115122                                 draft = normalizeTag(parts.last())116123                             } else {

view file

app/src/test/java/com/peachpasswords/ui/vault/EntryEditScreenTest.kt+17 −0
@@ -92,6 +92,23 @@9292         assertEquals("hide generator", generatorToggleLabel(open = true))9393     }9494 95+    @Test fun tag_suggestions_match_browser_add_view_limit_and_filtering() {96+        val all = listOf("banking", "billing", "books", "business", "backup", "travel")97+        assertEquals(98+            listOf("banking", "billing", "books", "business", "backup"),99+            tagSuggestionsFor(input = "b", allTags = all, tags = emptyList()),100+        )101+        assertEquals(102+            listOf("billing", "books", "business", "backup"),103+            tagSuggestionsFor(input = "b", allTags = all, tags = listOf("banking")),104+        )105+    }106+107+    @Test fun tag_normalization_allows_spaces_and_caps_length_like_browser() {108+        assertEquals("shared login", normalizeTag(" Shared Login "))109+        assertEquals("a".repeat(MAX_TAG_LEN), normalizeTag("A".repeat(MAX_TAG_LEN + 8)))110+    }111+95112     // ── Card field formatting (CardFieldUtils, used live by setCardNumber etc.) ─96113 97114     @Test fun new_card_number_auto_formats() {

view file