SearchToolbar: Better physical keyboard support (#8529)

Make enter keys behave like search key of on-screen keyboard
This commit is contained in:
Ivan Iskandar 2022-11-13 22:59:23 +07:00 committed by GitHub
parent c31cf2a03a
commit acd43005df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 11 deletions

View file

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

View file

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

View file

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

View file

@ -10,6 +10,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed import androidx.compose.ui.composed
import androidx.compose.ui.draw.alpha 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.LayoutModifier
import androidx.compose.ui.layout.Measurable import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult 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") @Suppress("ModifierInspectorInfo")
fun Modifier.minimumTouchTargetSize(): Modifier = composed( fun Modifier.minimumTouchTargetSize(): Modifier = composed(
inspectorInfo = debugInspectorInfo { inspectorInfo = debugInspectorInfo {