From 4080189752c752046ba2dc62728b696104a91fff Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Tue, 22 Aug 2023 10:37:25 +0700 Subject: [PATCH 1/5] replace object with data object in search feature, simple format code for the reader --- .../search/RecentSearchQueriesUiState.kt | 2 +- .../feature/search/SearchResultUiState.kt | 6 +- .../feature/search/SearchScreen.kt | 20 ++---- .../feature/search/SearchViewModel.kt | 67 +++++++++---------- 4 files changed, 38 insertions(+), 57 deletions(-) diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/RecentSearchQueriesUiState.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/RecentSearchQueriesUiState.kt index 8628d2e54..8aa5bb3b8 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/RecentSearchQueriesUiState.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/RecentSearchQueriesUiState.kt @@ -19,7 +19,7 @@ package com.google.samples.apps.nowinandroid.feature.search import com.google.samples.apps.nowinandroid.core.data.model.RecentSearchQuery sealed interface RecentSearchQueriesUiState { - object Loading : RecentSearchQueriesUiState + data object Loading : RecentSearchQueriesUiState data class Success( val recentQueries: List = emptyList(), diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt index 68ea623e8..2bf5d0531 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt @@ -20,14 +20,14 @@ import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource sealed interface SearchResultUiState { - object Loading : SearchResultUiState + data object Loading : SearchResultUiState /** * The state query is empty or too short. To distinguish the state between the * (initial state or when the search query is cleared) vs the state where no search * result is returned, explicitly define the empty query state. */ - object EmptyQuery : SearchResultUiState + data object EmptyQuery : SearchResultUiState object LoadFailed : SearchResultUiState @@ -42,5 +42,5 @@ sealed interface SearchResultUiState { * A state where the search contents are not ready. This happens when the *Fts tables are not * populated yet. */ - object SearchNotReady : SearchResultUiState + data object SearchNotReady : SearchResultUiState } diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt index fede7766b..42aa76295 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt @@ -312,11 +312,7 @@ private fun SearchResultBody( state = state, ) { if (topics.isNotEmpty()) { - item( - span = { - GridItemSpan(maxLineSpan) - }, - ) { + item(span = { GridItemSpan(maxLineSpan) }) { Text( text = buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { @@ -330,9 +326,7 @@ private fun SearchResultBody( val topicId = followableTopic.topic.id item( key = "topic-$topicId", // Append a prefix to distinguish a key for news resources - span = { - GridItemSpan(maxLineSpan) - }, + span = { GridItemSpan(maxLineSpan) }, ) { InterestsItem( name = followableTopic.topic.name, @@ -351,11 +345,7 @@ private fun SearchResultBody( } if (newsResources.isNotEmpty()) { - item( - span = { - GridItemSpan(maxLineSpan) - }, - ) { + item(span = { GridItemSpan(maxLineSpan) }) { Text( text = buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { @@ -440,9 +430,7 @@ private fun RecentSearchesBody( style = MaterialTheme.typography.headlineSmall, modifier = Modifier .padding(vertical = 16.dp) - .clickable { - onRecentSearchClicked(recentSearch) - } + .clickable { onRecentSearchClicked(recentSearch) } .fillMaxWidth(), ) } diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt index f5b409edf..4cfb5e60c 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt @@ -51,43 +51,41 @@ class SearchViewModel @Inject constructor( val searchQuery = savedStateHandle.getStateFlow(SEARCH_QUERY, "") val searchResultUiState: StateFlow = - getSearchContentsCountUseCase().flatMapLatest { totalCount -> - if (totalCount < SEARCH_MIN_FTS_ENTITY_COUNT) { - flowOf(SearchResultUiState.SearchNotReady) - } else { - searchQuery.flatMapLatest { query -> - if (query.length < SEARCH_QUERY_MIN_LENGTH) { - flowOf(SearchResultUiState.EmptyQuery) - } else { - getSearchContentsUseCase(query).asResult().map { - when (it) { - is Result.Success -> { - SearchResultUiState.Success( - topics = it.data.topics, - newsResources = it.data.newsResources, - ) - } - - is Result.Loading -> { - SearchResultUiState.Loading - } + getSearchContentsCountUseCase() + .flatMapLatest { totalCount -> + if (totalCount < SEARCH_MIN_FTS_ENTITY_COUNT) { + flowOf(SearchResultUiState.SearchNotReady) + } else { + searchQuery.flatMapLatest { query -> + if (query.length < SEARCH_QUERY_MIN_LENGTH) { + flowOf(SearchResultUiState.EmptyQuery) + } else { + getSearchContentsUseCase(query) + .asResult() + .map { result -> + when (result) { + is Result.Success -> SearchResultUiState.Success( + topics = result.data.topics, + newsResources = result.data.newsResources, + ) - is Result.Error -> { - SearchResultUiState.LoadFailed + is Result.Loading -> SearchResultUiState.Loading + is Result.Error -> SearchResultUiState.LoadFailed + } } - } } } } } - }.stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = SearchResultUiState.Loading, - ) + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = SearchResultUiState.Loading, + ) val recentSearchQueriesUiState: StateFlow = - recentSearchQueriesUseCase().map(RecentSearchQueriesUiState::Success) + recentSearchQueriesUseCase() + .map(RecentSearchQueriesUiState::Success) .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), @@ -109,14 +107,9 @@ class SearchViewModel @Inject constructor( viewModelScope.launch { recentSearchRepository.insertOrReplaceRecentSearch(query) } - analyticsHelper.logEvent( - AnalyticsEvent( - type = SEARCH_QUERY, - extras = listOf( - Param(SEARCH_QUERY, query), - ), - ), - ) + val eventExtras = listOf(element = Param(key = SEARCH_QUERY, value = query)) + val analyticsEvent = AnalyticsEvent(type = SEARCH_QUERY, extras = eventExtras) + analyticsHelper.logEvent(event = analyticsEvent) } fun clearRecentSearches() { From 70a0a542d536b74b6daca713feead3b75f2ad25a Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Tue, 22 Aug 2023 11:05:18 +0700 Subject: [PATCH 2/5] replace object with data object in search feature, simple format code for the reader --- .../apps/nowinandroid/feature/search/SearchResultUiState.kt | 2 +- .../apps/nowinandroid/feature/search/SearchViewModel.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt index 2bf5d0531..aaf7dba7d 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchResultUiState.kt @@ -29,7 +29,7 @@ sealed interface SearchResultUiState { */ data object EmptyQuery : SearchResultUiState - object LoadFailed : SearchResultUiState + data object LoadFailed : SearchResultUiState data class Success( val topics: List = emptyList(), diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt index 4cfb5e60c..8d9771fbf 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt @@ -76,8 +76,7 @@ class SearchViewModel @Inject constructor( } } } - } - .stateIn( + }.stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = SearchResultUiState.Loading, From 62d4f3175b74e8343de92d21be75cb5dab3b8a52 Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Tue, 22 Aug 2023 11:27:10 +0700 Subject: [PATCH 3/5] separate function logEvent for search triggered --- .../nowinandroid/feature/search/SearchViewModel.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt index 8d9771fbf..2a5b3ece0 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt @@ -28,6 +28,7 @@ import com.google.samples.apps.nowinandroid.core.domain.GetSearchContentsCountUs import com.google.samples.apps.nowinandroid.core.domain.GetSearchContentsUseCase import com.google.samples.apps.nowinandroid.core.result.Result import com.google.samples.apps.nowinandroid.core.result.asResult +import com.google.samples.apps.nowinandroid.feature.foryou.navigation.LINKED_NEWS_RESOURCE_ID import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -106,9 +107,7 @@ class SearchViewModel @Inject constructor( viewModelScope.launch { recentSearchRepository.insertOrReplaceRecentSearch(query) } - val eventExtras = listOf(element = Param(key = SEARCH_QUERY, value = query)) - val analyticsEvent = AnalyticsEvent(type = SEARCH_QUERY, extras = eventExtras) - analyticsHelper.logEvent(event = analyticsEvent) + analyticsHelper.logEventSearchTriggered(query = query) } fun clearRecentSearches() { @@ -118,6 +117,14 @@ class SearchViewModel @Inject constructor( } } +private fun AnalyticsHelper.logEventSearchTriggered(query: String) = + logEvent( + event = AnalyticsEvent( + type = SEARCH_QUERY, + extras = listOf(element = Param(key = SEARCH_QUERY, value = query)), + ), + ) + /** Minimum length where search query is considered as [SearchResultUiState.EmptyQuery] */ private const val SEARCH_QUERY_MIN_LENGTH = 2 From f6a36e1f6691c0ddeb3859f3733a6bf219cfe474 Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Tue, 22 Aug 2023 11:30:40 +0700 Subject: [PATCH 4/5] separate function logEvent for search triggered --- .../apps/nowinandroid/feature/search/SearchViewModel.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt index 2a5b3ece0..6dd93ceb6 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchViewModel.kt @@ -28,7 +28,6 @@ import com.google.samples.apps.nowinandroid.core.domain.GetSearchContentsCountUs import com.google.samples.apps.nowinandroid.core.domain.GetSearchContentsUseCase import com.google.samples.apps.nowinandroid.core.result.Result import com.google.samples.apps.nowinandroid.core.result.asResult -import com.google.samples.apps.nowinandroid.feature.foryou.navigation.LINKED_NEWS_RESOURCE_ID import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -49,7 +48,7 @@ class SearchViewModel @Inject constructor( private val analyticsHelper: AnalyticsHelper, ) : ViewModel() { - val searchQuery = savedStateHandle.getStateFlow(SEARCH_QUERY, "") + val searchQuery = savedStateHandle.getStateFlow(key = SEARCH_QUERY, initialValue = "") val searchResultUiState: StateFlow = getSearchContentsCountUseCase() @@ -105,7 +104,7 @@ class SearchViewModel @Inject constructor( */ fun onSearchTriggered(query: String) { viewModelScope.launch { - recentSearchRepository.insertOrReplaceRecentSearch(query) + recentSearchRepository.insertOrReplaceRecentSearch(searchQuery = query) } analyticsHelper.logEventSearchTriggered(query = query) } From 42895e06a8aa66bf979e92fe0435db5770ed89f0 Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Wed, 23 Aug 2023 09:33:46 +0700 Subject: [PATCH 5/5] format modification for screen search --- .../nowinandroid/feature/search/SearchScreen.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt index 42aa76295..2a6117f6b 100644 --- a/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt +++ b/feature/search/src/main/java/com/google/samples/apps/nowinandroid/feature/search/SearchScreen.kt @@ -312,7 +312,11 @@ private fun SearchResultBody( state = state, ) { if (topics.isNotEmpty()) { - item(span = { GridItemSpan(maxLineSpan) }) { + item( + span = { + GridItemSpan(maxLineSpan) + }, + ) { Text( text = buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { @@ -326,7 +330,9 @@ private fun SearchResultBody( val topicId = followableTopic.topic.id item( key = "topic-$topicId", // Append a prefix to distinguish a key for news resources - span = { GridItemSpan(maxLineSpan) }, + span = { + GridItemSpan(maxLineSpan) + }, ) { InterestsItem( name = followableTopic.topic.name, @@ -345,7 +351,11 @@ private fun SearchResultBody( } if (newsResources.isNotEmpty()) { - item(span = { GridItemSpan(maxLineSpan) }) { + item( + span = { + GridItemSpan(maxLineSpan) + }, + ) { Text( text = buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {