my fork of the bluesky client
1import '#/lib/sentry' // must be near top
2import '#/view/icons'
3import './style.css'
4
5import React, {useEffect, useState} from 'react'
6import {RootSiblingParent} from 'react-native-root-siblings'
7import {SafeAreaProvider} from 'react-native-safe-area-context'
8import {msg} from '@lingui/macro'
9import {useLingui} from '@lingui/react'
10
11import {QueryProvider} from '#/lib/react-query'
12import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
13import {ThemeProvider} from '#/lib/ThemeContext'
14import I18nProvider from '#/locale/i18nProvider'
15import {logger} from '#/logger'
16import {Provider as A11yProvider} from '#/state/a11y'
17import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
18import {Provider as DialogStateProvider} from '#/state/dialogs'
19import {listenSessionDropped} from '#/state/events'
20import {
21 beginResolveGeolocation,
22 ensureGeolocationResolved,
23 Provider as GeolocationProvider,
24} from '#/state/geolocation'
25import {Provider as InvitesStateProvider} from '#/state/invites'
26import {Provider as LightboxStateProvider} from '#/state/lightbox'
27import {MessagesProvider} from '#/state/messages'
28import {Provider as ModalStateProvider} from '#/state/modals'
29import {init as initPersistedState} from '#/state/persisted'
30import {Provider as PrefsStateProvider} from '#/state/preferences'
31import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
32import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
33import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
34import {
35 Provider as SessionProvider,
36 SessionAccount,
37 useSession,
38 useSessionApi,
39} from '#/state/session'
40import {readLastActiveAccount} from '#/state/session/util'
41import {Provider as ShellStateProvider} from '#/state/shell'
42import {Provider as ComposerProvider} from '#/state/shell/composer'
43import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
44import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
45import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
46import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
47import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
48import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext'
49import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
50import * as Toast from '#/view/com/util/Toast'
51import {ToastContainer} from '#/view/com/util/Toast.web'
52import {Shell} from '#/view/shell/index'
53import {ThemeProvider as Alf} from '#/alf'
54import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
55import {NuxDialogs} from '#/components/dialogs/nuxs'
56import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
57import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
58import {Provider as PortalProvider} from '#/components/Portal'
59import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
60
61/**
62 * Begin geolocation ASAP
63 */
64beginResolveGeolocation()
65
66function InnerApp() {
67 const [isReady, setIsReady] = React.useState(false)
68 const {currentAccount} = useSession()
69 const {resumeSession} = useSessionApi()
70 const theme = useColorModeTheme()
71 const {_} = useLingui()
72 const hasCheckedReferrer = useStarterPackEntry()
73
74 // init
75 useEffect(() => {
76 async function onLaunch(account?: SessionAccount) {
77 try {
78 if (account) {
79 await resumeSession(account)
80 }
81 } catch (e) {
82 logger.error(`session: resumeSession failed`, {message: e})
83 } finally {
84 setIsReady(true)
85 }
86 }
87 const account = readLastActiveAccount()
88 onLaunch(account)
89 }, [resumeSession])
90
91 useEffect(() => {
92 return listenSessionDropped(() => {
93 Toast.show(
94 _(msg`Sorry! Your session expired. Please log in again.`),
95 'info',
96 )
97 })
98 }, [_])
99
100 // wait for session to resume
101 if (!isReady || !hasCheckedReferrer) return null
102
103 return (
104 <Alf theme={theme}>
105 <ThemeProvider theme={theme}>
106 <RootSiblingParent>
107 <VideoVolumeProvider>
108 <ActiveVideoProvider>
109 <React.Fragment
110 // Resets the entire tree below when it changes:
111 key={currentAccount?.did}>
112 <QueryProvider currentDid={currentAccount?.did}>
113 <ComposerProvider>
114 <StatsigProvider>
115 <MessagesProvider>
116 {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
117 <LabelDefsProvider>
118 <ModerationOptsProvider>
119 <LoggedOutViewProvider>
120 <SelectedFeedProvider>
121 <HiddenRepliesProvider>
122 <UnreadNotifsProvider>
123 <BackgroundNotificationPreferencesProvider>
124 <MutedThreadsProvider>
125 <SafeAreaProvider>
126 <ProgressGuideProvider>
127 <Shell />
128 <NuxDialogs />
129 </ProgressGuideProvider>
130 </SafeAreaProvider>
131 </MutedThreadsProvider>
132 </BackgroundNotificationPreferencesProvider>
133 </UnreadNotifsProvider>
134 </HiddenRepliesProvider>
135 </SelectedFeedProvider>
136 </LoggedOutViewProvider>
137 </ModerationOptsProvider>
138 </LabelDefsProvider>
139 </MessagesProvider>
140 </StatsigProvider>
141 </ComposerProvider>
142 </QueryProvider>
143 <ToastContainer />
144 </React.Fragment>
145 </ActiveVideoProvider>
146 </VideoVolumeProvider>
147 </RootSiblingParent>
148 </ThemeProvider>
149 </Alf>
150 )
151}
152
153function App() {
154 const [isReady, setReady] = useState(false)
155
156 React.useEffect(() => {
157 Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
158 setReady(true),
159 )
160 }, [])
161
162 if (!isReady) {
163 return null
164 }
165
166 /*
167 * NOTE: only nothing here can depend on other data or session state, since
168 * that is set up in the InnerApp component above.
169 */
170 return (
171 <GeolocationProvider>
172 <A11yProvider>
173 <SessionProvider>
174 <PrefsStateProvider>
175 <I18nProvider>
176 <ShellStateProvider>
177 <InvitesStateProvider>
178 <ModalStateProvider>
179 <DialogStateProvider>
180 <LightboxStateProvider>
181 <PortalProvider>
182 <StarterPackProvider>
183 <IntentDialogProvider>
184 <InnerApp />
185 </IntentDialogProvider>
186 </StarterPackProvider>
187 </PortalProvider>
188 </LightboxStateProvider>
189 </DialogStateProvider>
190 </ModalStateProvider>
191 </InvitesStateProvider>
192 </ShellStateProvider>
193 </I18nProvider>
194 </PrefsStateProvider>
195 </SessionProvider>
196 </A11yProvider>
197 </GeolocationProvider>
198 )
199}
200
201export default App