Closed kp17211 closed 2 years ago
Triggered auto assignment to @mallenexpensify (AutoAssignerTriage
), see https://stackoverflow.com/c/expensify/questions/4749 for more details.
I don't have Android, trying to find someone on the CM team to triage
Assigning to @laurenreidexpensify for review since she has Android and I don't.
To me this is reproducible.
@kp17211 @parasharrajat I'm trying to reproduce this and a bit confused.
Am I missing something? Isn't this the expected behaviour?
am taken to the chat I was just in
This is an issue.
the flow should be
Ah got it - okay yes I can confirm this is the behaviour then. Will send this to our engineering team for next review.
Triggered auto assignment to @flodnv (Engineering
), see https://stackoverflow.com/c/expensify/questions/4319 for more details.
I could've sworn this was a feature and not a bug (granted, that I found strange as well). What's the behavior on iOS?
What's the behavior on iOS?
I don't believe iOS has a "back" hardware button (at least most of their devices don't) so I think this only applies in Android.
I agree this should be fixed eventually, it's how most (if not all) Android apps work, so I'll take this over and making it External
Looks like these resources could be helpful:
Triggered auto assignment to @trjExpensify (External
), see https://stackoverflow.com/c/expensify/questions/8582 for more details.
The title of this issue is a bit generic and the steps in the OP are a little confusing, so it would be good to spruce this up before posting to Upwork. Before I make the updates, am I right in thinking the issue here is isolated to: The Android hardware back button does not minimise the app when pressed on the LHN/home screen
?
Then the Action Performed
reproduction steps are:
Expected Results
Actual Results
Let me know if that's correct and I'll update the issue. ๐ Also, not sure if it's helpful to reference for the implementation approach, but we had some wider inconsistencies with the Android back button a little while back here.
We should first look into React-navigation. It was previously fixed but after the upgrade of react-navigation to v6 broke that fix.
Nice @trjExpensify that looks like a great summary! ๐
Cool, updated. Upwork job is here. @kp17211 are you interested in applying seeing as though you raised this issue?
Hello @trjExpensify yes I want to work on this issue
@kp17211 I think what @trjExpensify was asking was if you want to submit a proposal for the fix :D
Not overdue, just waiting for proposals
Changing priority to weekly as we wait for proposals
@Beamanator I'm interested to work on the job. Submitted proposal at Upwork.
Thanks for your interested @Aamer-Rasheed ! Please make sure to follow these steps too: https://github.com/Expensify/App/blob/main/CONTRIBUTING.md#propose-a-solution-for-the-job
I've accepted @kp17211 proposal in Upwork, as he created the issue. Over to you! ๐
@kp17211 before you submit your PR could you please post your proposal here so I can review? ๐
Okay, @kp17211 has reached out to me on Upwork to say he has accepted another offer so won't have time for this. Unassigning! @kp17211 in the future, could you just drop us a note here please? We're far more active and on top of comms in the GH repo than we are the Upwork messaging tool. Thanks!
@Aamer-Rasheed are you still interested in this job? Please let us know how you plan to approach the solution and then we can proceed to hire and moving to the PR.
@trjExpensify Thanks for the query. Got another project with a deadline of 03 weeks so would be unavailable during this time.
Doubled price to $500 in Upwork
After debugging I found out this.
Backhandler
. hardwareBackPress
event is consumed by the Drawer BankHandler which block our attempt to override it. To fix this issue we have to do the following but I am not how to run this piece of code when the drawer is open as Backhandler'hardwareBackPress'
never fires.
Run it on Backhandler'hardwareBackPress'
if(drawerisOpen) {
navigation.dispatch(StackAction.pop());
}
Other things I am exploring:
I got an invite from Upwork regarding this task. Is it still available? @trjExpensify @parasharrajat
Yes @Dev-Manny
@parasharrajat thanks for linking the previous issue opened by Marc! It looks like it was closed b/c we didn't respond back. In the issue, someone linked https://reactnavigation.org/docs/preventing-going-back/ - have you tried testing the code on that page?
reactnavigation.org/docs/preventing-going-back . This does not work for drawers.
But what I found so far is this.
useFocusEffect(
React.useCallback(() => {
let backSub = {remove: () => {}};
const handler = _.throttle((e) => {
const state = getActiveState(e.data.state);
const history = _.last(state.history);
console.debug(e.data.state);
if (!history) {
return;
}
console.debug(state.type, history);
if (state.type === 'drawer' && history.type === 'drawer' && history.status === 'open') {
console.debug('open');
backSub.remove();
backSub = BackHandler.addEventListener('hardwareBackPress', () => {
if (navigation.canGoBack()) {
Navigation.dismissModal();
} else {
BackHandler.exitApp();
}
backSub.remove();
return true;
});
} else {
console.debug('not open');
backSub.remove();
}
});
const sub = navigation.addListener('state', handler);
return () => {
sub();
backSub.remove();
};
}, [navigation]),
);
It works great and handles both of our drawers but it does not work for the first time when you navigate to the drawer screen as the drawer is opened by default which does not create a history entry.
If we can disable the drawer back handler from the Marc issue, things will become easier.
Apologies if I am repeating something that is no longer true, but @Maftalion suggested the following solution a while ago, which sounds like a better fix in my opinion:
@Maftalion
the complexity stems from the way the current navigation is set up, technically the reportview is the active page and the list of chats is a open drawer on top of that page
if that gets restructured as two separate pages, then the issue with the reportview would go away
He's referring to the point that the reportView
page used to be the top-level page in the app, with the NavDrawer|LHN
being a view that overlayed the content, instead of being its own separate page. When we made the NavDrawer|LHN
the top-level page we did not modify the RN page hierarchy to represent the true navigational hierarchy.
It looks like it was closed b/c we didn't respond back
Oh hmm the react-navigation issue was closed (maybe we can reopen it with a reproduction?). That suggestion was not from a maintainer which is why I didn't respond (it also doesn't work).
the reportView page used to be the top-level page in the app, with the NavDrawer|LHN being a view that overlayed the content, instead of being its own separate page
It sounds like we are suggesting to make the LHN another screen in the main stack navigator but I'm not too sure. We can achieve the drawer navigator "overlay" style with drawerType: 'front'
if that's a design we want to go with and it fixes the back handler issue.
we did not modify the RN page hierarchy to represent the true navigational hierarchy
What makes something a true navigational hierarchy?
Does everyone agree the proper fix should be in react-navigation
?
I agree that there should be an option to disable the back handler controlling the drawer as we want that. This causes issue when the drawer is nested in a screen.
It sounds like we are suggesting to make the LHN another screen in the main stack navigator but I'm not too sure.
Yeah, that's the suggestion here. We are only facing this issue because we are trying to force a NavigationDrawer to behave like a Page for our convenience. I believe this is also the reason why the component does not support App close behaviour -- it is not supposed to handle app close, because that should always be the responsibility of the page it sits on top of.
Scenario A: Original version of our app
A NavDrawer should open on top of the current page and is a part of that page.
A few months ago, we decided to switch to the WhatsApp pattern. The important distinction is that the LHN is now its own Page, rather than an overlay NavDrawer. We now (correctly) animate between the chat page and LHN as if they are parent and child pages, instead of the LHN simply being an overlay.
Scenario B: Our current app
I agree that we definitely could continue to use the NavigationDrawer
component for the LHN page and it will look mostly look fine, but I fear we'll run into lots of minor bugs/odd behaviors if we continue with this. One thing that jumps out to me is that we have to maintain two different ways of animating pages: 1) react-navigation
handles page to page animation for us, 2) we use the NavigationDrawer
component options to choose from 4 animation types (this is the only page handled in this way).
The reason I care (probably too much) about this, is because I would like us to have a truly mobile-first user experience and I fear that we'll end up with mostly correct, but buggy-looking UX.
What makes something a true navigational hierarchy?
I mean, if we can make the NavigationDrawer
behave in the right way then there is no problem. But why not make LHN a page? It makes our lives easier because we can trust the library to handle navigation, rather than having to manually fix this specific case with a workaround.
Sorry for the wall of text ๐ฌ
The reason I care (probably too much) about this, is because I would like us to have a truly mobile-first user experience and I fear that we'll end up with mostly correct, but buggy-looking UX.
Thanks for the thoughts @Julesssss! It might be worth creating a separate issue to discuss all this and we can loop some more folks in. It sounds like even if we fix this back button behavior there will remain an issue that the UX is still not ideal. And in that case, I would definitely encourage you to do the research and build a case for it if you feel strongly about it.
why not make LHN a page?
Might need to do some digging to produce a more thorough answer, but the reasons I can think of are...
drawerType: front
or do a custom implementation where we have the drawer sit above everything in a fixed way and not include it in the react-navigation
stack. The latter sounds complicated to me, but might worth doing.I'm not against ditching the drawer navigator. It might actually be better for performance since we can render the LHN without incurring a big cost to render the react-navigation
tree. But it does feel like a big undertaking if our main concern is that the drawer navigator doesn't let us close the app on Android.
Yeah, if I remember correctly the biggest issue was getting the desired UI/UX across all platforms (mobile, web, etc) which led to the drawer implementation.
As you mentioned @Julesssss a lot of the issues stem from trying to use the drawer as a screen instead of a drawer but at the same time want some functionality of the drawer (as Marc mentioned above with the gesture swiping).
Has there been any thought on keeping it as a drawer but not making the LHN the "initial screen"? Basically if you implemented something similar to Slack's UI where the chat is the home screen and the LHN is treated purely as a drawer? I believe that would fix the back button since back will just close the drawer and back from the chat would close the app.
Doubled price to $1000 https://www.upwork.com/jobs/~017e60e720f6f9aca8
I am awaiting @marcaaron 's decision on approaching the issue.
Either we should reopen the issue https://github.com/react-navigation/react-navigation/issues/9511 and add code to hide the drawer. The React-navigation repo is like a snail. I found it hard that someone will help us there.
Jules has a good suggestion https://github.com/Expensify/App/issues/4211#issuecomment-902155340 but I am not sure if that is possible. It requires rethinking the app architecture for few major parts. I don't think it's a good idea at this stage of the APP.
Last option is we hack our way through it and apply the fix in the code.
Here is a way to do it, Adding this handler in the Stack screen which contains the drawer. App already has a common BaseDrawerNavigator
component which makes it the best target. This code handles both Main LHN and Workspace Drawer.
const navigation = useNavigation();
useFocusEffect(
React.useCallback(() => {
let backSub = {remove: () => {}};
const handler = _.throttle((e) => {
// latest active state by custom function
const state = getActiveState(e.data.state);
const history = _.last(state.history);
if (state.type !== 'drawer' || (history && history.type === 'drawer' && history.status === 'open')) {
console.debug('open');
backSub.remove();
backSub = BackHandler.addEventListener('hardwareBackPress', () => {
if (navigation.canGoBack()) {
Navigation.dismissModal();
} else {
BackHandler.exitApp();
}
backSub.remove();
return true;
});
} else {
console.debug('not open');
backSub.remove();
}
});
const sub = navigation.addListener('state', handler);
return () => {
sub();
backSub.remove();
};
}, [navigation]),
);
What if we go with this plan:
Implement Rajat's code above (assuming we test and don't find any issues)
The code looks a bit complicated to me personally - which makes me concerned it will be difficult to maintain if we end up not doing 2
. I think we should first try to re-open the issue, provide a reproduction, and attempt a fix in react-navigation
.
I can't think of any reason why this issue needs to be fixed urgently - there are other ways to exit the app.
Just to follow up on my post above, I created a separate issue. It's probably not a high priority, but I think this improvement is worth implementing if we can figure out how to handle web.
Thanks for your comments!
Ok so let's go with this:
I think this would count as 2 jobs, so the reward would be $500
These are both relatively small changes, so @parasharrajat are you willing to work on those while we consider replacing the LHN with a Page? (@Julesssss 's suggestion)
I am on vacation. back on 8.
Enjoy! Take your time responding :)
Bump @parasharrajat :D
Ok. I am not yet sure what are we trying to fix in the R-navigation repo. @Beamanator. The issue I linked was only trying to disable the functionality to control the open-closed state of the drawer behind a flag.
So before we move, a few questions:
What is the problem, we are trying to fix on R-navigation repo?
Do we need to reopen the linked issue? If So, it only disables the back hardware key functionality for the drawer and we will still need to add the navigation in our app but the code would be much simpler than what I proposed.
Or do we want to add the back hardware button functionality to navigate back or close the app with drawer Navigator in r-navigation lib? If so, I didn't find any piece of code that does that in the codebase for r-navigation. I think is managed by react-native-screens.
Or, I think if we disable the back hardware key functionality for the drawer, we may not need the custom logic to handle it as It will be handled via Stack Navigator and thus should work fine.
@parasharrajat
As for where to make the changes, I would go with the smallest change in React-Navigation (as this is probably the easiest to get approved), then the rest in our app. So 2 or 4 - but honestly I can't really tell the difference between those proposals
If you havenโt already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Action Performed:
Expected Result:
Actual Result:
Workaround:
Platform:
Where is this issue occurring?
Version Number: Logs: https://stackoverflow.com/c/expensify/questions/4856 Notes/Photos/Videos: Any additional supporting documentation Upwork URL: https://www.upwork.com/jobs/~017e60e720f6f9aca8
View all open jobs on Upwork