Skip to content

Commit

Permalink
Merge pull request #251 from hotwired/fix-navhost-reset
Browse files Browse the repository at this point in the history
Fix resetting the `TurboSessionNavHostFragment`
  • Loading branch information
jayohms authored Nov 16, 2022
2 parents 31569a0 + d1cc239 commit f63adb6
Showing 1 changed file with 26 additions and 17 deletions.
43 changes: 26 additions & 17 deletions turbo/src/main/kotlin/dev/hotwire/turbo/nav/TurboNavGraphBuilder.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.hotwire.turbo.nav

import android.net.Uri
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
Expand All @@ -13,6 +12,7 @@ import androidx.navigation.fragment.FragmentNavigator
import androidx.navigation.fragment.FragmentNavigatorDestinationBuilder
import dev.hotwire.turbo.config.TurboPathConfiguration
import dev.hotwire.turbo.config.uri
import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.isSubclassOf
Expand All @@ -23,13 +23,13 @@ internal class TurboNavGraphBuilder(
private val pathConfiguration: TurboPathConfiguration
) {
private data class ActivityDestination(
val id: Int,
val route: String,
val uri: Uri,
val kClass: KClass<out AppCompatActivity>
)

private data class FragmentDestination(
val id: Int,
val route: String,
val uri: Uri,
val kClass: KClass<out Fragment>
)
Expand All @@ -38,19 +38,19 @@ internal class TurboNavGraphBuilder(
registeredActivities: List<KClass<out AppCompatActivity>>,
registeredFragments: List<KClass<out Fragment>>
): NavGraph {
var currentId = 1
var currentRoute = 1

val activityDestinations = registeredActivities.map {
ActivityDestination(
id = currentId.also { currentId++ },
route = currentRoute.also { currentRoute++ }.toString(),
uri = it.turboAnnotation().uri.toUri(),
kClass = it
)
}

val fragmentDestinations = registeredFragments.map {
FragmentDestination(
id = currentId.also { currentId++ },
route = currentRoute.also { currentRoute++ }.toString(),
uri = it.turboAnnotation().uri.toUri(),
kClass = it
)
Expand All @@ -59,39 +59,48 @@ internal class TurboNavGraphBuilder(
return createGraph(
activityDestinations,
fragmentDestinations,
fragmentDestinations.startDestination().id
fragmentDestinations.startDestination().route
)
}

@Suppress("UNCHECKED_CAST")
private fun createGraph(
activityDestinations: List<ActivityDestination>,
fragmentDestinations: List<FragmentDestination>,
startDestinationId: Int
startDestinationRoute: String
): NavGraph {
return navController.createGraph(startDestination = startDestinationId) {
return navController.createGraph(startDestination = startDestinationRoute) {
activityDestinations.forEach {
activity(it.id) {
activity(it.route) {
activityClass = it.kClass
deepLink(it.uri.toString())
}
}

fragmentDestinations.withoutDialogs().forEach {
fragment(it.id, it.kClass) {
fragment(it.route, it.kClass) {
deepLink(it.uri.toString())
}
}

fragmentDestinations.dialogs().forEach {
dialog(it.id, it.kClass as KClass<out DialogFragment>) {
dialog(it.route, it.kClass as KClass<out DialogFragment>) {
deepLink(it.uri.toString())
}
}

argument("location") {
defaultValue = startLocation
}

// Use a random value to represent a unique instance of the graph, so the
// graph is unique every time. This lets it be reset/recreated on-demand from
// `TurboSessionNavHostFragment.reset()`. Replacing an existing nav graph with
// an identical one would bypass recreating the nav stack from scratch in
// `NavController.setGraph()`.
argument("unique_instance") {
defaultValue = UUID.randomUUID().toString()
}
}
}

Expand All @@ -100,7 +109,7 @@ internal class TurboNavGraphBuilder(
}

private fun List<FragmentDestination>.withoutDialogs(): List<FragmentDestination> {
return minus(dialogs())
return minus(dialogs().toSet())
}

private fun List<FragmentDestination>.startDestination(): FragmentDestination {
Expand All @@ -118,26 +127,26 @@ internal class TurboNavGraphBuilder(

// Modified from AndroidX FragmentNavigatorDestinationBuilder extensions
private inline fun NavGraphBuilder.fragment(
@IdRes id: Int,
route: String,
fragmentClass: KClass<out Fragment>,
builder: FragmentNavigatorDestinationBuilder.() -> Unit
) = destination(
FragmentNavigatorDestinationBuilder(
provider[FragmentNavigator::class],
id,
route,
fragmentClass
).apply(builder)
)

// Modified from AndroidX DialogFragmentNavigatorDestinationBuilder extensions
private inline fun NavGraphBuilder.dialog(
@IdRes id: Int,
route: String,
fragmentClass: KClass<out DialogFragment>,
builder: DialogFragmentNavigatorDestinationBuilder.() -> Unit
) = destination(
DialogFragmentNavigatorDestinationBuilder(
provider[DialogFragmentNavigator::class],
id,
route,
fragmentClass
).apply(builder)
)
Expand Down

0 comments on commit f63adb6

Please sign in to comment.