@@ -31,6 +31,9 @@ import {colors, darkColors} from '@/styles/colors'
3131import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
3232import { isLiquidGlassSupported as _isLiquidGlassSupported } from '@callstack/liquid-glass'
3333import { Platform , StatusBar , View , useColorScheme } from 'react-native'
34+ import AccountSwitchHeaderAvatar from './account-switch-header-avatar'
35+ import { clearPendingAccountSwitch , consumePendingAccountSwitchTab } from './account-switch'
36+ import { useCurrentUserState } from '@/stores/current-user'
3437const isLiquidGlassSupported = isMobile ? ( _isLiquidGlassSupported as boolean ) : false
3538// `bubble`/`bubble.fill` SF Symbols only exist on iOS 17+; older sims render blank.
3639const isIOS17Plus = isIOS && parseInt ( Platform . Version as string , 10 ) >= 17
@@ -304,13 +307,27 @@ const tabStackOptions = ({
304307 navigation,
305308} : {
306309 navigation : { canGoBack : ( ) => boolean }
307- } ) : NativeStackNavigationOptions => ( {
308- ...Common . defaultNavigationOptions ,
309- // Use the native back button (liquid glass pill on iOS 26) for non-root screens;
310- // omit headerLeft entirely on root screens so no empty glass circle appears.
311- headerBackVisible : navigation . canGoBack ( ) ,
312- headerLeft : undefined ,
313- } )
310+ } ) : NativeStackNavigationOptions => {
311+ const canGoBack = navigation . canGoBack ( )
312+ return {
313+ ...Common . defaultNavigationOptions ,
314+ // Root screens show the account switcher avatar. Pushed screens use the
315+ // native back button (liquid glass pill on iOS 26).
316+ headerBackVisible : canGoBack ,
317+ headerLeft : isAndroid && ! canGoBack ? ( ) => < AccountSwitchHeaderAvatar /> : undefined ,
318+ ...( isIOS && ! canGoBack
319+ ? {
320+ unstable_headerLeftItems : ( ) => [
321+ {
322+ element : < AccountSwitchHeaderAvatar /> ,
323+ hidesSharedBackground : true ,
324+ type : 'custom' as const ,
325+ } ,
326+ ] ,
327+ }
328+ : { } ) ,
329+ }
330+ }
314331
315332// On phones, each tab stack only contains its root screen. All other routes live in
316333// the root stack (alongside chatConversation) so they render above the tab bar.
@@ -581,9 +598,14 @@ const nativeLinkingConfig = isMobile ? createLinkingConfig(handleAppLink) : unde
581598function NativeRouter ( ) {
582599 const loggedInLoaded = useHandshakeEverDone ( )
583600
584- const { loggedIn, startupLoaded} = useConfigState (
585- C . useShallow ( s => ( { loggedIn : s . loggedIn , startupLoaded : s . startup . loaded } ) )
601+ const { loggedIn, startupLoaded, userSwitching} = useConfigState (
602+ C . useShallow ( s => ( {
603+ loggedIn : s . loggedIn ,
604+ startupLoaded : s . startup . loaded ,
605+ userSwitching : s . userSwitching ,
606+ } ) )
586607 )
608+ const username = useCurrentUserState ( s => s . username )
587609
588610 const { barStyle, isDarkMode} = useDarkModeState (
589611 C . useShallow ( s => {
@@ -597,13 +619,28 @@ function NativeRouter() {
597619 return { barStyle, isDarkMode}
598620 } )
599621 )
622+
600623 const bar = barStyle === 'default' ? null : < StatusBar barStyle = { barStyle } />
601624 // Android also remounts on dark mode changes
602625 const nativeIsDarkMode = useColorScheme ( ) === 'dark'
603626 const navKey = Common . useUserSwitchNavKey ( )
604627 const nativeDarkSuffix = isAndroid ? ( nativeIsDarkMode ? '-dark' : '-light' ) : ''
605628 const rootKey = navKey ? `${ navKey } ${ nativeDarkSuffix } ` : ''
606629
630+ React . useEffect ( ( ) => {
631+ if ( ! userSwitching ) {
632+ clearPendingAccountSwitch ( username )
633+ }
634+ } , [ userSwitching , username ] )
635+
636+ const onNativeReady = ( ) => {
637+ onStateChange ( )
638+ const tab = consumePendingAccountSwitchTab ( username )
639+ if ( tab ) {
640+ C . Router2 . switchTab ( tab )
641+ }
642+ }
643+
607644 if ( ! loggedInLoaded || ( loggedIn && ! startupLoaded ) ) {
608645 return (
609646 < Kb . Box2 direction = "vertical" style = { Kb . Styles . globalStyles . fillAbsolute } >
@@ -621,7 +658,7 @@ function NativeRouter() {
621658 // Sync the initial state from the linking config into the router store.
622659 // onStateChange doesn't fire for the initial state, so this ensures
623660 // onRouteChanged runs and conversation data gets loaded on startup.
624- onReady = { onStateChange }
661+ onReady = { onNativeReady }
625662 onStateChange = { onStateChange }
626663 onUnhandledAction = { onUnhandledAction }
627664 ref = { setNavRef }
0 commit comments