You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Android - Copilot - Account switcher list appears behind device navigation bar #94081
Version Number: 9.4.16-1 Reproducible in staging?: Yes Reproducible in production?: No If this was caught during regression testing, add the test name, ID and link from BrowserStack:#88578 Email or phone of affected tester (no customers):sdjnoisdjdosijsonssjo@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Samsung Galaxy S25 FE / Android 16 App Component: User Settings
Action Performed:
Precondition:
Set device navigation to bar instead of gestures.
Add 6 copilots to the account
Launch Expensify app.
Go to Account.
Open account switcher.
Scroll down the list.
Expected Result:
Account switcher list will appear above device navigation bar.
Actual Result:
Account switcher list appears behind device navigation bar.
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Identify the pull request that introduced this issue and revert it.
🤖 Generated by MelvinBot · confidence: medium-high (mechanism verified in code; the exact in-modal inset value of 0 should be confirmed on an Android device with a 3-button nav bar).
Reproduce
Android, 3-button navigation bar, 6 copilots → open the account switcher and scroll. The bottom of the list renders behind the nav bar instead of above it.
Root cause
Regression from Expensify/App#88578 ("fix: bottom-safe-area-padding-in-modals (part 1)"), which is why this is staging-only (the PR hasn't reached production).
That PR changed AccountSwitcher.tsx to drop the hardcoded scrollContainerStyle={styles.pb4} and instead pass enableEdgeToEdgeBottomSafeAreaPadding. That flag flips the modal into edge-to-edge mode, and in that mode the modal stops adding its own bottom safe-area padding — see BaseModal.tsx:259-265:
The bottom inset is now expected to be applied by the child ScrollView addBottomSafeAreaPadding instead. But that ScrollView is rendered inside the native RN Modal (ReanimatedModal/index.tsx:5), and there is no SafeAreaProvider/SafeAreaInsetsContext re-established inside that modal window. So useSafeAreaInsets().bottom resolves to ~0 there, and paddingBottom = insets.bottom * 1 = 0 (useSafeAreaPaddings.ts:36,48).
Net effect: the modal padding was turned off, and its intended replacement evaluates to 0 → no bottom padding at all → scrollable content slides under the nav bar. Gesture nav has a near-zero inset, so it only shows with a 3-button nav bar.
The strongest tell that the inset is unavailable inside the modal: BaseModal reads insets from the outer tree (where they're correct) and used them for the modal's own padding pre-PR — edge-to-edge mode discards that correct value and relies on a child that can't see it.
Why the other 5 modals in the PR don't obviously break
AccountSwitcher is the only one combining shouldUseScrollView + a tall maxHeight: windowHeight / 2 container that actually reaches the nav bar with enough rows to scroll. The same latent zero-inset issue likely affects the others but isn't visible unless their content extends to the bottom edge. Worth spot-checking before a broad fix.
Solution
For the deploy blocker, the lowest-risk fix is to revert just the AccountSwitcher change at AccountSwitcher.tsx:305-310: restore scrollContainerStyle={styles.pb4} and remove enableEdgeToEdgeBottomSafeAreaPadding. This brings back the modal's own bottom safe-area padding (known-good in production).
Alternative (proper edge-to-edge follow-up)
Keep edge-to-edge but make the inset reach the content inside the modal — e.g. in BaseModal (edge-to-edge branch) wrap the children in <SafeAreaInsetsContext.Provider value={insets}> seeded with the already-correct outer insets, or pass the outer insets.bottom down as additionalPaddingBottom. This would also harden the other 5 modals. Higher risk; better as a non-blocker PR.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/94081) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
Activity
applause-bot commentedon Jun 19, 2026
While Applause doesn't embed attachments for this bug, here are the links for quick view:
https://platform.applause.com/services/links/v1/external/9137123d4f5b1f841386fd1c6ffbb612fc179340ed02df837d293151f2f4d2a9
melvin-bot commentedon Jun 19, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #88578
melvin-bot commentedon Jun 19, 2026
💬 A slack conversation has been started in #expensify-open-source
github-actions commentedon Jun 19, 2026
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
MelvinBot commentedon Jun 19, 2026
Proposal
Reproduce
Android, 3-button navigation bar, 6 copilots → open the account switcher and scroll. The bottom of the list renders behind the nav bar instead of above it.
Root cause
Regression from
Expensify/App#88578("fix: bottom-safe-area-padding-in-modals (part 1)"), which is why this is staging-only (the PR hasn't reached production).That PR changed
AccountSwitcher.tsxto drop the hardcodedscrollContainerStyle={styles.pb4}and instead passenableEdgeToEdgeBottomSafeAreaPadding. That flag flips the modal into edge-to-edge mode, and in that mode the modal stops adding its own bottom safe-area padding — seeBaseModal.tsx:259-265:The bottom inset is now expected to be applied by the child
ScrollView addBottomSafeAreaPaddinginstead. But thatScrollViewis rendered inside the native RNModal(ReanimatedModal/index.tsx:5), and there is noSafeAreaProvider/SafeAreaInsetsContextre-established inside that modal window. SouseSafeAreaInsets().bottomresolves to ~0 there, andpaddingBottom = insets.bottom * 1 = 0(useSafeAreaPaddings.ts:36,48).Net effect: the modal padding was turned off, and its intended replacement evaluates to 0 → no bottom padding at all → scrollable content slides under the nav bar. Gesture nav has a near-zero inset, so it only shows with a 3-button nav bar.
The strongest tell that the inset is unavailable inside the modal:
BaseModalreadsinsetsfrom the outer tree (where they're correct) and used them for the modal's own padding pre-PR — edge-to-edge mode discards that correct value and relies on a child that can't see it.Why the other 5 modals in the PR don't obviously break
AccountSwitcher is the only one combining
shouldUseScrollView+ a tallmaxHeight: windowHeight / 2container that actually reaches the nav bar with enough rows to scroll. The same latent zero-inset issue likely affects the others but isn't visible unless their content extends to the bottom edge. Worth spot-checking before a broad fix.Solution
For the deploy blocker, the lowest-risk fix is to revert just the AccountSwitcher change at
AccountSwitcher.tsx:305-310: restorescrollContainerStyle={styles.pb4}and removeenableEdgeToEdgeBottomSafeAreaPadding. This brings back the modal's own bottom safe-area padding (known-good in production).Alternative (proper edge-to-edge follow-up)
Keep edge-to-edge but make the inset reach the content inside the modal — e.g. in
BaseModal(edge-to-edge branch) wrap the children in<SafeAreaInsetsContext.Provider value={insets}>seeded with the already-correct outerinsets, or pass the outerinsets.bottomdown asadditionalPaddingBottom. This would also harden the other 5 modals. Higher risk; better as a non-blocker PR.Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/94081)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
truph01 commentedon Jun 20, 2026
It looks like an expected behavior:
Screen.Recording.2026-06-20.at.10.07.43.mov
mountiny commentedon Jun 21, 2026
@truph01 Can you try with the Samsung Galaxy S25 FE / Android 16 device?
mountiny commentedon Jun 21, 2026
Demoting as its minor and looks like its device specific, we will try to fix this quick though
melvin-bot commentedon Jun 24, 2026
@truph01 Whoops! This issue is 2 days overdue. Let's get this updated quick!
truph01 commentedon Jun 25, 2026
Not overdue
shubham1206agra commentedon Jun 29, 2026
@mountiny Can we close this?