Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help with child controller custom back handling #536

Open
ursusursus opened this issue Apr 28, 2019 · 2 comments
Open

Help with child controller custom back handling #536

ursusursus opened this issue Apr 28, 2019 · 2 comments

Comments

@ursusursus
Copy link

ursusursus commented Apr 28, 2019

Hi, I have a drawer layout, (whole screen is a controller), where drawer has its own backstack, and content (the view under drawer when it is opened) has also its own backstack; so two child routers

When drawer is opened, I want to handle the drawer router back clicks; if not, then the content's

Mind you the first controller placed in the drawer router has handleBack overriden with
override fun handleBack() = false. Which in my mind reads I dont wanna handle back at all, just pass it through

What I want is:
When I press back when the drawer is opened, that means I should pop that drawer router; and when there is only one controller left on drawer router, just close the drawer

So the the back implementation in the root controller is like this:

override fun handleBack(): Boolean {
    if (drawerLayout.isDrawerOpen()) {
        if (!drawerRouter.handleBack()) {
            drawerLayout.closeDrawer()
        }
        return true
    } else {
        if (contentRouter.handleBack()) {            
            return true
        }
    }
    return false
}

However this has a bug, where if there is only 1 controller in the drawer router, because of this Conductor code

class Controller ....
    @UiThread
    public boolean handleBack() {
        ThreadUtils.ensureMainThread();

        if (!backstack.isEmpty()) {
            //noinspection ConstantConditions
            if (backstack.peek().controller.handleBack()) {
                return true;
            } else if (popCurrentController()) { <-------- THIS
                return true;
            }
        }

        return false;
    }

tldr;

When there is only one, the expected would be to have its handleBack called; which in my case always returns false, and therefore it should pass through to the root controller, which would return hardcoded true in this case, thuss stopping the back press handling; with nothing actually happening (besides the drawer closing)

However the THIS line shows it gets popped, thuss calling its onDestroy, which is not what I want. I would not expect it to get popped if I return false from its handleBack. Another interesting fact is that the controller's view stays in layout, and then when another controller is placed onto drawer router, I can see 2 overlapping controllers (bug)

@PaulWoitaschek
Copy link
Collaborator

For me the default handleBack almost always does the wrong thing. Especially it pops controllers from pager adapters so I end up with an activity without controllers.

I have a BaseController where I override handleBack and return false. Now my controllers can overwrite that and return true if they want to handle back themselfes. In that case if they return true, nothing is closed because of the following behavior:

Now I handle onBackPressed in my activity and check for the backstack size.

  • If it's <=1, I check if my topmost controller wants to handle back (by checking if router.backstack().last().controller?:handleBack()==true?).
    If yes, I don't proceed. If false, I let my activity finish by calling super.onBackPressed().
  • If it's > 1, I call router.handleBack().

@ursusursus
Copy link
Author

ursusursus commented Apr 29, 2019

@PaulWoitaschek so this is what I tried, it works; thanks

However this controller is retainViewMode = Controller.RetainViewMode.RETAIN_DETACH, and after I move away to another controller, then back, then push something onto leftDrawerRouter (so the backstack size is 2), however I can see the 1st controller view, wth?

If I remove the retain mode, it works as should

override fun handleBack(): Boolean {
        if (drawerLayout.isDrawerOpen(leftDrawerControllerContainer)) {
            if (leftDrawerRouter.backstackSize > 1) {
                leftDrawerRouter.handleBack()
            } else {
                drawerLayout.closeDrawer(leftDrawerControllerContainer)
            }
            return true

        } else if (drawerLayout.isDrawerOpen(rightDrawerControllerContainer)) {
            if (rightDrawerRouter.backstackSize > 1) {
                rightDrawerRouter.handleBack()
            } else {
                drawerLayout.closeDrawer(rightDrawerControllerContainer)
            }
            return true

        } else {
            if (chatRouter.handleBack()) {
                return true
            }
        }
        return false
    }

Any ideas?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants