Adib Faramarzi

    Adib Faramarzi

    1 year ago
    Is there a way to simulate activity's
    back pressed
    state for compose-navigation?
    popBackStack
    does not finish navigation (and instead just removes the destination) but pressing the back key always works perfectly. This becomes a problem when you have nested navigation as the inner navigation stacks can never pop themselves
    For example, If in the scenario below, you are in the screen C and you pop the back stack, you will see a white screen (because C has been popped off, but it has not been navigated back to A). If you press the back button, it works fine and you will see A. • A • B ◦ C ◦ D
    n

    nitrog42

    1 year ago
    it kinda looks like a bug 🤔
    which version of navigation-compose are you using ?
    Adib Faramarzi

    Adib Faramarzi

    1 year ago
    2.4.0-alpha06
    n

    nitrog42

    1 year ago
    can you try with alpha04 to check if the same happens ? (I believe alpha05 had some critical bugs)
    Adib Faramarzi

    Adib Faramarzi

    1 year ago
    Yes
    I hope it doesn't conflict with accompanist's navigation
    It seems to be present in alpha-04 too.
    n

    nitrog42

    1 year ago
    you should probably open a bug here then : https://issuetracker.google.com/issues?q=componentid:409828%20status:open , with a reproducible sample if you can
    i

    Ian Lake

    1 year ago
    The docs (https://developer.android.com/guide/navigation/navigation-navigate#back-stack) do specifically state:
    NavController.popBackStack() returns a boolean indicating whether it successfully popped back to another destination. The most common case when this returns false is when you manually pop the start destination of your graph.
    When the method returns false, NavController.getCurrentDestination() returns null. You are responsible for either navigating to a new destination or handling the pop by calling finish() on your Activity
    So it sounds like you'll want to use
    false
    as your signal to call
    popBackStack()
    on your outer NavController
    Adib Faramarzi

    Adib Faramarzi

    1 year ago
    Thanks
    This makes nested navigation very hard though
    Is there a way to access a parent nav controller within one?
    i

    Ian Lake

    1 year ago
    Taking a step back, nested nav hosts are rarely actually the right answer, as we've talked about before https://kotlinlang.slack.com/archives/CJLTWPH7S/p1627490432392100?thread_ts=1627477759.324500&cid=CJLTWPH7S
    In Compose, state goes down the tree and events go up - the thing manually calling
    popBackStack()
    should also be taking a lambda to trigger when that returns
    false
    - that would be how you'd encapsulate the access to the outer NavController
    Maybe if you explain your use case, we can help build a better architecture for what you are trying to do?
    Adib Faramarzi

    Adib Faramarzi

    1 year ago
    Thanks for the info. Will check shortly. I totally agree about the events going up (in which, this case is in violation of by calling
    popBackStack()
    ) I have a back button in the inner-navigation page which should pop its page. Currently it is using
    popBackStack
    . I think what might be better is passing a
    onBackPressed
    into the function that is rendering this page (which is a
    NavHost
    and handle the back there (pop the backstack of the parent nav controller).
    i

    Ian Lake

    1 year ago
    Yeah, if you're taking the events as lambdas thing to heart, none of your screens should have access to a NavController at all (as per our testing docs: https://developer.android.com/jetpack/compose/navigation#testing) so it would be really easy to pass a different lambda to the start destination of that inner graph that just triggers a lambda passed from the outer NavHost
    Adib Faramarzi

    Adib Faramarzi

    1 year ago
    That's correct. Thanks 🙂
    i

    Ian Lake

    1 year ago
    But again, I'd verify if a nested nav host is actually the right architecture choice in the first place - it is not the right choice if you're just using it to hide/show global UI ala a bottom nav, app bar, etc
    Adib Faramarzi

    Adib Faramarzi

    1 year ago
    The back button is not general (it exists only in the page)
    n

    nitrog42

    1 year ago
    I might misunderstood the initial issue, but I believe it was : • one navhost • a main graph containing a subgraph • when on a destination of the subgraph, using navController.popBackStack won't return the current destination to the main graph and display a blank screen
    let me check 😄 edit : Yeah I misunderstood, I thought the use case was this :
    NavHost(navController = navController, startDestination = nav_home) {
        composable("home") {
            Text("Home")
        }
        navigation(startDestination = "profile/", route = "profile") {
            composable("profile/") {
                Button(onClick = { navController.popBackStack() }) {
                    Text("Should go to home") // But display blank page instead
                }
            }
        }
    }
    Colton Idle

    Colton Idle

    1 year ago
    Ian, I had a similar question to this that I was able to answer myself, but maybe I'll tag it along here. I have ScreenA and ScreenB. Screen B has an up button. ScreenB also has a pager with 5 pages and my UX person wants every touch of the up button to move back through the view pager if I'm on page > 1.
    val dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
    
    BackHandler(enabled = pagerState.currentPage > 0) {
        viewModel.updateCurrentPage(pagerState.currentPage.minus(1))
        scope.launch { pagerState.animateScrollToPage(pagerState.currentPage.minus(1)) }
    }
    And my top bar is declared like this
    topBar = {
        MyTopAppBar(navBackIconClicked = { dispatcher.onBackPressed() })
    @Adib Faramarzi maybe you'll find this useful.
    i

    Ian Lake

    1 year ago
    Seems reasonable, but note that your top app bar will do a lot more than just trigger page changes if any page adds their own
    BackHandler
    . Just double check that behavior is actually what you want or if you want to bypass those to only swap back pages, no matter what internal BackHandlers exist (i.e., make the signal explicit as we've been talking about)