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