1
1
package dev.hotwire.turbo.nav
2
2
3
3
import android.net.Uri
4
- import androidx.annotation.IdRes
5
4
import androidx.appcompat.app.AppCompatActivity
6
5
import androidx.core.net.toUri
7
6
import androidx.fragment.app.DialogFragment
@@ -13,6 +12,7 @@ import androidx.navigation.fragment.FragmentNavigator
13
12
import androidx.navigation.fragment.FragmentNavigatorDestinationBuilder
14
13
import dev.hotwire.turbo.config.TurboPathConfiguration
15
14
import dev.hotwire.turbo.config.uri
15
+ import java.util.*
16
16
import kotlin.reflect.KClass
17
17
import kotlin.reflect.full.findAnnotation
18
18
import kotlin.reflect.full.isSubclassOf
@@ -23,13 +23,13 @@ internal class TurboNavGraphBuilder(
23
23
private val pathConfiguration : TurboPathConfiguration
24
24
) {
25
25
private data class ActivityDestination (
26
- val id : Int ,
26
+ val route : String ,
27
27
val uri : Uri ,
28
28
val kClass : KClass <out AppCompatActivity >
29
29
)
30
30
31
31
private data class FragmentDestination (
32
- val id : Int ,
32
+ val route : String ,
33
33
val uri : Uri ,
34
34
val kClass : KClass <out Fragment >
35
35
)
@@ -38,19 +38,19 @@ internal class TurboNavGraphBuilder(
38
38
registeredActivities : List <KClass <out AppCompatActivity >>,
39
39
registeredFragments : List <KClass <out Fragment >>
40
40
): NavGraph {
41
- var currentId = 1
41
+ var currentRoute = 1
42
42
43
43
val activityDestinations = registeredActivities.map {
44
44
ActivityDestination (
45
- id = currentId .also { currentId ++ },
45
+ route = currentRoute .also { currentRoute ++ }.toString() ,
46
46
uri = it.turboAnnotation().uri.toUri(),
47
47
kClass = it
48
48
)
49
49
}
50
50
51
51
val fragmentDestinations = registeredFragments.map {
52
52
FragmentDestination (
53
- id = currentId .also { currentId ++ },
53
+ route = currentRoute .also { currentRoute ++ }.toString() ,
54
54
uri = it.turboAnnotation().uri.toUri(),
55
55
kClass = it
56
56
)
@@ -59,39 +59,48 @@ internal class TurboNavGraphBuilder(
59
59
return createGraph(
60
60
activityDestinations,
61
61
fragmentDestinations,
62
- fragmentDestinations.startDestination().id
62
+ fragmentDestinations.startDestination().route
63
63
)
64
64
}
65
65
66
66
@Suppress(" UNCHECKED_CAST" )
67
67
private fun createGraph (
68
68
activityDestinations : List <ActivityDestination >,
69
69
fragmentDestinations : List <FragmentDestination >,
70
- startDestinationId : Int
70
+ startDestinationRoute : String
71
71
): NavGraph {
72
- return navController.createGraph(startDestination = startDestinationId ) {
72
+ return navController.createGraph(startDestination = startDestinationRoute ) {
73
73
activityDestinations.forEach {
74
- activity(it.id ) {
74
+ activity(it.route ) {
75
75
activityClass = it.kClass
76
76
deepLink(it.uri.toString())
77
77
}
78
78
}
79
79
80
80
fragmentDestinations.withoutDialogs().forEach {
81
- fragment(it.id , it.kClass) {
81
+ fragment(it.route , it.kClass) {
82
82
deepLink(it.uri.toString())
83
83
}
84
84
}
85
85
86
86
fragmentDestinations.dialogs().forEach {
87
- dialog(it.id , it.kClass as KClass <out DialogFragment >) {
87
+ dialog(it.route , it.kClass as KClass <out DialogFragment >) {
88
88
deepLink(it.uri.toString())
89
89
}
90
90
}
91
91
92
92
argument(" location" ) {
93
93
defaultValue = startLocation
94
94
}
95
+
96
+ // Use a random value to represent a unique instance of the graph, so the
97
+ // graph is unique every time. This lets it be reset/recreated on-demand from
98
+ // `TurboSessionNavHostFragment.reset()`. Replacing an existing nav graph with
99
+ // an identical one would bypass recreating the nav stack from scratch in
100
+ // `NavController.setGraph()`.
101
+ argument(" unique_instance" ) {
102
+ defaultValue = UUID .randomUUID().toString()
103
+ }
95
104
}
96
105
}
97
106
@@ -100,7 +109,7 @@ internal class TurboNavGraphBuilder(
100
109
}
101
110
102
111
private fun List<FragmentDestination>.withoutDialogs (): List <FragmentDestination > {
103
- return minus(dialogs())
112
+ return minus(dialogs().toSet() )
104
113
}
105
114
106
115
private fun List<FragmentDestination>.startDestination (): FragmentDestination {
@@ -118,26 +127,26 @@ internal class TurboNavGraphBuilder(
118
127
119
128
// Modified from AndroidX FragmentNavigatorDestinationBuilder extensions
120
129
private inline fun NavGraphBuilder.fragment (
121
- @IdRes id : Int ,
130
+ route : String ,
122
131
fragmentClass : KClass <out Fragment >,
123
132
builder : FragmentNavigatorDestinationBuilder .() -> Unit
124
133
) = destination(
125
134
FragmentNavigatorDestinationBuilder (
126
135
provider[FragmentNavigator ::class ],
127
- id ,
136
+ route ,
128
137
fragmentClass
129
138
).apply (builder)
130
139
)
131
140
132
141
// Modified from AndroidX DialogFragmentNavigatorDestinationBuilder extensions
133
142
private inline fun NavGraphBuilder.dialog (
134
- @IdRes id : Int ,
143
+ route : String ,
135
144
fragmentClass : KClass <out DialogFragment >,
136
145
builder : DialogFragmentNavigatorDestinationBuilder .() -> Unit
137
146
) = destination(
138
147
DialogFragmentNavigatorDestinationBuilder (
139
148
provider[DialogFragmentNavigator ::class ],
140
- id ,
149
+ route ,
141
150
fragmentClass
142
151
).apply (builder)
143
152
)
0 commit comments