app: simplify ArticlesSearchScreen by using a new destination for each query
authorDa Risk <da_risk@geekorum.com>
Mon, 25 Mar 2024 21:39:04 -0400
changeset 1227 7579ac9ae3d3
parent 1226 044cf0eb5c39
child 1228 d79b184243d8
app: simplify ArticlesSearchScreen by using a new destination for each query
app/src/main/java/com/geekorum/ttrss/articles_list/ActivityViewModel.kt
app/src/main/java/com/geekorum/ttrss/articles_list/AppBarPresenter.kt
app/src/main/java/com/geekorum/ttrss/articles_list/Navigation.kt
app/src/main/java/com/geekorum/ttrss/articles_list/search/ArticlesSearchScreen.kt
app/src/main/java/com/geekorum/ttrss/articles_list/search/SearchViewModel.kt
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/ActivityViewModel.kt	Mon Mar 25 19:56:55 2024 -0400
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/ActivityViewModel.kt	Mon Mar 25 21:39:04 2024 -0400
@@ -52,9 +52,6 @@
     private val _articleSelectedEvent = MutableLiveData<Event<ArticleSelectedParameters>>()
     val articleSelectedEvent: LiveData<Event<ArticleSelectedParameters>> = _articleSelectedEvent
 
-    private val _searchQuery = MutableStateFlow("")
-    val searchQuery = _searchQuery.asStateFlow()
-
     private val _refreshClickedEvent = MutableLiveData<Event<Any>>()
     val refreshClickedEvent: LiveData<Event<Any>> = _refreshClickedEvent
 
@@ -123,10 +120,6 @@
         browserLauncher.launchUrl(context, article.link.toUri())
     }
 
-    fun setSearchQuery(query: String) {
-        _searchQuery.value = query
-    }
-
     fun recordSearchQueryInHistory(query: String) = viewModelScope.launch {
         try {
             delayHistoryUpdate = true
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/AppBarPresenter.kt	Mon Mar 25 19:56:55 2024 -0400
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/AppBarPresenter.kt	Mon Mar 25 21:39:04 2024 -0400
@@ -85,12 +85,6 @@
         )
 
         val isSearchOpen = currentDestination != null && currentDestination?.destination?.route == NavRoutes.Search
-        val isNotOnSearchDestination = currentDestination != null && currentDestination?.destination?.route != NavRoutes.Search
-        if (isNotOnSearchDestination) {
-            LaunchedEffect(Unit) {
-                activityViewModel.setSearchQuery("")
-            }
-        }
 
         val searchScreenTransition = updateTransition(targetState = isSearchOpen, label = "show search")
         SideEffect {
@@ -129,9 +123,9 @@
                     },
                     suggestions = suggestions,
                     onSearch = {
-                        activityViewModel.setSearchQuery(it)
                         activityViewModel.recordSearchQueryInHistory(it)
                         hasSearched = true
+                        navController.navigateToSearch(it)
                     },
                     onUpClick = { navController.popBackStack() },
                     modifier = Modifier
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/Navigation.kt	Mon Mar 25 19:56:55 2024 -0400
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/Navigation.kt	Mon Mar 25 21:39:04 2024 -0400
@@ -47,7 +47,7 @@
     const val Magazine = "magazine"
     const val ArticlesList = "feeds/{feed_id}?feed_name={feed_name}"
     const val ArticlesListByTag = "tags/{tag}"
-    const val Search = "search"
+    const val Search = "search?query={query}"
 
     fun getLabelForRoute(context: Context, route: String?) = when(route) {
         Magazine -> context.getString(R.string.title_magazine)
@@ -109,7 +109,12 @@
                 windowSizeClass = windowSizeClass, contentPadding = contentPadding)
         }
 
-        composable(NavRoutes.Search) {
+        composable(NavRoutes.Search,
+            arguments = listOf(navArgument("query") {
+                nullable = false
+                defaultValue = ""
+            })
+        ) {
             ArticlesSearchScreen(activityViewModel = activityViewModel, windowSizeClass = windowSizeClass)
         }
     }
@@ -159,9 +164,12 @@
     context.startActivity(intent)
 }
 
-
-fun NavController.navigateToSearch() {
-    navigate(NavRoutes.Search)
+fun NavController.navigateToSearch(query: String = "") {
+    navigate("search?query=$query", navOptions = navOptions {
+        popUpTo(NavRoutes.Search) {
+            inclusive = true
+        }
+    })
 }
 
 fun NavController.navigateToManageFeeds() {
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/search/ArticlesSearchScreen.kt	Mon Mar 25 19:56:55 2024 -0400
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/search/ArticlesSearchScreen.kt	Mon Mar 25 21:39:04 2024 -0400
@@ -207,12 +207,6 @@
     activityViewModel: ActivityViewModel,
     searchViewModel: SearchViewModel = hiltViewModel(),
 ) {
-    LaunchedEffect(activityViewModel, searchViewModel) {
-        activityViewModel.searchQuery.collect {
-            searchViewModel.setSearchQuery(it)
-        }
-    }
-
     val compactItemsInSmallScreens by activityViewModel.displayCompactItems.collectAsStateWithLifecycle()
     val displayCompactItems = compactItemsInSmallScreens
             && (windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/search/SearchViewModel.kt	Mon Mar 25 19:56:55 2024 -0400
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/search/SearchViewModel.kt	Mon Mar 25 21:39:04 2024 -0400
@@ -20,25 +20,25 @@
  */
 package com.geekorum.ttrss.articles_list.search
 
-import androidx.annotation.MainThread
+import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import androidx.paging.Pager
 import androidx.paging.PagingConfig
 import androidx.paging.PagingData
+import androidx.paging.cachedIn
 import com.geekorum.ttrss.articles_list.ArticlesRepository
 import com.geekorum.ttrss.data.ArticleWithFeed
 import com.geekorum.ttrss.session.SessionActivityComponent
 import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flatMapLatest
 import javax.inject.Inject
 
-@OptIn(ExperimentalCoroutinesApi::class)
+private val ARG_QUERY = "query"
+
 @HiltViewModel
 class SearchViewModel @Inject constructor(
+    savedStateHandle: SavedStateHandle,
     componentFactory: SessionActivityComponent.Factory
 ) : ViewModel() {
 
@@ -46,18 +46,11 @@
     private val articlesRepository: ArticlesRepository = sessionActivityComponent.articleRepository
     private val setFieldActionFactory = sessionActivityComponent.setArticleFieldActionFactory
 
-    private val searchQuery = MutableStateFlow("")
-
-    val articles: Flow<PagingData<ArticleWithFeed>> = searchQuery.flatMapLatest {
-        Pager(PagingConfig(pageSize = 50)) {
-            articlesRepository.searchArticles(it)
-        }.flow
-    }
-
-    @MainThread
-    fun setSearchQuery(keyword: String) {
-        searchQuery.value = keyword
-    }
+    val articles: Flow<PagingData<ArticleWithFeed>> = Pager(PagingConfig(pageSize = 50)) {
+        val searchQuery = savedStateHandle.get<String>(ARG_QUERY)!!
+        articlesRepository.searchArticles(searchQuery)
+    }.flow
+        .cachedIn(viewModelScope)
 
     fun setArticleStarred(articleId: Long, newValue: Boolean) {
         val action = setFieldActionFactory.createSetStarredAction(viewModelScope, articleId, newValue)