SearchToolbar: Better physical keyboard support (#8529)

Make enter keys behave like search key of on-screen keyboard

(cherry picked from commit acd43005dff055564dd6526eaa3f32347408be5c)
This commit is contained in:
Ivan Iskandar 2022-11-13 22:59:23 +07:00 committed by Jobobby04
parent df63f3e698
commit 33f57f6df7
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 {