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 Linking from 'expo-linking'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
import {i18n, type MessageDescriptor} from '@lingui/core' import {i18n, type MessageDescriptor} from '@lingui/core'
@@ -14,6 +14,7 @@ import {
DefaultTheme, DefaultTheme,
type LinkingOptions, type LinkingOptions,
NavigationContainer, NavigationContainer,
type NavigationState,
StackActions, StackActions,
} from '@react-navigation/native' } from '@react-navigation/native'
@@ -140,6 +141,7 @@ import {useAnalytics} from '#/analytics'
import {setNavigationMetadata} from '#/analytics/metadata' import {setNavigationMetadata} from '#/analytics/metadata'
import {IS_NATIVE, IS_WEB} from '#/env' import {IS_NATIVE, IS_WEB} from '#/env'
import {router} from '#/routes' import {router} from '#/routes'
import {device} from '#/storage'
import {Referrer} from '../modules/expo-bluesky-swiss-army' import {Referrer} from '../modules/expo-bluesky-swiss-army'
const navigationRef = createNavigationContainerRef<AllNavigatorParams>() const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@@ -886,6 +888,39 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
const closeAllActiveElements = useCloseAllActiveElements() const closeAllActiveElements = useCloseAllActiveElements()
const linkingUrl = Linking.useLinkingURL() 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. * Handle navigation to a conversation, or prepares for account switch.
* *
@@ -1012,10 +1047,11 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
return ( return (
<NavigationContainer <NavigationContainer
initialState={initialState}
ref={navigationRef} ref={navigationRef}
linking={LINKING} linking={LINKING}
theme={theme} theme={theme}
onStateChange={() => { onStateChange={state => {
const currentScreen = getCurrentRouteName() const currentScreen = getCurrentRouteName()
// do this before metric // do this before metric
setNavigationMetadata({ setNavigationMetadata({
@@ -1024,6 +1060,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
}) })
ax.metric('router:navigate', {from: previousScreen.current}) ax.metric('router:navigate', {from: previousScreen.current})
previousScreen.current = currentScreen previousScreen.current = currentScreen
persistState(state)
}} }}
onReady={onNavigationReady} onReady={onNavigationReady}
// WARNING: Implicit navigation to nested navigators is depreciated in React Navigation 7.x // 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 ID as PolicyUpdate202508} from '#/components/PolicyUpdateOverlay/updates/202508/config'
import {type Geolocation} from '#/geolocation/types' import {type Geolocation} from '#/geolocation/types'
@@ -66,6 +68,11 @@ export type Device = {
*/ */
policyUpdateDebugOverride?: boolean policyUpdateDebugOverride?: boolean
[PolicyUpdate202508]?: boolean [PolicyUpdate202508]?: boolean
navigationState?: {
did: string
state: InitialState
}
} }
export type Account = { export type Account = {