Assisted inject approach

Change-Id: I5fba15921520bc83b13601fa82ae71457d875805
av/material3-adaptive-1.1
Alex Vanyo 1 month ago
parent 89c408b5c4
commit 9b83e060b1

@ -18,6 +18,7 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.LocalMinimumInteractiveComponentSize
@ -50,6 +51,7 @@ import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.viewModelFactory
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable 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.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.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.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.TopicRoute
import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen 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 val route = selectedTopicId?.let { TopicRoute(id = it) } ?: TopicPlaceholderRoute
mutableStateOf(route) mutableStateOf(route)
} }
var nestedNavKey by rememberSaveable(
stateSaver = Saver({ it.toString() }, UUID::fromString),
) {
mutableStateOf(UUID.randomUUID())
}
val nestedNavController = key(nestedNavKey) {
rememberNavController()
}
fun onTopicClickShowDetailPane(topicId: String) { fun onTopicClickShowDetailPane(topicId: String) {
onTopicClick(topicId) onTopicClick(topicId)
if (listDetailNavigator.isDetailPaneVisible()) { nestedNavHostStartRoute = TopicRoute(id = topicId)
// If the detail pane was visible, then use the nestedNavController navigate call
// directly
nestedNavController.navigateToTopic(topicId) {
popUpTo<DetailPaneNavHostRoute>()
}
} else {
// Otherwise, recreate the NavHost entirely, and start at the new destination
nestedNavHostStartRoute = TopicRoute(id = topicId)
nestedNavKey = UUID.randomUUID()
}
coroutineScope.launch { coroutineScope.launch {
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail) listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
} }
@ -207,22 +194,25 @@ internal fun InterestsListDetailScreen(
} }
}, },
) { ) {
key(nestedNavKey) { AnimatedContent(nestedNavHostStartRoute) { route ->
NavHost( when (route) {
navController = nestedNavController, is TopicRoute -> {
startDestination = nestedNavHostStartRoute, TopicScreen(
route = DetailPaneNavHostRoute::class, showBackButton = !listDetailNavigator.isListPaneVisible(),
) { onBackClick = {
topicScreen( coroutineScope.launch {
showBackButton = !listDetailNavigator.isListPaneVisible(), listDetailNavigator.navigateBack()
onBackClick = { }
coroutineScope.launch { },
listDetailNavigator.navigateBack() onTopicClick = ::onTopicClickShowDetailPane,
viewModel = hiltViewModel<TopicViewModel, TopicViewModel.Factory>(
key = route.id,
) { factory ->
factory.create(route.id)
} }
}, )
onTopicClick = ::onTopicClickShowDetailPane, }
) is TopicPlaceholderRoute -> {
composable<TopicPlaceholderRoute> {
TopicDetailPlaceholder() TopicDetailPlaceholder()
} }
} }

@ -16,10 +16,8 @@
package com.google.samples.apps.nowinandroid.feature.topic package com.google.samples.apps.nowinandroid.feature.topic
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope 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.NewsResourceQuery
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository 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.model.data.UserNewsResource
import com.google.samples.apps.nowinandroid.core.result.Result import com.google.samples.apps.nowinandroid.core.result.Result
import com.google.samples.apps.nowinandroid.core.result.asResult 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 dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@ -38,18 +38,14 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel @HiltViewModel(assistedFactory = TopicViewModel.Factory::class)
class TopicViewModel @Inject constructor( class TopicViewModel @AssistedInject constructor(
savedStateHandle: SavedStateHandle,
private val userDataRepository: UserDataRepository, private val userDataRepository: UserDataRepository,
topicsRepository: TopicsRepository, topicsRepository: TopicsRepository,
userNewsResourceRepository: UserNewsResourceRepository, userNewsResourceRepository: UserNewsResourceRepository,
@Assisted val topicId: String,
) : ViewModel() { ) : ViewModel() {
val topicId = savedStateHandle.toRoute<TopicRoute>().id
val topicUiState: StateFlow<TopicUiState> = topicUiState( val topicUiState: StateFlow<TopicUiState> = topicUiState(
topicId = topicId, topicId = topicId,
userDataRepository = userDataRepository, userDataRepository = userDataRepository,
@ -89,6 +85,13 @@ class TopicViewModel @Inject constructor(
userDataRepository.setNewsResourceViewed(newsResourceId, viewed) userDataRepository.setNewsResourceViewed(newsResourceId, viewed)
} }
} }
@AssistedFactory
interface Factory {
fun create(
topicId: String,
): TopicViewModel
}
} }
private fun topicUiState( private fun topicUiState(

@ -18,7 +18,7 @@ androidxHiltNavigationCompose = "1.2.0"
androidxLifecycle = "2.8.7" androidxLifecycle = "2.8.7"
androidxMacroBenchmark = "1.3.3" androidxMacroBenchmark = "1.3.3"
androidxMetrics = "1.0.0-beta01" androidxMetrics = "1.0.0-beta01"
androidxNavigation = "2.8.4" androidxNavigation = "2.8.5"
androidxProfileinstaller = "1.4.1" androidxProfileinstaller = "1.4.1"
androidxTestCore = "1.6.1" androidxTestCore = "1.6.1"
androidxTestExt = "1.2.1" androidxTestExt = "1.2.1"

Loading…
Cancel
Save