From 9b83e060b16f12be6734ed45ce3bcf114478901b Mon Sep 17 00:00:00 2001 From: Alex Vanyo Date: Thu, 12 Dec 2024 17:30:20 -0800 Subject: [PATCH] Assisted inject approach Change-Id: I5fba15921520bc83b13601fa82ae71457d875805 --- .../InterestsListDetailScreen.kt | 58 ++++++++----------- .../feature/topic/TopicViewModel.kt | 23 ++++---- gradle/libs.versions.toml | 2 +- 3 files changed, 38 insertions(+), 45 deletions(-) diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt index 93ed303b8..c33b1611b 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt @@ -18,6 +18,7 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane import androidx.activity.compose.BackHandler import androidx.annotation.Keep +import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.material3.LocalMinimumInteractiveComponentSize @@ -50,6 +51,7 @@ import androidx.compose.ui.layout.layout import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.viewModelFactory import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -57,6 +59,9 @@ import androidx.navigation.compose.rememberNavController import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsRoute import com.google.samples.apps.nowinandroid.feature.topic.TopicDetailPlaceholder +import com.google.samples.apps.nowinandroid.feature.topic.TopicScreen +import com.google.samples.apps.nowinandroid.feature.topic.TopicViewModel +import com.google.samples.apps.nowinandroid.feature.topic.TopicViewModel_Factory import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicRoute import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen @@ -126,28 +131,10 @@ internal fun InterestsListDetailScreen( val route = selectedTopicId?.let { TopicRoute(id = it) } ?: TopicPlaceholderRoute mutableStateOf(route) } - var nestedNavKey by rememberSaveable( - stateSaver = Saver({ it.toString() }, UUID::fromString), - ) { - mutableStateOf(UUID.randomUUID()) - } - val nestedNavController = key(nestedNavKey) { - rememberNavController() - } fun onTopicClickShowDetailPane(topicId: String) { onTopicClick(topicId) - if (listDetailNavigator.isDetailPaneVisible()) { - // If the detail pane was visible, then use the nestedNavController navigate call - // directly - nestedNavController.navigateToTopic(topicId) { - popUpTo() - } - } else { - // Otherwise, recreate the NavHost entirely, and start at the new destination - nestedNavHostStartRoute = TopicRoute(id = topicId) - nestedNavKey = UUID.randomUUID() - } + nestedNavHostStartRoute = TopicRoute(id = topicId) coroutineScope.launch { listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail) } @@ -207,22 +194,25 @@ internal fun InterestsListDetailScreen( } }, ) { - key(nestedNavKey) { - NavHost( - navController = nestedNavController, - startDestination = nestedNavHostStartRoute, - route = DetailPaneNavHostRoute::class, - ) { - topicScreen( - showBackButton = !listDetailNavigator.isListPaneVisible(), - onBackClick = { - coroutineScope.launch { - listDetailNavigator.navigateBack() + AnimatedContent(nestedNavHostStartRoute) { route -> + when (route) { + is TopicRoute -> { + TopicScreen( + showBackButton = !listDetailNavigator.isListPaneVisible(), + onBackClick = { + coroutineScope.launch { + listDetailNavigator.navigateBack() + } + }, + onTopicClick = ::onTopicClickShowDetailPane, + viewModel = hiltViewModel( + key = route.id, + ) { factory -> + factory.create(route.id) } - }, - onTopicClick = ::onTopicClickShowDetailPane, - ) - composable { + ) + } + is TopicPlaceholderRoute -> { TopicDetailPlaceholder() } } diff --git a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt index ba8baad14..8865da463 100644 --- a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt +++ b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt @@ -16,10 +16,8 @@ package com.google.samples.apps.nowinandroid.feature.topic -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.navigation.toRoute import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQuery import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository @@ -29,7 +27,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource 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.topic.navigation.TopicRoute +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -38,18 +38,14 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import javax.inject.Inject -@HiltViewModel -class TopicViewModel @Inject constructor( - savedStateHandle: SavedStateHandle, +@HiltViewModel(assistedFactory = TopicViewModel.Factory::class) +class TopicViewModel @AssistedInject constructor( private val userDataRepository: UserDataRepository, topicsRepository: TopicsRepository, userNewsResourceRepository: UserNewsResourceRepository, + @Assisted val topicId: String, ) : ViewModel() { - - val topicId = savedStateHandle.toRoute().id - val topicUiState: StateFlow = topicUiState( topicId = topicId, userDataRepository = userDataRepository, @@ -89,6 +85,13 @@ class TopicViewModel @Inject constructor( userDataRepository.setNewsResourceViewed(newsResourceId, viewed) } } + + @AssistedFactory + interface Factory { + fun create( + topicId: String, + ): TopicViewModel + } } private fun topicUiState( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f0e2a2b9b..9417d9129 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ androidxHiltNavigationCompose = "1.2.0" androidxLifecycle = "2.8.7" androidxMacroBenchmark = "1.3.3" androidxMetrics = "1.0.0-beta01" -androidxNavigation = "2.8.4" +androidxNavigation = "2.8.5" androidxProfileinstaller = "1.4.1" androidxTestCore = "1.6.1" androidxTestExt = "1.2.1"