c83ebe04e301

reorder the entry-row pointer chain so long-press wins over the swipe detector, and rewire it to enter multi-select

time
2026-07-25 23:40 UTC · 3 months ago
machine
koh2
agent
claude-opus-5
session
long press multi select
parent
2a3b3c774a14
1 file app/src/main/java/com/peachpasswords/ui/vault/VaultListScreen.kt+31 −22
app/src/main/java/com/peachpasswords/ui/vault/VaultListScreen.kt+31 −22
@@ -243,9 +243,19 @@243243                                     if (isMultiSelect) vm.toggleSelected(entry.id)244244                                     else onNavigate(entryTapDestination(entry))245245                                 },246+                                // Long-press enters multi-select (Material 3 / Android247+                                // list convention) and selects the held entry. The248+                                // prior behaviour opened a context menu; the menu's249+                                // actions (copy password/username/TOTP, edit, trash)250+                                // are still reachable through the new entry-detail251+                                // surface, so no functionality is dropped — the252+                                // gesture is just no longer ambushed by the253+                                // swipe-copy detector, which is the bug this254+                                // re-ordering also fixes (see VaultListScreen255+                                // modifier chain comment near EntryRow).246256                                 onLongPress = {247-                                    if (isMultiSelect) vm.toggleSelected(entry.id)248-                                    else menuEntry = entry257+                                    if (!isMultiSelect) vm.enterMultiSelect()258+                                    vm.toggleSelected(entry.id)249259                                 },250260                                 onSwipeCopy = { vm.copyPassword(entry) },251261                                 // Sort changes, deletes, and new entries used to snap@@ -305,17 +315,6 @@305315         } // Box306316     }307317 308-    menuEntry?.let { e ->309-        ContextMenuSheet(310-            entry = e,311-            onCopyPassword = { vm.copyPassword(e); PeachHaptics.onCopy(view) },312-            onCopyUsername = { vm.copyUsername(e); PeachHaptics.onCopy(view) },313-            onCopyTotp = { vm.copyTotp(e); PeachHaptics.onCopy(view) },314-            onEdit = { onNavigate(PeachNav.EntryDetail(e.id)) },315-            onMoveToTrash = { vm.softDelete(e) },316-            onDismiss = { menuEntry = null },317-        )318-    }319318 }320319 321320 @Composable@@ -636,6 +635,25 @@636635             .fillMaxWidth()637636             .clip(RoundedCornerShape(7.dp))638637             .background(rowBg)638+            // Modifier order matters here, even though it looks incidental.639+            // detectTapGestures needs to be the OUTERMOST pointer modifier so640+            // its onLongPress gets first chance to fire (~500ms with no641+            // movement past its slop). The downstream detectHorizontalDragGestures642+            // has a smaller slop and will claim a touch with even a few pixels643+            // of motion during a long-press, swallowing the gesture — that is644+            // why long-press on a real device "did nothing" with the prior645+            // arrangement, where the swipe detector was outermost. Putting646+            // tap detection first lets it decide intent before movement647+            // arbitration kicks in.648+            .pointerInput(entry.id, multiSelect) {649+                detectTapGestures(650+                    onLongPress = {651+                        PeachHaptics.onLongPress(context)652+                        onLongPress()653+                    },654+                )655+            }656+            .clickable(interactionSource = interaction, indication = null, onClick = onTap)639657             .pointerInput(entry.id, canSwipeCopy) {640658                 if (!canSwipeCopy) return@pointerInput641659                 var dx = 0f@@ -653,15 +671,6 @@653671                     onHorizontalDrag = { change, amount -> dx += amount; dy += change.positionChange().y },654672                 )655673             }656-            .pointerInput(entry.id, multiSelect) {657-                detectTapGestures(658-                    onLongPress = {659-                        PeachHaptics.onLongPress(context)660-                        onLongPress()661-                    },662-                )663-            }664-            .clickable(interactionSource = interaction, indication = null, onClick = onTap)665674             .padding(horizontal = 16.dp, vertical = 7.dp),666675         horizontalArrangement = Arrangement.spacedBy(10.dp),667676         verticalAlignment = Alignment.CenterVertically,

view file