From a1e90b8c9f30b49bf33d01bf0d8d52528dcf7572 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 10 Mar 2026 16:56:31 -0400 Subject: [PATCH] save the lazy list state and make it scroll in the search view model to avoid coming back on another feed position --- .../loggedIn/search/SearchBarViewModel.kt | 8 +++-- .../ui/screen/loggedIn/search/SearchScreen.kt | 31 ++++--------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt index ed1ed0017..028b9eec3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.search +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.runtime.Stable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -87,8 +88,10 @@ class SearchBarViewModel( val searchDataSourceState = SearchQueryState(MutableStateFlow(searchValue), account) + val listState: LazyListState = LazyListState(0, 0) + val directNip05Resolver: Flow = - searchValueFlow + searchTerm .debounce(400) .mapLatest { term -> if (term.contains('@')) { @@ -248,11 +251,12 @@ class SearchBarViewModel( fun clear() = updateSearchValue("") - fun updateDataSource(searchTerm: String) { + suspend fun updateDataSource(searchTerm: String) { if (searchTerm.isBlank()) { searchDataSourceState.searchQuery.tryEmit("") } else { searchDataSourceState.searchQuery.tryEmit(searchTerm) + listState.scrollToItem(0, 0) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt index f61421bed..68d952c01 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt @@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions @@ -58,9 +57,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.service.relayClient.searchCommand.TextSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel -import com.vitorpamplona.amethyst.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar import com.vitorpamplona.amethyst.ui.navigation.navs.INav @@ -109,16 +106,16 @@ fun SearchScreen( ) { WatchLifecycleAndUpdateModel(searchBarViewModel) - val listState = rememberForeverLazyListState(ScrollStateKeys.SEARCH_SCREEN) - LaunchedEffect(searchBarViewModel.focusRequester) { - searchBarViewModel.focusRequester.requestFocus() + if (searchBarViewModel.listState.firstVisibleItemIndex == 0) { + searchBarViewModel.focusRequester.requestFocus() + } } DisappearingScaffold( isInvertedLayout = false, topBar = { - SearchBar(searchBarViewModel, listState, accountViewModel, nav) + SearchBar(searchBarViewModel, accountViewModel, nav) }, bottomBar = { AppBottomBar(Route.Search, accountViewModel) { route -> @@ -131,7 +128,7 @@ fun SearchScreen( modifier = Modifier.padding(it).consumeWindowInsets(it), ) { ObserveRelayListForSearchAndDisplayIfNotFound(accountViewModel, nav) - DisplaySearchResults(searchBarViewModel, listState, nav, accountViewModel) + DisplaySearchResults(searchBarViewModel, nav, accountViewModel) } } } @@ -140,7 +137,6 @@ fun SearchScreen( @Composable private fun SearchBar( searchBarViewModel: SearchBarViewModel, - listState: LazyListState, accountViewModel: AccountViewModel, nav: INav, ) { @@ -164,23 +160,9 @@ private fun SearchBar( } } - AnimateOnNewSearch(searchBarViewModel, listState) - SearchTextField(searchBarViewModel, Modifier.statusBarsPadding()) } -@Composable -fun AnimateOnNewSearch( - searchBarViewModel: SearchBarViewModel, - listState: LazyListState, -) { - val searchTerm by searchBarViewModel.searchTerm.collectAsStateWithLifecycle() - - LaunchedEffect(searchTerm) { - listState.animateScrollToItem(0) - } -} - @Composable private fun SearchTextField( searchBarViewModel: SearchBarViewModel, @@ -237,7 +219,6 @@ private fun SearchTextField( @Composable private fun DisplaySearchResults( searchBarViewModel: SearchBarViewModel, - listState: LazyListState, nav: INav, accountViewModel: AccountViewModel, ) { @@ -256,7 +237,7 @@ private fun DisplaySearchResults( LazyColumn( modifier = Modifier.fillMaxHeight(), contentPadding = FeedPadding, - state = listState, + state = searchBarViewModel.listState, ) { itemsIndexed( hashTags,