Bluesky app fork with some witchin' additions 💫

Restructure notification/linking handling to use synchronous APIs (#9497)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Eric Bailey <git@esb.lol>

authored by samuel.fm

Claude Opus 4.6
Eric Bailey
and committed by
GitHub
bdf143ce adc079e0

+20 -24
+20 -24
src/Navigation.tsx
··· 1 import {type JSX, useCallback, useRef} from 'react' 2 - import {Linking} from 'react-native' 3 import * as Notifications from 'expo-notifications' 4 import {i18n, type MessageDescriptor} from '@lingui/core' 5 import {msg} from '@lingui/macro' ··· 874 }, 875 } satisfies LinkingOptions<AllNavigatorParams> 876 877 - /** 878 - * Used to ensure we don't handle the same notification twice 879 - */ 880 - let lastHandledNotificationDateDedupe: number | undefined 881 - 882 function RoutesContainer({children}: React.PropsWithChildren<{}>) { 883 const ax = useAnalytics() 884 const notyLogger = ax.logger.useChild(ax.logger.Context.Notifications) ··· 889 const previousScreen = useRef<string | undefined>(undefined) 890 const emailDialogControl = useEmailDialogControl() 891 const closeAllActiveElements = useCloseAllActiveElements() 892 893 /** 894 * Handle navigation to a conversation, or prepares for account switch. ··· 923 }, 924 ) 925 926 - async function handlePushNotificationEntry() { 927 if (!IS_NATIVE) return 928 929 - // deep links take precedence - on android, 930 - // getLastNotificationResponseAsync returns a "notification" 931 - // that is actually a deep link. avoid handling it twice -sfn 932 - if (await Linking.getInitialURL()) { 933 - return 934 - } 935 - 936 - /** 937 - * The notification that caused the app to open, if applicable 938 - */ 939 - const response = await Notifications.getLastNotificationResponseAsync() 940 941 - if (response) { 942 - notyLogger.debug(`handlePushNotificationEntry: response`, {response}) 943 944 - if (response.notification.date === lastHandledNotificationDateDedupe) 945 - return 946 - lastHandledNotificationDateDedupe = response.notification.date 947 948 - const payload = getNotificationPayload(response.notification) 949 950 if (payload) { 951 ax.metric('notifications:openApp', {
··· 1 import {type JSX, useCallback, useRef} from 'react' 2 + import * as Linking from 'expo-linking' 3 import * as Notifications from 'expo-notifications' 4 import {i18n, type MessageDescriptor} from '@lingui/core' 5 import {msg} from '@lingui/macro' ··· 874 }, 875 } satisfies LinkingOptions<AllNavigatorParams> 876 877 function RoutesContainer({children}: React.PropsWithChildren<{}>) { 878 const ax = useAnalytics() 879 const notyLogger = ax.logger.useChild(ax.logger.Context.Notifications) ··· 884 const previousScreen = useRef<string | undefined>(undefined) 885 const emailDialogControl = useEmailDialogControl() 886 const closeAllActiveElements = useCloseAllActiveElements() 887 + const linkingUrl = Linking.useLinkingURL() 888 + const notificationResponse = Notifications.useLastNotificationResponse() 889 890 /** 891 * Handle navigation to a conversation, or prepares for account switch. ··· 920 }, 921 ) 922 923 + function handlePushNotificationEntry() { 924 if (!IS_NATIVE) return 925 926 + // intent urls are handled by `useIntentHandler` 927 + if (linkingUrl) return 928 929 + if (notificationResponse) { 930 + notyLogger.debug(`handlePushNotificationEntry: response`, { 931 + response: notificationResponse, 932 + }) 933 934 + // Clear the last notification response to ensure it's not used again 935 + try { 936 + Notifications.clearLastNotificationResponse() 937 + } catch (error) { 938 + notyLogger.error( 939 + `handlePushNotificationEntry: error clearing notification response`, 940 + {error}, 941 + ) 942 + } 943 944 + const payload = getNotificationPayload(notificationResponse.notification) 945 946 if (payload) { 947 ax.metric('notifications:openApp', {