compose-destinations: IllegalArgumentException: navigation destination test_screen is not a direct child of this NavGraph

Hey there, I’m facing this error and I’m pretty desperate.

‘IllegalArgumentException: navigation destination test_screen is not a direct child of this NavGraph’

I’m using latest version of compose-destinations - 1.9.40-beta. I have a multi-module project with more graphs. I copy-pasted the code from tivi project with small modifications (mentioned in 1.9.40-beta release notes).

I added to all my modules build.gradle.kts files this block of code:

ksp {
        arg("compose-destinations.moduleName", "test")
        arg("compose-destinations.mode", "destinations")
        arg("compose-destinations.generateNavGraphs", "false")
    }

Also here is my Destinations (only with Text, for simplicity)

@Destination
@Composable
fun TestScreen(){
    Column(){
        Text("Test")
    }
}
@Destination
@Composable
fun TestOneScreen(){
    Column(){
        Text("Test 1")
    }
}

and here is Navigation code:

object NavGraphs {
    val test = object : NavGraphSpec {
        override val destinationsByRoute = emptyMap<String, DestinationSpec<*>>()
        override val route = "test"
        override val startRoute = TestScreenDestination routedIn this
    }

    val test1 = object : NavGraphSpec {
        override val destinationsByRoute = emptyMap<String, DestinationSpec<*>>()
        override val route = "test1"
        override val startRoute = TestOneScreenDestination routedIn this
    }

    val root = object : NavGraphSpec {
        override val route = "root"
        override val startRoute = test
        override val destinationsByRoute = emptyMap<String, DestinationSpec<*>>()
        override val nestedNavGraphs = listOf(
            test, test1
        )
    }
}

fun ArrayDeque<NavBackStackEntry>.print(prefix: String = "stack") {
    val stack = toMutableList()
        .map { it.destination.route }
        .toTypedArray().contentToString()
    println("$prefix = $stack")
}

fun DependenciesContainerBuilder<*>.currentNavigator(): CommonNavGraphNavigator {
    return CommonNavGraphNavigator(
        navBackStackEntry.destination.navGraph(),
        navController
    )
}

@OptIn(ExperimentalMaterialNavigationApi::class)
@ExperimentalAnimationApi
@Composable
internal fun AppNavigation(
    navController: NavHostController,
    modifier: Modifier = Modifier,
) {
    DestinationsNavHost(
        engine = rememberAnimatedNavHostEngine(
            rootDefaultAnimations = RootNavGraphDefaultAnimations(
                enterTransition = { defaultEnterTransition(initialState, targetState) },
                exitTransition = { defaultExitTransition(initialState, targetState) },
                popEnterTransition = { defaultPopEnterTransition() },
                popExitTransition = { defaultPopExitTransition() },
            )
        ),
        navController = navController,
        navGraph = NavGraphs.root,
        modifier = modifier,
        dependenciesContainerBuilder = {
            dependency(currentNavigator())
        }
    )
}

@ExperimentalAnimationApi
private fun AnimatedContentTransitionScope<*>.defaultEnterTransition(
    initial: NavBackStackEntry,
    target: NavBackStackEntry,
): EnterTransition {
    val initialNavGraph = initial.destination.hostNavGraph
    val targetNavGraph = target.destination.hostNavGraph
    // If we're crossing nav graphs (bottom navigation graphs), we crossfade
    if (initialNavGraph.id != targetNavGraph.id) {
        return fadeIn()
    }
    // Otherwise we're in the same nav graph, we can imply a direction
    return fadeIn() + slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Start)
}

@ExperimentalAnimationApi
private fun AnimatedContentTransitionScope<*>.defaultExitTransition(
    initial: NavBackStackEntry,
    target: NavBackStackEntry,
): ExitTransition {
    val initialNavGraph = initial.destination.hostNavGraph
    val targetNavGraph = target.destination.hostNavGraph
    // If we're crossing nav graphs (bottom navigation graphs), we crossfade
    if (initialNavGraph.id != targetNavGraph.id) {
        return fadeOut()
    }
    // Otherwise we're in the same nav graph, we can imply a direction
    return fadeOut() + slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Start)
}

private val NavDestination.hostNavGraph: NavGraph
    get() = hierarchy.first { it is NavGraph } as NavGraph

@ExperimentalAnimationApi
private fun AnimatedContentTransitionScope<*>.defaultPopEnterTransition(): EnterTransition {
    return fadeIn() + slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.End)
}

@ExperimentalAnimationApi
private fun AnimatedContentTransitionScope<*>.defaultPopExitTransition(): ExitTransition {
    return fadeOut() + slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.End)
}

Tried to remove routedIn (but it was not working). Try all advices what I see in issues in repos, but still not working.

Do you have any idea what I’m doing wrong? Thanks

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

Like this it works. Reason is that routedIn call actually calls route, but if route is only initialized after, then it returns null. So the final route is null/test.

Expect the multi module experience to improve soon. But right now this is the case…

Turns out you need to specify route before calling routedIn 🤦

    val test = object : NavGraphSpec {
        override val route = "test"
        override val destinationsByRoute = listOf<DestinationSpec<*>>(
            TestScreenDestination
        ).routedIn(this)
            .associateBy { it.route }
        override val startRoute = TestScreenDestination routedIn this
    }

    val foo = object : NavGraphSpec {
        override val route = "foo"
        override val destinationsByRoute = listOf<DestinationSpec<*>>(
            FooScreenDestination
        ).routedIn(this)
            .associateBy { it.route }
        override val startRoute = FooScreenDestination routedIn this
    }

Sure, here it is: https://github.com/Vlado24/compose-destinations-example same error. Tried with different startRoute, but still not working.