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