mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import '#/logger/sentry/setup' // must be near top
2import '#/view/icons'
3import './style.css'
4
5import React, {useEffect, useState} from 'react'
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'
10import * as Sentry from '@sentry/react-native'
11
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 {
22 beginResolveGeolocation,
23 ensureGeolocationResolved,
24 Provider as GeolocationProvider,
25} from '#/state/geolocation'
26import {Provider as HomeBadgeProvider} from '#/state/home-badge'
27import {Provider as InvitesStateProvider} from '#/state/invites'
28import {Provider as LightboxStateProvider} from '#/state/lightbox'
29import {MessagesProvider} from '#/state/messages'
30import {Provider as ModalStateProvider} from '#/state/modals'
31import {init as initPersistedState} from '#/state/persisted'
32import {Provider as PrefsStateProvider} from '#/state/preferences'
33import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
34import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
35import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
36import {Provider as ServiceConfigProvider} from '#/state/service-config'
37import {
38 Provider as SessionProvider,
39 type SessionAccount,
40 useSession,
41 useSessionApi,
42} from '#/state/session'
43import {readLastActiveAccount} from '#/state/session/util'
44import {Provider as ShellStateProvider} from '#/state/shell'
45import {Provider as ComposerProvider} from '#/state/shell/composer'
46import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
47import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
48import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
49import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
50import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
51import * as Toast from '#/view/com/util/Toast'
52import {ToastContainer} from '#/view/com/util/Toast.web'
53import {Shell} from '#/view/shell/index'
54import {ThemeProvider as Alf} from '#/alf'
55import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
56import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
57import {NuxDialogs} from '#/components/dialogs/nuxs'
58import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
59import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
60import {Provider as PortalProvider} from '#/components/Portal'
61import {Provider as ActiveVideoProvider} from '#/components/Post/Embed/VideoEmbed/ActiveVideoWebContext'
62import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
63import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
64import {Provider as HideBottomBarBorderProvider} from './lib/hooks/useHideBottomBarBorder'
65
66/**
67 * Begin geolocation ASAP
68 */
69beginResolveGeolocation()
70
71function InnerApp() {
72 const [isReady, setIsReady] = React.useState(false)
73 const {currentAccount} = useSession()
74 const {resumeSession} = useSessionApi()
75 const theme = useColorModeTheme()
76 const {_} = useLingui()
77 const hasCheckedReferrer = useStarterPackEntry()
78
79 // init
80 useEffect(() => {
81 async function onLaunch(account?: SessionAccount) {
82 try {
83 if (account) {
84 await resumeSession(account)
85 }
86 } catch (e) {
87 logger.error(`session: resumeSession failed`, {message: e})
88 } finally {
89 setIsReady(true)
90 }
91 }
92 const account = readLastActiveAccount()
93 onLaunch(account)
94 }, [resumeSession])
95
96 useEffect(() => {
97 return listenSessionDropped(() => {
98 Toast.show(
99 _(msg`Sorry! Your session expired. Please sign in again.`),
100 'info',
101 )
102 })
103 }, [_])
104
105 // wait for session to resume
106 if (!isReady || !hasCheckedReferrer) return null
107
108 return (
109 <Alf theme={theme}>
110 <ThemeProvider theme={theme}>
111 <ContextMenuProvider>
112 <RootSiblingParent>
113 <VideoVolumeProvider>
114 <ActiveVideoProvider>
115 <React.Fragment
116 // Resets the entire tree below when it changes:
117 key={currentAccount?.did}>
118 <QueryProvider currentDid={currentAccount?.did}>
119 <ComposerProvider>
120 <StatsigProvider>
121 <MessagesProvider>
122 {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
123 <LabelDefsProvider>
124 <ModerationOptsProvider>
125 <LoggedOutViewProvider>
126 <SelectedFeedProvider>
127 <HiddenRepliesProvider>
128 <HomeBadgeProvider>
129 <UnreadNotifsProvider>
130 <BackgroundNotificationPreferencesProvider>
131 <MutedThreadsProvider>
132 <SafeAreaProvider>
133 <ProgressGuideProvider>
134 <ServiceConfigProvider>
135 <HideBottomBarBorderProvider>
136 <IntentDialogProvider>
137 <Shell />
138 <NuxDialogs />
139 </IntentDialogProvider>
140 </HideBottomBarBorderProvider>
141 </ServiceConfigProvider>
142 </ProgressGuideProvider>
143 </SafeAreaProvider>
144 </MutedThreadsProvider>
145 </BackgroundNotificationPreferencesProvider>
146 </UnreadNotifsProvider>
147 </HomeBadgeProvider>
148 </HiddenRepliesProvider>
149 </SelectedFeedProvider>
150 </LoggedOutViewProvider>
151 </ModerationOptsProvider>
152 </LabelDefsProvider>
153 </MessagesProvider>
154 </StatsigProvider>
155 </ComposerProvider>
156 </QueryProvider>
157 <ToastContainer />
158 </React.Fragment>
159 </ActiveVideoProvider>
160 </VideoVolumeProvider>
161 </RootSiblingParent>
162 </ContextMenuProvider>
163 </ThemeProvider>
164 </Alf>
165 )
166}
167
168function App() {
169 const [isReady, setReady] = useState(false)
170
171 React.useEffect(() => {
172 Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
173 setReady(true),
174 )
175 }, [])
176
177 if (!isReady) {
178 return null
179 }
180
181 /*
182 * NOTE: only nothing here can depend on other data or session state, since
183 * that is set up in the InnerApp component above.
184 */
185 return (
186 <GeolocationProvider>
187 <A11yProvider>
188 <SessionProvider>
189 <PrefsStateProvider>
190 <I18nProvider>
191 <ShellStateProvider>
192 <InvitesStateProvider>
193 <ModalStateProvider>
194 <DialogStateProvider>
195 <LightboxStateProvider>
196 <PortalProvider>
197 <StarterPackProvider>
198 <InnerApp />
199 </StarterPackProvider>
200 </PortalProvider>
201 </LightboxStateProvider>
202 </DialogStateProvider>
203 </ModalStateProvider>
204 </InvitesStateProvider>
205 </ShellStateProvider>
206 </I18nProvider>
207 </PrefsStateProvider>
208 </SessionProvider>
209 </A11yProvider>
210 </GeolocationProvider>
211 )
212}
213
214export default Sentry.wrap(App)