The filter on Repositories takes focus only when touched (closes #12) 75ceba747960
Tapping a destination in the navigation bar gives the app's view focus, which Compose hands to the screen's first focusable: the filter, so the keyboard came up on every visit to Repositories. The filter can now take focus only once touched, or when the device is used from a keyboard. Checked on a Pixel 10 Pro Fold over adb: no keyboard on opening, the keyboard on tapping the filter, filtering as before.
- Author
- Andy McCall @andymccall <[email protected]>
- via
- agent
agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key 62e60420377a
- When
- · 2026-10-25 11:03 UTC
- Signature
- ◈ sealed by agent:claude@andymccall
- Hash
75ceba7479600e5cf590b136c67b90c2299cf47ed5b86ebb6fc0a2ff8daf55a1- Depends on
- 144cbf7bf2b5
- Depended on by
- 821035db5a1c
- In bookmarks
- main
- In tags
- v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 v0.1.5 v0.1.6 v0.1.7 v0.1.8 v0.1.9
- Edits
- 4 atoms, 0 tree operations, 1 file
Browse the tree at this change
modified app/src/main/java/io/oxygenhub/android/ui/repos/RepositoriesScreen.kt +31 −1
| … | 28 unchanged lines |
||
| 29 | 29 | import androidx.compose.runtime.getValue |
|
| 30 | 30 | import androidx.compose.runtime.rememberCoroutineScope |
|
| 31 | 31 | import androidx.compose.ui.Modifier |
|
| 32 | + | import androidx.compose.foundation.gestures.awaitEachGesture |
|
| 33 | + | import androidx.compose.foundation.gestures.awaitFirstDown |
|
| 34 | + | import androidx.compose.runtime.mutableStateOf |
|
| 35 | + | import androidx.compose.runtime.remember |
|
| 36 | + | import androidx.compose.runtime.setValue |
|
| 37 | + | import androidx.compose.ui.composed |
|
| 38 | + | import androidx.compose.ui.focus.focusProperties |
|
| 39 | + | import androidx.compose.ui.input.InputMode |
|
| 40 | + | import androidx.compose.ui.input.pointer.PointerEventPass |
|
| 41 | + | import androidx.compose.ui.input.pointer.pointerInput |
|
| 42 | + | import androidx.compose.ui.platform.LocalInputModeManager |
|
| 32 | 43 | import androidx.compose.ui.unit.dp |
|
| 33 | 44 | import androidx.lifecycle.compose.collectAsStateWithLifecycle |
|
| 34 | 45 | import androidx.window.core.layout.WindowSizeClass |
|
| … | 45 unchanged lines |
||
| 80 | 91 | ) |
|
| 81 | 92 | } |
|
| 82 | 93 | ||
| 94 | + | /** |
|
| 95 | + | * Focus only when touched (or reached from a keyboard): tapping a |
|
| 96 | + | * destination in the navigation bar gives the app's view focus, which |
|
| 97 | + | * Compose passes on to the screen's first focusable, and this filter then |
|
| 98 | + | * took it and brought the keyboard up on every visit (#12). |
|
| 99 | + | */ |
|
| 100 | + | private fun Modifier.focusedOnlyWhenTouched(): Modifier = composed { |
|
| 101 | + | val keyboard = LocalInputModeManager.current.inputMode == InputMode.Keyboard |
|
| 102 | + | var touched by remember { mutableStateOf(false) } |
|
| 103 | + | this |
|
| 104 | + | .pointerInput(Unit) { |
|
| 105 | + | awaitEachGesture { |
|
| 106 | + | awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial) |
|
| 107 | + | touched = true |
|
| 108 | + | } |
|
| 109 | + | } |
|
| 110 | + | .focusProperties { canFocus = touched || keyboard } |
|
| 111 | + | } |
|
| 112 | + | ||
| 83 | 113 | @Composable |
|
| 84 | 114 | private fun RepositoryList(vm: RepositoriesViewModel, selected: String?, onOpen: (Repository) -> Unit) { |
|
| 85 | 115 | val state by vm.state.collectAsStateWithLifecycle() |
|
| … | 6 unchanged lines |
||
| 92 | 122 | placeholder = { Text("Filter") }, |
|
| 93 | 123 | leadingIcon = { Icon(Icons.Outlined.Search, contentDescription = null) }, |
|
| 94 | 124 | singleLine = true, |
|
| 95 | - | modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), |
|
| 125 | + | modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp).focusedOnlyWhenTouched(), |
|
| 96 | 126 | ) |
|
| 97 | 127 | Row(Modifier.padding(horizontal = 16.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) { |
|
| 98 | 128 | FilterChip(query.filter == RepoFilter.Yours, onClick = { vm.setFilter(RepoFilter.Yours) }, label = { Text("Yours") }) |
|
| … | 27 unchanged lines |