With Nav3, do we have an equivalent for a subgraph...
# compose-android
g
With Nav3, do we have an equivalent for a subgraph from Nav2? It was quite convenient for a feature module to have its own little navigation graph πŸ€”
i
Each feature module can contribute its own set of NavEntry, for example by providing extensions on the
EntryProviderBuilder
that is used in the DSL: https://developer.android.com/guide/navigation/navigation-3/basics#use_the_entryprovider_dsl So your code would look like
Copy code
entryProvider {
  homeModuleEntries()
  profileModuleEntries()
}
🀩 1
But no, there's no concept of graphs at all, much less subgraphs
Maybe it would be helpful if you explained what base functionality you are looking for - focusing on requirements instead of solutions is a good way to avoid an XY Problem:https://en.wikipedia.org/wiki/XY_problem
βž• 1
g
Thank you, yes that sounds like the exact API I was looking for, going to try that right now πŸ‘ > But no, there's no concept of graphs at all, much less subgraphs I am very glad we're parting with the graph representation πŸ˜… > Maybe it would be helpful if you explained what base functionality you are looking for - focusing on requirements instead of solutions is a good way to avoid an XY Problem:https://en.wikipedia.org/wiki/XY_problem Sure, the base functionally that I am looking for is the encapsulation of a part of the navigation, in this use case, for an "entrance" module which responsibility is to login/signup the user and contains those screens/flows: β€’ Login Screen β€’ ForgotPasswordScreen β€’ Signup Screen -> CompleteAccountScreen From the app perspective, I would like to expose a single "open entrance" API, which after doing its thing should return back some Result (when we'll get the equivalent of a Result API).
i
Yep, it should be possible right now to set up that kind of structure - you only expose the data object for the entrance to your login graph (so other modules can add it to the back stack, starting the flow) and keep the keys for other classes that are part of that flow internal to that module
🀩 1
s
A bit unrelated perhaps, but without the concept of graphs, how is navigateUp planned to be supported? Just more manual handling of it instead of relying on a proper graph setup?
g
@Ian Lake The implementation looks very cool, also with one extension function I can keep all the entries internal:
Copy code
fun NavBackStack.navigateToEntrance() {
    add(EntranceNavigation.Login)
}

internal object EntranceNavigation {
    @Serializable data object Login: NavKey
    @Serializable data object Signup: NavKey
    @Serializable data object ForgotPassword: NavKey
    @Serializable data object CompleteAccount: NavKey
}

fun EntryProviderBuilder<NavKey>.authModuleEntries(
    navigateTo: (NavKey) -> Unit,
    replace: (toRemove: NavKey, toAdd: NavKey) -> Unit,
    popBackStack: () -> Unit,
) {
    entry(EntranceNavigation.Login) {
        LoginScreen(
            onSignUpClick = { replace(EntranceNavigation.Login, EntranceNavigation.Signup) },
            onForgotPasswordClick = { navigateTo(EntranceNavigation.ForgotPassword) },
            onAuthSuccess = { popBackStack() },
        )
    }

    entry(EntranceNavigation.Signup) {
        SignUpScreen(
            onBackClick = { popBackStack() },
            onSignUpSuccess = {
                replace(
                    EntranceNavigation.Signup,
                    EntranceNavigation.CompleteAccount
                )
            }
        )
    }

    entry(EntranceNavigation.ForgotPassword) {
        ForgotPasswordScreen(
            onBackClick = { popBackStack() },
        )
    }

    entry(EntranceNavigation.CompleteAccount) {
        CompleteAccountScreen(
            onBackClick = { popBackStack() },
            onComplete = { popBackStack() },
        )
    }
}
I would love to see a recipe on how to modularize (like this or in any other way) the navigation graph 😊
i
Yep, looks about right to me. Feel free to file an issue on the recipes repository if you'd like us to explore any particular pattern
The nav3-recipes repository is also where we'll be looking at deep linking, which is the only case where Up vs Back is actually any different, as I talked about here: https://bsky.app/profile/ianlake.bsky.social/post/3lpmw236wws2r
g
Will do! One more question: what is the best way to know what item in the backstack actually called in this case
navigateToEntranc()
to pop back to it? The use case is when there's a long flow of screens and the user presses up for example, I would like to remove all the screens of that module πŸ€” Using the metadata map maybe?
Or simply removing all the screens from the backstack anyway, present or not, that would do I guess
i
I don't understand, you have the entire back stack, you know all of the screens in the module, isn't that just
dropLastWhile { it is EntranceScreen }
(if you had a sealed marker interface for all your screens in that module, for instance)
βž• 1
g
That is a much better idea than removing all screens one by one 😍
i
The nice part about it being a list you own is you get to use all the fun list operations make these things way easier to do
g
It is indeed amazing we own the backstack ❀️ Here we go, the API seems very clean to me now:
Copy code
fun NavBackStack.navigateToEntrance() {
    add(EntranceNavigation.Login)
}

fun NavBackStack.popEntrance() {
    dropLastWhile { it is EntranceNavigation.EntranceNavKey }
}

internal object EntranceNavigation {
    
    interface EntranceNavKey : NavKey
    
    @Serializable data object Login: EntranceNavKey
    @Serializable data object Signup: EntranceNavKey
    @Serializable data object ForgotPassword: EntranceNavKey
    @Serializable data object CompleteAccount: EntranceNavKey
}
i
tenor_gif628799931570519451.gif
🀣 3
g
thank you color 1
p
How crazy is it to contribute one NavDisplay per feature module(aka subgraph) and nest it within a parent NavDisplay?
πŸ‘ŽπŸΎ 1
i
Trying to do this at the NavDisplay level is almost certainly the wrong choice and is going to make proper transitions and usages of Scenes near impossible. Again, worth talking about your requirements, not possible solutions
βž• 1
πŸ‘Œ 1
p
Ok, worth the clarification. My requirement is certainly the same as Alex above. It is to be able to encapsulate and or isolate the navigation to libraries. My App code is split into multiple .aar and each one contains its own UI and navigation logic. I want to expose the least possible of each aar. It seems the approach is somewhere around Alex snippets above. Thanks πŸ™πŸ‘
πŸ‘ 1