From 9df8db91ff7ab71d1c92f08bb6dcbe4f36e59528 Mon Sep 17 00:00:00 2001 From: Mohamed Isa Date: Sun, 10 May 2026 18:24:31 +0300 Subject: [PATCH] Double tap on search tab to focus on search input --- .../commonMain/kotlin/com/nuvio/app/App.kt | 23 +++++++++++++++++-- .../nuvio/app/features/search/SearchScreen.kt | 12 ++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt index 1508344b..f364e2e5 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt @@ -520,6 +520,7 @@ private fun MainAppContent( val hapticFeedback = LocalHapticFeedback.current val coroutineScope = rememberCoroutineScope() var selectedTab by rememberSaveable { mutableStateOf(AppScreenTab.Home) } + var searchFocusRequestCount by remember { mutableStateOf(0) } val currentBackStackEntry by navController.currentBackStackEntryAsState() val nativeRequestedTab by remember { NativeTabBridge.requestedTab }.collectAsStateWithLifecycle() val liquidGlassNativeTabBarEnabled by remember { @@ -583,6 +584,9 @@ private fun MainAppContent( LaunchedEffect(selectedTab) { NativeTabBridge.publishSelectedTab(selectedTab.toNativeNavigationTab()) + if (selectedTab != AppScreenTab.Search) { + searchFocusRequestCount = 0 + } } DisposableEffect( @@ -1009,7 +1013,13 @@ private fun MainAppContent( ) NavItem( selected = selectedTab == AppScreenTab.Search, - onClick = { selectedTab = AppScreenTab.Search }, + onClick = { + if (selectedTab == AppScreenTab.Search) { + searchFocusRequestCount++ + } else { + selectedTab = AppScreenTab.Search + } + }, icon = Res.drawable.sidebar_search, contentDescription = stringResource(Res.string.compose_nav_search), ) @@ -1043,6 +1053,7 @@ private fun MainAppContent( .fillMaxSize() .padding(innerPadding), selectedTab = selectedTab, + searchFocusRequestCount = searchFocusRequestCount, animateHomeCollectionGifs = tabsRouteActive, onCatalogClick = onCatalogClick, onPosterClick = { meta -> @@ -1097,7 +1108,13 @@ private fun MainAppContent( if (isTabletLayout && !useNativeBottomTabs) { TabletFloatingTopBar( selectedTab = selectedTab, - onTabSelected = { selectedTab = it }, + onTabSelected = { tab -> + if (tab == AppScreenTab.Search && selectedTab == AppScreenTab.Search) { + searchFocusRequestCount++ + } else { + selectedTab = tab + } + }, onProfileSelected = onProfileSelected, onAddProfileRequested = onSwitchProfile, ) @@ -1975,6 +1992,7 @@ private fun rememberGuardedPopBackStack( private fun AppTabHost( selectedTab: AppScreenTab, modifier: Modifier = Modifier, + searchFocusRequestCount: Int = 0, animateHomeCollectionGifs: Boolean = true, onCatalogClick: ((HomeCatalogSection) -> Unit)? = null, onPosterClick: ((MetaPreview) -> Unit)? = null, @@ -2022,6 +2040,7 @@ private fun AppTabHost( modifier = Modifier.fillMaxSize(), onPosterClick = onPosterClick, onPosterLongClick = onPosterLongClick, + searchFocusRequestCount = searchFocusRequestCount, ) } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt index bad6cc11..5d2f2ee4 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt @@ -33,6 +33,8 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.Alignment +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.Dp import androidx.compose.ui.text.font.FontWeight @@ -80,7 +82,16 @@ fun SearchScreen( modifier: Modifier = Modifier, onPosterClick: ((MetaPreview) -> Unit)? = null, onPosterLongClick: ((MetaPreview) -> Unit)? = null, + searchFocusRequestCount: Int = 0, ) { + val focusRequester = remember { FocusRequester() } + + LaunchedEffect(searchFocusRequestCount) { + if (searchFocusRequestCount > 0) { + focusRequester.requestFocus() + } + } + LaunchedEffect(Unit) { AddonRepository.initialize() WatchedRepository.ensureLoaded() @@ -240,6 +251,7 @@ fun SearchScreen( value = query, onValueChange = { query = it }, placeholder = stringResource(Res.string.compose_search_placeholder), + modifier = Modifier.focusRequester(focusRequester), trailingContent = if (query.isNotBlank()) { { IconButton(onClick = { query = "" }) {