commit 3e9a30bd9d709b5985b48ce943c7603198aafd6b parent 6c3a0a12f215c45ed380272e5a1f6a88eab354ed Author: Harrison Oglesby <oglesby.harrison@gmail.com> Date: Tue, 9 Dec 2025 22:29:04 +0000 Bug 2003639 - Preserve keyboard open state on user navigation to result in Settings Search r=android-reviewers,moyin Differential Revision: https://phabricator.services.mozilla.com/D275119 Diffstat:
3 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchBar.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchBar.kt @@ -22,12 +22,15 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.compose.LocalLifecycleOwner import mozilla.components.compose.base.button.IconButton import mozilla.components.compose.base.theme.AcornTheme import mozilla.components.lib.state.ext.observeAsComposableState @@ -39,12 +42,16 @@ import mozilla.components.ui.icons.R as iconsR * * @param store [SettingsSearchStore] for the screen. * @param onBackClick Invoked when the app bar's back button is clicked. + * @param isSearchFocused Whether the search bar is currently focused. + * @param onSearchFocusChange Invoked when the search bar's focus state changes. */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsSearchBar( store: SettingsSearchStore, onBackClick: () -> Unit, + isSearchFocused: Boolean, + onSearchFocusChange: (Boolean) -> Unit, ) { val focusRequester = remember { FocusRequester() } @@ -55,6 +62,8 @@ fun SettingsSearchBar( SettingsSearchField( store = store, focusRequester = focusRequester, + isSearchFocused = isSearchFocused, + onSearchFocusChange = onSearchFocusChange, ) }, navigationIcon = { BackButton(onClick = onBackClick) }, @@ -63,18 +72,18 @@ fun SettingsSearchBar( bottom = 0.dp, ), ) - - LaunchedEffect(Unit) { - focusRequester.requestFocus() - } } @Composable private fun SettingsSearchField( store: SettingsSearchStore, focusRequester: FocusRequester, + isSearchFocused: Boolean, + onSearchFocusChange: (Boolean) -> Unit, ) { val state by store.observeAsComposableState { it } + val lifecycleOwner = LocalLifecycleOwner.current + var searchQuery by remember { mutableStateOf( TextFieldValue( @@ -93,7 +102,12 @@ private fun SettingsSearchField( textStyle = AcornTheme.typography.body1, modifier = Modifier .fillMaxWidth() - .focusRequester(focusRequester), + .focusRequester(focusRequester) + .onFocusChanged { focusState -> + if (lifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { + onSearchFocusChange(focusState.isFocused) + } + }, placeholder = @Composable { Text( text = stringResource(R.string.settings_search_title), @@ -124,6 +138,12 @@ private fun SettingsSearchField( } }, ) + + LaunchedEffect(Unit) { + if (isSearchFocused) { + focusRequester.requestFocus() + } + } } @Composable diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchFragment.kt @@ -9,6 +9,10 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.fragment.app.Fragment import androidx.fragment.compose.content import androidx.lifecycle.coroutineScope @@ -32,11 +36,15 @@ class SettingsSearchFragment : Fragment() { settingsSearchStore = buildSettingsSearchStore() (activity as? AppCompatActivity)?.supportActionBar?.hide() FirefoxTheme { + var isSearchFocused by rememberSaveable { mutableStateOf(true) } + SettingsSearchScreen( store = settingsSearchStore, onBackClick = { findNavController().popBackStack() }, + isSearchFocused = isSearchFocused, + onSearchFocusChange = { isSearchFocused = it }, ) } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchScreen.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchScreen.kt @@ -48,11 +48,15 @@ import org.mozilla.fenix.theme.FirefoxTheme * * @param store [SettingsSearchStore] for the screen. * @param onBackClick Callback for when the back button is clicked. + * @param isSearchFocused Whether the search bar is currently focused. + * @param onSearchFocusChange Callback for when the search bar's focus state changes. */ @Composable fun SettingsSearchScreen( store: SettingsSearchStore, onBackClick: () -> Unit, + isSearchFocused: Boolean, + onSearchFocusChange: (Boolean) -> Unit, ) { val state by store.observeAsComposableState { it } Scaffold( @@ -61,6 +65,8 @@ fun SettingsSearchScreen( SettingsSearchBar( store = store, onBackClick = onBackClick, + isSearchFocused = isSearchFocused, + onSearchFocusChange = onSearchFocusChange, ) HorizontalDivider() } @@ -299,6 +305,8 @@ private fun SettingsSearchScreenInitialStatePreview() { SettingsSearchScreen( store = SettingsSearchStore(), onBackClick = {}, + isSearchFocused = false, + onSearchFocusChange = {}, ) } } @@ -333,6 +341,8 @@ private fun SettingsSearchScreenWithRecentsPreview() { SettingsSearchScreen( store = storeWithRecents, onBackClick = {}, + isSearchFocused = false, + onSearchFocusChange = {}, ) } } @@ -390,6 +400,8 @@ private fun SettingsSearchScreenWithResultsPreview() { SettingsSearchScreen( store = storeWithResults, onBackClick = {}, + isSearchFocused = false, + onSearchFocusChange = {}, ) } } @@ -410,6 +422,8 @@ private fun SettingsSearchScreenNoResultsPreview() { SettingsSearchScreen( store = storeWithNoResults, onBackClick = {}, + isSearchFocused = false, + onSearchFocusChange = {}, ) } }