deer social fork for personal usage. but you might see a use idk. github mirror
1import '#/view/icons'
2
3import React, {useEffect, useState} from 'react'
4import {GestureHandlerRootView} from 'react-native-gesture-handler'
5import {
6 initialWindowMetrics,
7 SafeAreaProvider,
8} from 'react-native-safe-area-context'
9import * as ScreenOrientation from 'expo-screen-orientation'
10import * as SplashScreen from 'expo-splash-screen'
11import * as SystemUI from 'expo-system-ui'
12import {msg} from '@lingui/macro'
13import {useLingui} from '@lingui/react'
14
15import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController'
16import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder'
17import {QueryProvider} from '#/lib/react-query'
18import {Provider as StatsigProvider, tryFetchGates} from '#/lib/statsig/statsig'
19import {s} from '#/lib/styles'
20import {ThemeProvider} from '#/lib/ThemeContext'
21import I18nProvider from '#/locale/i18nProvider'
22import {logger} from '#/logger'
23import {isAndroid, isIOS} from '#/platform/detection'
24import {Provider as A11yProvider} from '#/state/a11y'
25import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
26import {Provider as DialogStateProvider} from '#/state/dialogs'
27import {Provider as EmailVerificationProvider} from '#/state/email-verification'
28import {listenSessionDropped} from '#/state/events'
29import {GlobalGestureEventsProvider} from '#/state/global-gesture-events'
30import {Provider as HomeBadgeProvider} from '#/state/home-badge'
31import {Provider as LightboxStateProvider} from '#/state/lightbox'
32import {MessagesProvider} from '#/state/messages'
33import {Provider as ModalStateProvider} from '#/state/modals'
34import {init as initPersistedState} from '#/state/persisted'
35import {Provider as PrefsStateProvider} from '#/state/preferences'
36import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
37import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
38import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
39import {Provider as ServiceAccountManager} from '#/state/service-config'
40import {
41 Provider as SessionProvider,
42 type SessionAccount,
43 useSession,
44 useSessionApi,
45} from '#/state/session'
46import {readLastActiveAccount} from '#/state/session/util'
47import {Provider as ShellStateProvider} from '#/state/shell'
48import {Provider as ComposerProvider} from '#/state/shell/composer'
49import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
50import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
51import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
52import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
53import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
54import {TestCtrls} from '#/view/com/testing/TestCtrls'
55import * as Toast from '#/view/com/util/Toast'
56import {Shell} from '#/view/shell'
57import {ThemeProvider as Alf} from '#/alf'
58import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
59import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
60import {NuxDialogs} from '#/components/dialogs/nuxs'
61import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
62import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
63import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
64import {Provider as PortalProvider} from '#/components/Portal'
65import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
66import {ToastOutlet} from '#/components/Toast'
67import {Splash} from '#/Splash'
68import {BottomSheetProvider} from '../modules/bottom-sheet'
69import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
70
71SplashScreen.preventAutoHideAsync()
72if (isIOS) {
73 SystemUI.setBackgroundColorAsync('black')
74}
75if (isAndroid) {
76 // iOS is handled by the config plugin -sfn
77 ScreenOrientation.lockAsync(
78 ScreenOrientation.OrientationLock.PORTRAIT_UP,
79 ).catch(error =>
80 logger.debug('Could not lock orientation', {safeMessage: error}),
81 )
82}
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 sign in again.`),
116 'info',
117 )
118 })
119 }, [_])
120
121 return (
122 <Alf theme={theme}>
123 <ThemeProvider theme={theme}>
124 <ContextMenuProvider>
125 <Splash isReady={isReady && hasCheckedReferrer}>
126 <VideoVolumeProvider>
127 <React.Fragment
128 // Resets the entire tree below when it changes:
129 key={currentAccount?.did}>
130 <QueryProvider currentDid={currentAccount?.did}>
131 <PolicyUpdateOverlayProvider>
132 <StatsigProvider>
133 <ComposerProvider>
134 <MessagesProvider>
135 {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
136 <LabelDefsProvider>
137 <ModerationOptsProvider>
138 <LoggedOutViewProvider>
139 <SelectedFeedProvider>
140 <HiddenRepliesProvider>
141 <HomeBadgeProvider>
142 <UnreadNotifsProvider>
143 <BackgroundNotificationPreferencesProvider>
144 <MutedThreadsProvider>
145 <ProgressGuideProvider>
146 <ServiceAccountManager>
147 <EmailVerificationProvider>
148 <HideBottomBarBorderProvider>
149 <GestureHandlerRootView
150 style={s.h100pct}>
151 <GlobalGestureEventsProvider>
152 <IntentDialogProvider>
153 <TestCtrls />
154 <Shell />
155 <NuxDialogs />
156 <ToastOutlet />
157 </IntentDialogProvider>
158 </GlobalGestureEventsProvider>
159 </GestureHandlerRootView>
160 </HideBottomBarBorderProvider>
161 </EmailVerificationProvider>
162 </ServiceAccountManager>
163 </ProgressGuideProvider>
164 </MutedThreadsProvider>
165 </BackgroundNotificationPreferencesProvider>
166 </UnreadNotifsProvider>
167 </HomeBadgeProvider>
168 </HiddenRepliesProvider>
169 </SelectedFeedProvider>
170 </LoggedOutViewProvider>
171 </ModerationOptsProvider>
172 </LabelDefsProvider>
173 </MessagesProvider>
174 </ComposerProvider>
175 </StatsigProvider>
176 </PolicyUpdateOverlayProvider>
177 </QueryProvider>
178 </React.Fragment>
179 </VideoVolumeProvider>
180 </Splash>
181 </ContextMenuProvider>
182 </ThemeProvider>
183 </Alf>
184 )
185}
186
187function App() {
188 const [isReady, setReady] = useState(false)
189
190 React.useEffect(() => {
191 Promise.all([initPersistedState()]).then(() => setReady(true))
192 }, [])
193
194 if (!isReady) {
195 return null
196 }
197
198 /*
199 * NOTE: only nothing here can depend on other data or session state, since
200 * that is set up in the InnerApp component above.
201 */
202 return (
203 <A11yProvider>
204 <KeyboardControllerProvider>
205 <SessionProvider>
206 <PrefsStateProvider>
207 <I18nProvider>
208 <ShellStateProvider>
209 <ModalStateProvider>
210 <DialogStateProvider>
211 <LightboxStateProvider>
212 <PortalProvider>
213 <BottomSheetProvider>
214 <StarterPackProvider>
215 <SafeAreaProvider
216 initialMetrics={initialWindowMetrics}>
217 <InnerApp />
218 </SafeAreaProvider>
219 </StarterPackProvider>
220 </BottomSheetProvider>
221 </PortalProvider>
222 </LightboxStateProvider>
223 </DialogStateProvider>
224 </ModalStateProvider>
225 </ShellStateProvider>
226 </I18nProvider>
227 </PrefsStateProvider>
228 </SessionProvider>
229 </KeyboardControllerProvider>
230 </A11yProvider>
231 )
232}
233
234export default App