mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import '#/logger/sentry/setup'
2import '#/logger/bitdrift/setup'
3import '#/view/icons'
4
5import React, {useEffect, useState} from 'react'
6import {GestureHandlerRootView} from 'react-native-gesture-handler'
7import {RootSiblingParent} from 'react-native-root-siblings'
8import {
9 initialWindowMetrics,
10 SafeAreaProvider,
11} from 'react-native-safe-area-context'
12import * as ScreenOrientation from 'expo-screen-orientation'
13import * as SplashScreen from 'expo-splash-screen'
14import * as SystemUI from 'expo-system-ui'
15import {msg} from '@lingui/macro'
16import {useLingui} from '@lingui/react'
17import * as Sentry from '@sentry/react-native'
18
19import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController'
20import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder'
21import {QueryProvider} from '#/lib/react-query'
22import {Provider as StatsigProvider, tryFetchGates} from '#/lib/statsig/statsig'
23import {s} from '#/lib/styles'
24import {ThemeProvider} from '#/lib/ThemeContext'
25import I18nProvider from '#/locale/i18nProvider'
26import {logger} from '#/logger'
27import {isAndroid, isIOS} from '#/platform/detection'
28import {Provider as A11yProvider} from '#/state/a11y'
29import {Provider as AgeAssuranceProvider} from '#/state/ageAssurance'
30import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
31import {Provider as DialogStateProvider} from '#/state/dialogs'
32import {Provider as EmailVerificationProvider} from '#/state/email-verification'
33import {listenSessionDropped} from '#/state/events'
34import {
35 beginResolveGeolocation,
36 ensureGeolocationResolved,
37 Provider as GeolocationProvider,
38} from '#/state/geolocation'
39import {GlobalGestureEventsProvider} from '#/state/global-gesture-events'
40import {Provider as HomeBadgeProvider} from '#/state/home-badge'
41import {Provider as InvitesStateProvider} from '#/state/invites'
42import {Provider as LightboxStateProvider} from '#/state/lightbox'
43import {MessagesProvider} from '#/state/messages'
44import {Provider as ModalStateProvider} from '#/state/modals'
45import {init as initPersistedState} from '#/state/persisted'
46import {Provider as PrefsStateProvider} from '#/state/preferences'
47import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
48import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
49import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
50import {Provider as ServiceAccountManager} from '#/state/service-config'
51import {
52 Provider as SessionProvider,
53 type SessionAccount,
54 useSession,
55 useSessionApi,
56} from '#/state/session'
57import {readLastActiveAccount} from '#/state/session/util'
58import {Provider as ShellStateProvider} from '#/state/shell'
59import {Provider as ComposerProvider} from '#/state/shell/composer'
60import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
61import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
62import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
63import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
64import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
65import {TestCtrls} from '#/view/com/testing/TestCtrls'
66import * as Toast from '#/view/com/util/Toast'
67import {Shell} from '#/view/shell'
68import {ThemeProvider as Alf} from '#/alf'
69import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
70import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
71import {NuxDialogs} from '#/components/dialogs/nuxs'
72import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
73import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
74import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
75import {Provider as PortalProvider} from '#/components/Portal'
76import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
77import {ToastOutlet} from '#/components/Toast'
78import {Splash} from '#/Splash'
79import {BottomSheetProvider} from '../modules/bottom-sheet'
80import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
81
82SplashScreen.preventAutoHideAsync()
83if (isIOS) {
84 SystemUI.setBackgroundColorAsync('black')
85}
86if (isAndroid) {
87 // iOS is handled by the config plugin -sfn
88 ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP)
89}
90
91/**
92 * Begin geolocation ASAP
93 */
94beginResolveGeolocation()
95
96function InnerApp() {
97 const [isReady, setIsReady] = React.useState(false)
98 const {currentAccount} = useSession()
99 const {resumeSession} = useSessionApi()
100 const theme = useColorModeTheme()
101 const {_} = useLingui()
102 const hasCheckedReferrer = useStarterPackEntry()
103
104 // init
105 useEffect(() => {
106 async function onLaunch(account?: SessionAccount) {
107 try {
108 if (account) {
109 await resumeSession(account)
110 } else {
111 await tryFetchGates(undefined, 'prefer-fresh-gates')
112 }
113 } catch (e) {
114 logger.error(`session: resume failed`, {message: e})
115 } finally {
116 setIsReady(true)
117 }
118 }
119 const account = readLastActiveAccount()
120 onLaunch(account)
121 }, [resumeSession])
122
123 useEffect(() => {
124 return listenSessionDropped(() => {
125 Toast.show(
126 _(msg`Sorry! Your session expired. Please sign in again.`),
127 'info',
128 )
129 })
130 }, [_])
131
132 return (
133 <Alf theme={theme}>
134 <ThemeProvider theme={theme}>
135 <ContextMenuProvider>
136 <Splash isReady={isReady && hasCheckedReferrer}>
137 <RootSiblingParent>
138 <VideoVolumeProvider>
139 <React.Fragment
140 // Resets the entire tree below when it changes:
141 key={currentAccount?.did}>
142 <QueryProvider currentDid={currentAccount?.did}>
143 <PolicyUpdateOverlayProvider>
144 <StatsigProvider>
145 <AgeAssuranceProvider>
146 <ComposerProvider>
147 <MessagesProvider>
148 {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
149 <LabelDefsProvider>
150 <ModerationOptsProvider>
151 <LoggedOutViewProvider>
152 <SelectedFeedProvider>
153 <HiddenRepliesProvider>
154 <HomeBadgeProvider>
155 <UnreadNotifsProvider>
156 <BackgroundNotificationPreferencesProvider>
157 <MutedThreadsProvider>
158 <ProgressGuideProvider>
159 <ServiceAccountManager>
160 <EmailVerificationProvider>
161 <HideBottomBarBorderProvider>
162 <GestureHandlerRootView
163 style={s.h100pct}>
164 <GlobalGestureEventsProvider>
165 <IntentDialogProvider>
166 <TestCtrls />
167 <Shell />
168 <NuxDialogs />
169 <ToastOutlet />
170 </IntentDialogProvider>
171 </GlobalGestureEventsProvider>
172 </GestureHandlerRootView>
173 </HideBottomBarBorderProvider>
174 </EmailVerificationProvider>
175 </ServiceAccountManager>
176 </ProgressGuideProvider>
177 </MutedThreadsProvider>
178 </BackgroundNotificationPreferencesProvider>
179 </UnreadNotifsProvider>
180 </HomeBadgeProvider>
181 </HiddenRepliesProvider>
182 </SelectedFeedProvider>
183 </LoggedOutViewProvider>
184 </ModerationOptsProvider>
185 </LabelDefsProvider>
186 </MessagesProvider>
187 </ComposerProvider>
188 </AgeAssuranceProvider>
189 </StatsigProvider>
190 </PolicyUpdateOverlayProvider>
191 </QueryProvider>
192 </React.Fragment>
193 </VideoVolumeProvider>
194 </RootSiblingParent>
195 </Splash>
196 </ContextMenuProvider>
197 </ThemeProvider>
198 </Alf>
199 )
200}
201
202function App() {
203 const [isReady, setReady] = useState(false)
204
205 React.useEffect(() => {
206 Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
207 setReady(true),
208 )
209 }, [])
210
211 if (!isReady) {
212 return null
213 }
214
215 /*
216 * NOTE: only nothing here can depend on other data or session state, since
217 * that is set up in the InnerApp component above.
218 */
219 return (
220 <GeolocationProvider>
221 <A11yProvider>
222 <KeyboardControllerProvider>
223 <SessionProvider>
224 <PrefsStateProvider>
225 <I18nProvider>
226 <ShellStateProvider>
227 <InvitesStateProvider>
228 <ModalStateProvider>
229 <DialogStateProvider>
230 <LightboxStateProvider>
231 <PortalProvider>
232 <BottomSheetProvider>
233 <StarterPackProvider>
234 <SafeAreaProvider
235 initialMetrics={initialWindowMetrics}>
236 <InnerApp />
237 </SafeAreaProvider>
238 </StarterPackProvider>
239 </BottomSheetProvider>
240 </PortalProvider>
241 </LightboxStateProvider>
242 </DialogStateProvider>
243 </ModalStateProvider>
244 </InvitesStateProvider>
245 </ShellStateProvider>
246 </I18nProvider>
247 </PrefsStateProvider>
248 </SessionProvider>
249 </KeyboardControllerProvider>
250 </A11yProvider>
251 </GeolocationProvider>
252 )
253}
254
255export default Sentry.wrap(App)