diff --git a/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsScreen.kt b/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsScreen.kt index 689b5bbf0..b70934eea 100644 --- a/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsScreen.kt +++ b/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsScreen.kt @@ -47,8 +47,6 @@ fun InterestsScreen( uiState = uiState, followTopic = viewModel::followTopic, onTopicClick = { - // TODO: this violates SSOT, events should go through the ViewModel - viewModel.onTopicClick(it) onTopicClick(it) }, shouldHighlightSelectedTopic = shouldHighlightSelectedTopic, diff --git a/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsViewModel.kt b/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsViewModel.kt index f79d79d09..7bf709b3e 100644 --- a/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsViewModel.kt +++ b/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/InterestsViewModel.kt @@ -16,14 +16,16 @@ package com.google.samples.apps.nowinandroid.feature.interests.impl -import androidx.lifecycle.SavedStateHandle +import androidx.compose.runtime.snapshotFlow import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase import com.google.samples.apps.nowinandroid.core.domain.TopicSortField import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic +import com.google.samples.apps.nowinandroid.core.navigation.NavigationState import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsNavKey +import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.TopicNavKey import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -36,22 +38,23 @@ import kotlinx.coroutines.launch @HiltViewModel(assistedFactory = InterestsViewModel.Factory::class) class InterestsViewModel @AssistedInject constructor( - private val savedStateHandle: SavedStateHandle, val userDataRepository: UserDataRepository, getFollowableTopics: GetFollowableTopicsUseCase, - // TODO: see comment below + @Assisted val navigationState: NavigationState, @Assisted val key: InterestsNavKey, ) : ViewModel() { - // TODO: this should no longer be necessary, the currently selected topic should be - // available through the navigation state - // Key used to save and retrieve the currently selected topic id from saved state. - private val selectedTopicIdKey = "selectedTopicIdKey" - - private val selectedTopicId = savedStateHandle.getStateFlow( - key = selectedTopicIdKey, - initialValue = key.initialTopicId, - ) + // Derive selected topic from navigation state + private val selectedTopicId: StateFlow = + snapshotFlow { + navigationState.currentSubStack + .lastOrNull { it is TopicNavKey } + ?.let { (it as TopicNavKey).id } + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = key.initialTopicId, + ) val uiState: StateFlow = combine( selectedTopicId, @@ -69,15 +72,9 @@ class InterestsViewModel @AssistedInject constructor( } } - fun onTopicClick(topicId: String?) { - // TODO: This should modify the navigation state directly rather than just updating the - // savedStateHandle - savedStateHandle[selectedTopicIdKey] = topicId - } - @AssistedFactory interface Factory { - fun create(key: InterestsNavKey): InterestsViewModel + fun create(navigationState: NavigationState, key: InterestsNavKey): InterestsViewModel } } diff --git a/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/navigation/InterestsEntryProvider.kt b/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/navigation/InterestsEntryProvider.kt index b92f462eb..f61b2870b 100644 --- a/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/navigation/InterestsEntryProvider.kt +++ b/feature/interests/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/impl/navigation/InterestsEntryProvider.kt @@ -36,7 +36,7 @@ fun EntryProviderScope.interestsEntry(navigator: Navigator) { }, ) { key -> val viewModel = hiltViewModel { - it.create(key) + it.create(navigator.state, key) } InterestsScreen( // TODO: This event should either be provided by the ViewModel or by the navigator, not both diff --git a/feature/interests/impl/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/impl/InterestsViewModelTest.kt b/feature/interests/impl/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/impl/InterestsViewModelTest.kt index 4e964b52b..6eb4d36e5 100644 --- a/feature/interests/impl/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/impl/InterestsViewModelTest.kt +++ b/feature/interests/impl/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/impl/InterestsViewModelTest.kt @@ -16,17 +16,18 @@ package com.google.samples.apps.nowinandroid.interests.impl -import androidx.lifecycle.SavedStateHandle -import androidx.navigation.testing.invoke +import androidx.navigation3.runtime.NavBackStack import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.Topic +import com.google.samples.apps.nowinandroid.core.navigation.NavigationState import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsNavKey import com.google.samples.apps.nowinandroid.feature.interests.impl.InterestsUiState import com.google.samples.apps.nowinandroid.feature.interests.impl.InterestsViewModel +import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.TopicNavKey import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -66,13 +67,23 @@ class InterestsViewModelTest { @Before fun setup() { + val initialTopicId = testInputTopics[0].topic.id + val interestsKey = InterestsNavKey(initialTopicId = initialTopicId) + viewModel = InterestsViewModel( - savedStateHandle = SavedStateHandle( - route = InterestsNavKey(initialTopicId = testInputTopics[0].topic.id), - ), userDataRepository = userDataRepository, getFollowableTopics = getFollowableTopicsUseCase, - InterestsNavKey(initialTopicId = testInputTopics[0].topic.id), + navigationState = NavigationState( + startKey = interestsKey, + topLevelStack = NavBackStack(interestsKey), + subStacks = mapOf( + interestsKey to NavBackStack( + interestsKey, + TopicNavKey(id = initialTopicId), // Add TopicNavKey to the sub-stack + ), + ), + ), + key = interestsKey, ) }