add mechanism for running navigation actions when it's ready
This commit is contained in:
+7
-2
@@ -123,6 +123,7 @@ import {QuoteNotificationSettingsScreen} from './screens/Settings/NotificationSe
|
|||||||
import {ReplyNotificationSettingsScreen} from './screens/Settings/NotificationSettings/ReplyNotificationSettings'
|
import {ReplyNotificationSettingsScreen} from './screens/Settings/NotificationSettings/ReplyNotificationSettings'
|
||||||
import {RepostNotificationSettingsScreen} from './screens/Settings/NotificationSettings/RepostNotificationSettings'
|
import {RepostNotificationSettingsScreen} from './screens/Settings/NotificationSettings/RepostNotificationSettings'
|
||||||
import {RepostsOnRepostsNotificationSettingsScreen} from './screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings'
|
import {RepostsOnRepostsNotificationSettingsScreen} from './screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings'
|
||||||
|
import {NavigationAvailable} from './state/shell/navigation-available'
|
||||||
|
|
||||||
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
||||||
|
|
||||||
@@ -825,6 +826,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const prevLoggedRouteName = React.useRef<string | undefined>(undefined)
|
const prevLoggedRouteName = React.useRef<string | undefined>(undefined)
|
||||||
const emailDialogControl = useEmailDialogControl()
|
const emailDialogControl = useEmailDialogControl()
|
||||||
|
const navigationAvailableRef = React.useRef<{onReady: () => void}>(null)
|
||||||
|
|
||||||
function onReady() {
|
function onReady() {
|
||||||
prevLoggedRouteName.current = getCurrentRouteName()
|
prevLoggedRouteName.current = getCurrentRouteName()
|
||||||
@@ -837,7 +839,9 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<NavigationAvailable
|
||||||
|
ref={navigationAvailableRef}
|
||||||
|
navigationRef={navigationRef}>
|
||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
ref={navigationRef}
|
ref={navigationRef}
|
||||||
linking={LINKING}
|
linking={LINKING}
|
||||||
@@ -856,6 +860,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
attachRouteToLogEvents(getCurrentRouteName)
|
attachRouteToLogEvents(getCurrentRouteName)
|
||||||
logModuleInitTime()
|
logModuleInitTime()
|
||||||
onReady()
|
onReady()
|
||||||
|
navigationAvailableRef.current?.onReady()
|
||||||
logger.metric('router:navigate', {}, {statsig: false})
|
logger.metric('router:navigate', {}, {statsig: false})
|
||||||
}}
|
}}
|
||||||
// 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
|
||||||
@@ -867,7 +872,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
navigationInChildEnabled>
|
navigationInChildEnabled>
|
||||||
{children}
|
{children}
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
</>
|
</NavigationAvailable>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {invalidateCachedUnreadPage} from '#/state/queries/notifications/unread'
|
|||||||
import {truncateAndInvalidate} from '#/state/queries/util'
|
import {truncateAndInvalidate} from '#/state/queries/util'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
|
import {useRunWhenNavigationAvailable} from '#/state/shell/navigation-available'
|
||||||
import {useCloseAllActiveElements} from '#/state/util'
|
import {useCloseAllActiveElements} from '#/state/util'
|
||||||
import {resetToTab} from '#/Navigation'
|
import {resetToTab} from '#/Navigation'
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ export function useNotificationsHandler() {
|
|||||||
const {currentConvoId} = useCurrentConvoId()
|
const {currentConvoId} = useCurrentConvoId()
|
||||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||||
const closeAllActiveElements = useCloseAllActiveElements()
|
const closeAllActiveElements = useCloseAllActiveElements()
|
||||||
|
const runWhenNavigationAvailable = useRunWhenNavigationAvailable()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
// On Android, we cannot control which sound is used for a notification on Android
|
// On Android, we cannot control which sound is used for a notification on Android
|
||||||
@@ -228,10 +230,17 @@ export function useNotificationsHandler() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (payload.reason) {
|
switch (payload.reason) {
|
||||||
|
case 'like':
|
||||||
|
case 'repost':
|
||||||
|
case 'reply':
|
||||||
|
case 'quote':
|
||||||
|
case 'mention':
|
||||||
|
case 'like-via-repost':
|
||||||
|
case 'repost-via-repost':
|
||||||
case 'subscribed-post':
|
case 'subscribed-post':
|
||||||
const urip = new AtUri(payload.uri)
|
runWhenNavigationAvailable(() => {
|
||||||
if (urip.collection === 'app.bsky.feed.post') {
|
const urip = new AtUri(payload.uri)
|
||||||
setTimeout(() => {
|
if (urip.collection === 'app.bsky.feed.post') {
|
||||||
// @ts-expect-error types are weird here
|
// @ts-expect-error types are weird here
|
||||||
navigation.navigate('HomeTab', {
|
navigation.navigate('HomeTab', {
|
||||||
screen: 'PostThread',
|
screen: 'PostThread',
|
||||||
@@ -240,51 +249,29 @@ export function useNotificationsHandler() {
|
|||||||
rkey: urip.rkey,
|
rkey: urip.rkey,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}, 500)
|
} else {
|
||||||
} else {
|
resetToTab('NotificationsTab')
|
||||||
resetToTab('NotificationsTab')
|
}
|
||||||
}
|
})
|
||||||
break
|
break
|
||||||
case 'like':
|
|
||||||
case 'repost':
|
|
||||||
case 'follow':
|
case 'follow':
|
||||||
case 'mention':
|
|
||||||
case 'quote':
|
|
||||||
case 'reply':
|
|
||||||
case 'starterpack-joined':
|
case 'starterpack-joined':
|
||||||
case 'like-via-repost':
|
runWhenNavigationAvailable(() => {
|
||||||
case 'repost-via-repost':
|
const urip = new AtUri(payload.uri)
|
||||||
|
// @ts-expect-error types are weird here
|
||||||
|
navigation.navigate('HomeTab', {
|
||||||
|
screen: 'Profile',
|
||||||
|
params: {
|
||||||
|
name: urip.host,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
break
|
||||||
case 'verified':
|
case 'verified':
|
||||||
case 'unverified':
|
case 'unverified':
|
||||||
default:
|
default:
|
||||||
resetToTab('NotificationsTab')
|
resetToTab('NotificationsTab')
|
||||||
break
|
break
|
||||||
// TODO implement these after we have an idea of how to handle each individual case
|
|
||||||
// case 'follow':
|
|
||||||
// const uri = new AtUri(payload.uri)
|
|
||||||
// setTimeout(() => {
|
|
||||||
// // @ts-expect-error types are weird here
|
|
||||||
// navigation.navigate('HomeTab', {
|
|
||||||
// screen: 'Profile',
|
|
||||||
// params: {
|
|
||||||
// name: uri.host,
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// }, 500)
|
|
||||||
// break
|
|
||||||
// case 'mention':
|
|
||||||
// case 'reply':
|
|
||||||
// const urip = new AtUri(payload.uri)
|
|
||||||
// setTimeout(() => {
|
|
||||||
// // @ts-expect-error types are weird here
|
|
||||||
// navigation.navigate('HomeTab', {
|
|
||||||
// screen: 'PostThread',
|
|
||||||
// params: {
|
|
||||||
// name: urip.host,
|
|
||||||
// rkey: urip.rkey,
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// }, 500)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,5 +403,6 @@ export function useNotificationsHandler() {
|
|||||||
navigation,
|
navigation,
|
||||||
onPressSwitchAccount,
|
onPressSwitchAccount,
|
||||||
setShowLoggedOut,
|
setShowLoggedOut,
|
||||||
|
runWhenNavigationAvailable,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import {createContext, useContext, useImperativeHandle, useState} from 'react'
|
||||||
|
import {type NavigationContainerRefWithCurrent} from '@react-navigation/native'
|
||||||
|
|
||||||
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
|
import {type AllNavigatorParams} from '#/lib/routes/types'
|
||||||
|
|
||||||
|
type QueueAction = () => void
|
||||||
|
const NavigationAvailableContext = createContext<
|
||||||
|
((cb: QueueAction) => void) | null
|
||||||
|
>(null)
|
||||||
|
|
||||||
|
export function NavigationAvailable({
|
||||||
|
children,
|
||||||
|
ref,
|
||||||
|
navigationRef,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
ref: React.Ref<{onReady: () => void}>
|
||||||
|
navigationRef: NavigationContainerRefWithCurrent<AllNavigatorParams>
|
||||||
|
}) {
|
||||||
|
const [queue, setQueue] = useState<QueueAction[]>([])
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
onReady: () => {
|
||||||
|
for (const item of queue) {
|
||||||
|
item()
|
||||||
|
}
|
||||||
|
setQueue([])
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const runWhenNavigationAvailable = useNonReactiveCallback(
|
||||||
|
(cb: QueueAction) => {
|
||||||
|
if (navigationRef.isReady()) {
|
||||||
|
cb()
|
||||||
|
} else {
|
||||||
|
setQueue(prev => [...prev, cb])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigationAvailableContext.Provider value={runWhenNavigationAvailable}>
|
||||||
|
{children}
|
||||||
|
</NavigationAvailableContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRunWhenNavigationAvailable() {
|
||||||
|
const context = useContext(NavigationAvailableContext)
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
'useRunWhenNavigationAvailable must be used within a NavigationAvailable component',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user