SearchToolbar: Better physical keyboard support (#8529)
Make enter keys behave like search key of on-screen keyboard
This commit is contained in:
parent
c31cf2a03a
commit
acd43005df
4 changed files with 40 additions and 11 deletions
|
@ -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,
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Reference in a new issue