Persist navigation state

This commit is contained in:
Samuel Newman
2025-12-06 21:26:24 +02:00
parent 80c0aa35e2
commit f1a814c59d
2 changed files with 46 additions and 2 deletions
+39 -2
View File
@@ -1,4 +1,4 @@
import {type JSX, useCallback, useRef} from 'react'
import {type JSX, useCallback, useRef, useState} from 'react'
import * as Linking from 'expo-linking'
import * as Notifications from 'expo-notifications'
import {i18n, type MessageDescriptor} from '@lingui/core'
@@ -14,6 +14,7 @@ import {
DefaultTheme,
type LinkingOptions,
NavigationContainer,
type NavigationState,
StackActions,
} from '@react-navigation/native'
@@ -140,6 +141,7 @@ import {useAnalytics} from '#/analytics'
import {setNavigationMetadata} from '#/analytics/metadata'
import {IS_NATIVE, IS_WEB} from '#/env'
import {router} from '#/routes'
import {device} from '#/storage'
import {Referrer} from '../modules/expo-bluesky-swiss-army'
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@@ -886,6 +888,39 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
const closeAllActiveElements = useCloseAllActiveElements()
const linkingUrl = Linking.useLinkingURL()
const [initialState] = useState(() => {
if (!IS_NATIVE) return
const previousNavState = device.get(['navigationState'])
if (previousNavState) {
// we want to clear it asap - even if we don't use it
// if they're opening it via an intent, we obviously prioritize the intent
// but also the *subsequent* open after that, it would be weird if it restored to the
// nav state *before* that, hence the aggressive clearing -sfn
device.remove(['navigationState'])
// we only want to use it if the current state is more-or-less where they left off:
// - logged in to the same account
// - no intent
// - not handling a notification
if (linkingUrl) return
if (notificationResponse) return
if (previousNavState.did !== currentAccount?.did) {
return
}
return previousNavState.state
}
})
const persistState = (state?: NavigationState) => {
if (!IS_NATIVE) return
if (!currentAccount) return
if (!state) return
device.set(['navigationState'], {did: currentAccount.did, state})
}
/**
* Handle navigation to a conversation, or prepares for account switch.
*
@@ -1012,10 +1047,11 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
return (
<NavigationContainer
initialState={initialState}
ref={navigationRef}
linking={LINKING}
theme={theme}
onStateChange={() => {
onStateChange={state => {
const currentScreen = getCurrentRouteName()
// do this before metric
setNavigationMetadata({
@@ -1024,6 +1060,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
})
ax.metric('router:navigate', {from: previousScreen.current})
previousScreen.current = currentScreen
persistState(state)
}}
onReady={onNavigationReady}
// WARNING: Implicit navigation to nested navigators is depreciated in React Navigation 7.x
+7
View File
@@ -1,3 +1,5 @@
import {type InitialState} from '@react-navigation/native'
import {type ID as PolicyUpdate202508} from '#/components/PolicyUpdateOverlay/updates/202508/config'
import {type Geolocation} from '#/geolocation/types'
@@ -66,6 +68,11 @@ export type Device = {
*/
policyUpdateDebugOverride?: boolean
[PolicyUpdate202508]?: boolean
navigationState?: {
did: string
state: InitialState
}
}
export type Account = {