Browse Source

SearchToolbar: Better physical keyboard support (#8529)

Make enter keys behave like search key of on-screen keyboard
Ivan Iskandar 2 years ago
parent
commit
acd43005df

+ 10 - 8
app/src/main/java/eu/kanade/presentation/components/AppBar.kt

@@ -44,6 +44,7 @@ import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import eu.kanade.presentation.util.runOnEnterKeyPressed
 import eu.kanade.presentation.util.secondaryItemAlpha
 import eu.kanade.tachiyomi.R
 
@@ -251,25 +252,26 @@ fun SearchToolbar(
             val keyboardController = LocalSoftwareKeyboardController.current
             val focusManager = LocalFocusManager.current
 
+            val searchAndClearFocus: () -> Unit = {
+                onSearch(searchQuery)
+                focusManager.clearFocus()
+                keyboardController?.hide()
+            }
+
             BasicTextField(
                 value = searchQuery,
                 onValueChange = onChangeSearchQuery,
                 modifier = Modifier
                     .fillMaxWidth()
-                    .focusRequester(focusRequester),
+                    .focusRequester(focusRequester)
+                    .runOnEnterKeyPressed(action = searchAndClearFocus),
                 textStyle = MaterialTheme.typography.titleMedium.copy(
                     color = MaterialTheme.colorScheme.onBackground,
                     fontWeight = FontWeight.Normal,
                     fontSize = 18.sp,
                 ),
                 keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
-                keyboardActions = KeyboardActions(
-                    onSearch = {
-                        onSearch(searchQuery)
-                        focusManager.clearFocus()
-                        keyboardController?.hide()
-                    },
-                ),
+                keyboardActions = KeyboardActions(onSearch = { searchAndClearFocus() }),
                 singleLine = true,
                 cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground),
                 visualTransformation = visualTransformation,

+ 8 - 2
app/src/main/java/eu/kanade/presentation/manga/TrackServiceSearch.kt

@@ -62,6 +62,7 @@ import eu.kanade.presentation.components.LoadingScreen
 import eu.kanade.presentation.components.MangaCover
 import eu.kanade.presentation.components.ScrollbarLazyColumn
 import eu.kanade.presentation.util.plus
+import eu.kanade.presentation.util.runOnEnterKeyPressed
 import eu.kanade.presentation.util.secondaryItemAlpha
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
@@ -80,6 +81,10 @@ fun TrackServiceSearch(
 ) {
     val focusManager = LocalFocusManager.current
     val focusRequester = remember { FocusRequester() }
+    val dispatchQueryAndClearFocus: () -> Unit = {
+        onDispatchQuery()
+        focusManager.clearFocus()
+    }
 
     Scaffold(
         contentWindowInsets = WindowInsets(
@@ -106,12 +111,13 @@ fun TrackServiceSearch(
                             onValueChange = onQueryChange,
                             modifier = Modifier
                                 .fillMaxWidth()
-                                .focusRequester(focusRequester),
+                                .focusRequester(focusRequester)
+                                .runOnEnterKeyPressed(action = dispatchQueryAndClearFocus),
                             textStyle = MaterialTheme.typography.bodyLarge
                                 .copy(color = MaterialTheme.colorScheme.onSurface),
                             singleLine = true,
                             keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
-                            keyboardActions = KeyboardActions(onSearch = { focusManager.clearFocus(); onDispatchQuery() }),
+                            keyboardActions = KeyboardActions(onSearch = { dispatchQueryAndClearFocus() }),
                             cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
                             decorationBox = {
                                 if (query.text.isEmpty()) {

+ 3 - 1
app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt

@@ -54,6 +54,7 @@ import eu.kanade.presentation.components.Divider
 import eu.kanade.presentation.components.EmptyScreen
 import eu.kanade.presentation.components.Scaffold
 import eu.kanade.presentation.more.settings.Preference
+import eu.kanade.presentation.util.runOnEnterKeyPressed
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.util.system.isLTR
 
@@ -108,7 +109,8 @@ class SettingsSearchScreen : Screen {
                                 onValueChange = { textFieldValue = it },
                                 modifier = Modifier
                                     .fillMaxWidth()
-                                    .focusRequester(focusRequester),
+                                    .focusRequester(focusRequester)
+                                    .runOnEnterKeyPressed(action = focusManager::clearFocus),
                                 textStyle = MaterialTheme.typography.bodyLarge
                                     .copy(color = MaterialTheme.colorScheme.onSurface),
                                 singleLine = true,

+ 19 - 0
app/src/main/java/eu/kanade/presentation/util/Modifier.kt

@@ -10,6 +10,9 @@ import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onPreviewKeyEvent
 import androidx.compose.ui.layout.LayoutModifier
 import androidx.compose.ui.layout.Measurable
 import androidx.compose.ui.layout.MeasureResult
@@ -43,6 +46,22 @@ fun Modifier.clickableNoIndication(
     )
 }
 
+/**
+ * For TextField, the provided [action] will be invoked when
+ * physical enter key is pressed.
+ *
+ * Naturally, the TextField should be set to single line only.
+ */
+fun Modifier.runOnEnterKeyPressed(action: () -> Unit): Modifier = this.onPreviewKeyEvent {
+    when (it.key) {
+        Key.Enter, Key.NumPadEnter -> {
+            action()
+            true
+        }
+        else -> false
+    }
+}
+
 @Suppress("ModifierInspectorInfo")
 fun Modifier.minimumTouchTargetSize(): Modifier = composed(
     inspectorInfo = debugInspectorInfo {