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