From fc330a34002a519465d80895df20578862fa371e Mon Sep 17 00:00:00 2001 From: damontecres <154766448+damontecres@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:44:39 -0500 Subject: [PATCH] Improve search keyboard dismissal (#317) I need to test this more Fixes the imeAction for search Initiating the search will move focus down if results are available Pressing back while focused on the search text box will move focus to either the results or the nav drawer. I think will will help devices that do not dismiss on the soft keyboard on back. Might fix #311 --- .../wholphin/ui/components/EditTextBox.kt | 12 +++--- .../wholphin/ui/main/SearchPage.kt | 37 ++++++++++++++++--- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/EditTextBox.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/EditTextBox.kt index c8b6796b..63d98a4f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/EditTextBox.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/EditTextBox.kt @@ -53,8 +53,8 @@ fun EditTextBox( isInputValid: (String) -> Boolean = { true }, supportingText: @Composable (() -> Unit)? = null, placeholder: @Composable (() -> Unit)? = null, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, ) { - val interactionSource = remember { MutableInteractionSource() } // From ButtonDefaults val colors = TextFieldDefaults.colors( @@ -157,6 +157,7 @@ fun SearchEditTextBox( enabled: Boolean = true, readOnly: Boolean = false, height: Dp = 40.dp, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, ) { EditTextBox( value, @@ -171,7 +172,7 @@ fun SearchEditTextBox( KeyboardActions( onSearch = { onSearchClick.invoke() - this.defaultKeyboardAction(ImeAction.Done) + this.defaultKeyboardAction(ImeAction.Search) }, ), leadingIcon = { @@ -181,9 +182,10 @@ fun SearchEditTextBox( tint = MaterialTheme.colorScheme.onPrimaryContainer, ) }, - enabled, - readOnly, - height, + enabled = enabled, + readOnly = readOnly, + height = height, + interactionSource = interactionSource, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt index 2a57fd34..b4ee7b1b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt @@ -1,5 +1,9 @@ package com.github.damontecres.wholphin.ui.main +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.focusGroup +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -18,10 +22,13 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel @@ -157,6 +164,8 @@ fun SearchPage( viewModel: SearchViewModel = hiltViewModel(), ) { val context = LocalContext.current + val focusManager = LocalFocusManager.current + val keyboardController = LocalSoftwareKeyboardController.current val movies by viewModel.movies.observeAsState(SearchResult.NoQuery) val collections by viewModel.collections.observeAsState(SearchResult.NoQuery) val series by viewModel.series.observeAsState(SearchResult.NoQuery) @@ -166,6 +175,7 @@ fun SearchPage( val focusRequester = remember { FocusRequester() } var position by rememberPosition() + var searchClicked by rememberSaveable { mutableStateOf(false) } LaunchedEffect(query) { delay(750L) @@ -177,17 +187,31 @@ fun SearchPage( val onClickItem = { index: Int, item: BaseItem -> viewModel.navigationManager.navigateTo(item.destination()) } + LaunchedEffect(searchClicked, movies, collections, series, episodes) { + if (searchClicked) { + if (listOf(movies, collections, series, episodes).any { it is SearchResult.Success }) { + focusManager.moveFocus(FocusDirection.Next) + searchClicked = false + } + } + } LazyColumn( contentPadding = PaddingValues(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 44.dp), verticalArrangement = Arrangement.spacedBy(16.dp), - modifier = modifier, + modifier = modifier.focusGroup(), ) { item { Box( contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth(), ) { + val interactionSource = remember { MutableInteractionSource() } + val focused by interactionSource.collectIsFocusedAsState() + BackHandler(focused) { + keyboardController?.hide() + focusManager.moveFocus(FocusDirection.Next) + } SearchEditTextBox( value = query, onValueChange = { @@ -195,12 +219,15 @@ fun SearchPage( }, onSearchClick = { viewModel.search(query) + searchClicked = true }, modifier = - Modifier.ifElse( - position.row < MOVIE_ROW, - Modifier.focusRequester(focusRequester), - ), + Modifier + .ifElse( + position.row < MOVIE_ROW, + Modifier.focusRequester(focusRequester), + ), + interactionSource = interactionSource, ) } }