Skip to content

Commit 835a65f

Browse files
committed
implement new typesafe routing
1 parent 04657ae commit 835a65f

2 files changed

Lines changed: 54 additions & 43 deletions

File tree

composeApp/src/commonMain/kotlin/App.kt

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import androidx.navigation.NavBackStackEntry
1313
import androidx.navigation.compose.NavHost
1414
import androidx.navigation.compose.composable
1515
import androidx.navigation.compose.rememberNavController
16-
import androidx.savedstate.read
16+
import androidx.navigation.toRoute
1717
import models.Wonder
1818
import models.parse
1919
import ui.screens.ArtifactDetailsScreen
@@ -40,26 +40,24 @@ fun App() {
4040

4141
NavHost(
4242
navController = navigator,
43-
startDestination = "/home",
43+
startDestination = AppRoute.Home,
4444
enterTransition = { DefaultEnterTransition },
4545
exitTransition = { DefaultExitTransition },
4646
popEnterTransition = { DefaultPopEnterTransition },
4747
popExitTransition = { DefaultPopExitTransition },
4848
) {
49-
composable(
50-
"/home",
51-
) { backStackEntry ->
49+
composable<AppRoute.Home> { backStackEntry ->
5250
// Temporary fix as current Wonder is not being remembered when in backstack
5351
val savedStateHandle = backStackEntry.savedStateHandle
5452
val currentWonderName = savedStateHandle.get<String>("currentWonder")
5553
val currentWonder = Wonder.parse(currentWonderName)
5654
HomeScreen(
5755
initialWonder = currentWonder,
5856
openDetailScreen = {
59-
navigator.navigate("/home/wonder/${it.name}")
57+
navigator.navigate(AppRoute.Wonder(it.name))
6058
},
6159
openTimelineScreen = {
62-
navigator.navigate("/timeline?type=${it.name}")
60+
navigator.navigate(AppRoute.Timeline(it.name))
6361
},
6462
animatedVisibilityScope = this,
6563
sharedTransitionScope = this@SharedTransitionLayout,
@@ -70,49 +68,42 @@ fun App() {
7068

7169
}
7270

73-
composable(
74-
"/home/wonder/{type}",
75-
) { backStackEntry ->
76-
val id = backStackEntry.arguments?.read { getString("type") }
77-
val wonder = Wonder.parse(id)
71+
composable<AppRoute.Wonder> { backStackEntry ->
72+
val route = backStackEntry.toRoute<AppRoute.Wonder>()
73+
val wonder = Wonder.parse(route.wonderId)
7874
WonderDetailsScreen(
7975
wonder = wonder,
8076
onPressHome = { navigator.popBackStack() },
81-
openTimelineScreen = { navigator.navigate("/timeline?type=${it?.name}") },
82-
openArtifactDetailsScreen = { navigator.navigate("/artifact/${it}") },
83-
openArtifactListScreen = { navigator.navigate("/search/${it.name}") },
84-
openMapScreen = { navigator.navigate("/maps/${it.name}") },
85-
openVideoScreen = { navigator.navigate("/video/$it") },
77+
openTimelineScreen = { navigator.navigate(AppRoute.Timeline(it?.name)) },
78+
openArtifactDetailsScreen = { navigator.navigate(AppRoute.ArtifactDetails(it)) },
79+
openArtifactListScreen = { navigator.navigate(AppRoute.Search(it.name)) },
80+
openMapScreen = { navigator.navigate(AppRoute.Maps(it.name)) },
81+
openVideoScreen = { navigator.navigate(AppRoute.Video(it)) },
8682
animatedVisibilityScope = this,
8783
sharedTransitionScope = this@SharedTransitionLayout,
8884
)
8985
}
90-
composable(
91-
"/timeline",
92-
) { backStackEntry ->
93-
val id = backStackEntry.arguments?.read { getString("type") }
94-
val wonder = Wonder.parse(id)
86+
87+
composable<AppRoute.Timeline> { backStackEntry ->
88+
val route = backStackEntry.toRoute<AppRoute.Timeline>()
89+
val wonder = Wonder.parse(route.wonderId)
9590
TimelineScreen(
9691
selectedWonder = wonder,
9792
onClickBack = { navigator.popBackStack() },
9893
)
9994
}
10095

101-
composable(
102-
"/artifact/{id}",
103-
) { backStackEntry ->
104-
val id = backStackEntry.arguments?.read { getString("id") }!!
96+
composable<AppRoute.ArtifactDetails> { backStackEntry ->
97+
val route = backStackEntry.toRoute<AppRoute.ArtifactDetails>()
10598
ArtifactDetailsScreen(
106-
artifactId = id,
99+
artifactId = route.artifactId,
107100
onClickBack = { navigator.popBackStack() },
108101
)
109102
}
110103

111-
composable(
112-
"/search/{type}",
113-
) { backStackEntry ->
114-
val id = backStackEntry.arguments?.read { getString("type") }
115-
val wonder = Wonder.parse(id)
104+
composable<AppRoute.Search> { backStackEntry ->
105+
val route = backStackEntry.toRoute<AppRoute.Search>()
106+
val wonder = Wonder.parse(route.wonderId)
116107
val viewModel = viewModel { ArtifactListViewModel(wonder) }
117108
ArtifactListScreen(
118109
wonder = wonder,
@@ -121,28 +112,24 @@ fun App() {
121112
onQueryChange = viewModel::onQueryChange,
122113
suggestions = viewModel.suggestions.collectAsStateWithLifecycle().value,
123114
filteredArtifacts = viewModel.filteredArtifacts.collectAsStateWithLifecycle().value,
124-
onClickArtifact = { navigator.navigate("/artifact/${it}") },
115+
onClickArtifact = { navigator.navigate(AppRoute.ArtifactDetails("$it")) },
125116
onBackClick = { navigator.navigateUp() },
126117
)
127118
}
128119

129-
composable(
130-
"/maps/{type}",
131-
) { backStackEntry ->
132-
val id = backStackEntry.arguments?.read { getString("type") }
133-
val wonder = Wonder.parse(id)
120+
composable<AppRoute.Maps> { backStackEntry ->
121+
val route = backStackEntry.toRoute<AppRoute.Maps>()
122+
val wonder = Wonder.parse(route.wonderId)
134123
MapScreen(
135124
latLng = wonder.latLng,
136125
onBackClick = { navigator.popBackStack() }
137126
)
138127
}
139128

140-
composable(
141-
"/video/{id}",
142-
) { backStackEntry ->
143-
val id = backStackEntry.arguments?.read { getString("id") }!!
129+
composable<AppRoute.Video> { backStackEntry ->
130+
val route = backStackEntry.toRoute<AppRoute.Video>()
144131
YoutubeVideoScreen(
145-
id = id,
132+
id = route.videoId,
146133
onBackClick = { navigator.popBackStack() }
147134
)
148135
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import kotlinx.serialization.Serializable
2+
3+
sealed interface AppRoute {
4+
@Serializable
5+
data object Home : AppRoute
6+
7+
@Serializable
8+
data class Wonder(val wonderId: String) : AppRoute
9+
10+
@Serializable
11+
data class Timeline(val wonderId: String? = null) : AppRoute
12+
13+
@Serializable
14+
data class ArtifactDetails(val artifactId: String) : AppRoute
15+
16+
@Serializable
17+
data class Search(val wonderId: String) : AppRoute
18+
19+
@Serializable
20+
data class Maps(val wonderId: String) : AppRoute
21+
22+
@Serializable
23+
data class Video(val videoId: String) : AppRoute
24+
}

0 commit comments

Comments
 (0)