|
|
|
@ -17,46 +17,24 @@
|
|
|
|
|
package com.google.samples.apps.nowinandroid.ui.interests2pane
|
|
|
|
|
|
|
|
|
|
import androidx.activity.compose.BackHandler
|
|
|
|
|
import androidx.annotation.Keep
|
|
|
|
|
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
|
|
|
|
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
|
|
|
|
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
|
|
|
|
import androidx.compose.material3.adaptive.layout.AnimatedPane
|
|
|
|
|
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
|
|
|
|
|
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
|
|
|
|
|
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
|
|
|
|
|
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem
|
|
|
|
|
import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective
|
|
|
|
|
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
|
|
|
|
|
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
|
import androidx.compose.runtime.key
|
|
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
|
|
import androidx.compose.runtime.remember
|
|
|
|
|
import androidx.compose.runtime.saveable.Saver
|
|
|
|
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
|
|
|
import androidx.compose.runtime.setValue
|
|
|
|
|
import androidx.hilt.navigation.compose.hiltViewModel
|
|
|
|
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
|
|
|
import androidx.navigation.NavGraphBuilder
|
|
|
|
|
import androidx.navigation.compose.NavHost
|
|
|
|
|
import androidx.navigation.compose.composable
|
|
|
|
|
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.navigation.TopicRoute
|
|
|
|
|
import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic
|
|
|
|
|
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen
|
|
|
|
|
import kotlinx.serialization.Serializable
|
|
|
|
|
import java.util.UUID
|
|
|
|
|
|
|
|
|
|
@Serializable internal object TopicPlaceholderRoute
|
|
|
|
|
|
|
|
|
|
// TODO: Remove @Keep when https://issuetracker.google.com/353898971 is fixed
|
|
|
|
|
@Keep
|
|
|
|
|
@Serializable internal object DetailPaneNavHostRoute
|
|
|
|
|
import com.google.samples.apps.nowinandroid.feature.topic.TopicScreen
|
|
|
|
|
|
|
|
|
|
fun NavGraphBuilder.interestsListDetailScreen() {
|
|
|
|
|
composable<InterestsRoute> {
|
|
|
|
@ -64,31 +42,16 @@ fun NavGraphBuilder.interestsListDetailScreen() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
internal fun InterestsListDetailScreen(
|
|
|
|
|
viewModel: Interests2PaneViewModel = hiltViewModel(),
|
|
|
|
|
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(),
|
|
|
|
|
) {
|
|
|
|
|
val selectedTopicId by viewModel.selectedTopicId.collectAsStateWithLifecycle()
|
|
|
|
|
InterestsListDetailScreen(
|
|
|
|
|
selectedTopicId = selectedTopicId,
|
|
|
|
|
onTopicClick = viewModel::onTopicClick,
|
|
|
|
|
windowAdaptiveInfo = windowAdaptiveInfo,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
|
|
|
|
@Composable
|
|
|
|
|
internal fun InterestsListDetailScreen(
|
|
|
|
|
selectedTopicId: String?,
|
|
|
|
|
onTopicClick: (String) -> Unit,
|
|
|
|
|
windowAdaptiveInfo: WindowAdaptiveInfo,
|
|
|
|
|
viewModel: Interests2PaneViewModel = hiltViewModel()
|
|
|
|
|
) {
|
|
|
|
|
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator(
|
|
|
|
|
scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo),
|
|
|
|
|
val selectedTopicId by viewModel.selectedTopicId.collectAsStateWithLifecycle()
|
|
|
|
|
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator<String>(
|
|
|
|
|
initialDestinationHistory = listOfNotNull(
|
|
|
|
|
ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.List),
|
|
|
|
|
ThreePaneScaffoldDestinationItem<Nothing>(ListDetailPaneScaffoldRole.Detail).takeIf {
|
|
|
|
|
ThreePaneScaffoldDestinationItem<String>(ListDetailPaneScaffoldRole.Detail).takeIf {
|
|
|
|
|
selectedTopicId != null
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
@ -97,33 +60,9 @@ internal fun InterestsListDetailScreen(
|
|
|
|
|
listDetailNavigator.navigateBack()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var nestedNavHostStartRoute by remember {
|
|
|
|
|
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<DetailPaneNavHostRoute>()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Otherwise, recreate the NavHost entirely, and start at the new destination
|
|
|
|
|
nestedNavHostStartRoute = TopicRoute(id = topicId)
|
|
|
|
|
nestedNavKey = UUID.randomUUID()
|
|
|
|
|
}
|
|
|
|
|
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
|
|
|
|
|
fun onTopicClickShowDetailPane(selectedTopicId: String) {
|
|
|
|
|
viewModel.onTopicClick(selectedTopicId)
|
|
|
|
|
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail, selectedTopicId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ListDetailPaneScaffold(
|
|
|
|
@ -139,22 +78,15 @@ internal fun InterestsListDetailScreen(
|
|
|
|
|
},
|
|
|
|
|
detailPane = {
|
|
|
|
|
AnimatedPane {
|
|
|
|
|
key(nestedNavKey) {
|
|
|
|
|
NavHost(
|
|
|
|
|
navController = nestedNavController,
|
|
|
|
|
startDestination = nestedNavHostStartRoute,
|
|
|
|
|
route = DetailPaneNavHostRoute::class,
|
|
|
|
|
) {
|
|
|
|
|
topicScreen(
|
|
|
|
|
showBackButton = !listDetailNavigator.isListPaneVisible(),
|
|
|
|
|
onBackClick = listDetailNavigator::navigateBack,
|
|
|
|
|
onTopicClick = ::onTopicClickShowDetailPane,
|
|
|
|
|
)
|
|
|
|
|
composable<TopicPlaceholderRoute> {
|
|
|
|
|
TopicDetailPlaceholder()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (selectedTopicId != null) {
|
|
|
|
|
TopicScreen(
|
|
|
|
|
topicId = selectedTopicId!!,
|
|
|
|
|
showBackButton = !listDetailNavigator.isListPaneVisible(),
|
|
|
|
|
onBackClick = listDetailNavigator::navigateBack,
|
|
|
|
|
onTopicClick = ::onTopicClickShowDetailPane,
|
|
|
|
|
)
|
|
|
|
|
} else
|
|
|
|
|
TopicDetailPlaceholder()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|