forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import '#/logger/sentry/setup' // must be near top
2import '#/view/icons'
3import './style.css'
4
5import React, {useEffect, useState} from 'react'
6import {SafeAreaProvider} from 'react-native-safe-area-context'
7import {msg} from '@lingui/macro'
8import {useLingui} from '@lingui/react'
9import * as Sentry from '@sentry/react-native'
10
11import {QueryProvider} from '#/lib/react-query'
12import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
13import {ThemeProvider} from '#/lib/ThemeContext'
14import I18nProvider from '#/locale/i18nProvider'
15import {logger} from '#/logger'
16import {Provider as A11yProvider} from '#/state/a11y'
17import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
18import {Provider as DialogStateProvider} from '#/state/dialogs'
19import {Provider as EmailVerificationProvider} from '#/state/email-verification'
20import {listenSessionDropped} from '#/state/events'
21import {Provider as HomeBadgeProvider} from '#/state/home-badge'
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 {Provider as ServiceConfigProvider} from '#/state/service-config'
31import {
32 Provider as SessionProvider,
33 type SessionAccount,
34 useSession,
35 useSessionApi,
36} from '#/state/session'
37import {readLastActiveAccount} from '#/state/session/util'
38import {Provider as ShellStateProvider} from '#/state/shell'
39import {Provider as ComposerProvider} from '#/state/shell/composer'
40import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
41import {Provider as OnboardingProvider} from '#/state/shell/onboarding'
42import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
43import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
44import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
45import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
46import * as Toast from '#/view/com/util/Toast'
47import {Shell} from '#/view/shell/index'
48import {ThemeProvider as Alf} from '#/alf'
49import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
50import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
51import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
52import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
53import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
54import {Provider as PortalProvider} from '#/components/Portal'
55import {Provider as ActiveVideoProvider} from '#/components/Post/Embed/VideoEmbed/ActiveVideoWebContext'
56import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
57import {ToastOutlet} from '#/components/Toast'
58import {Provider as AgeAssuranceV2Provider} from '#/ageAssurance'
59import {prefetchAgeAssuranceConfig} from '#/ageAssurance'
60import {
61 prefetchLiveEvents,
62 Provider as LiveEventsProvider,
63} from '#/features/liveEvents/context'
64import * as Geo from '#/geolocation'
65import {Splash} from '#/Splash'
66import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
67import {Provider as HideBottomBarBorderProvider} from './lib/hooks/useHideBottomBarBorder'
68
69/**
70 * Begin geolocation ASAP
71 */
72Geo.resolve()
73prefetchAgeAssuranceConfig()
74prefetchLiveEvents()
75
76function InnerApp() {
77 const [isReady, setIsReady] = React.useState(false)
78 const {currentAccount} = useSession()
79 const {resumeSession} = useSessionApi()
80 const theme = useColorModeTheme()
81 const {_} = useLingui()
82 const hasCheckedReferrer = useStarterPackEntry()
83
84 // init
85 useEffect(() => {
86 async function onLaunch(account?: SessionAccount) {
87 try {
88 if (account) {
89 await resumeSession(account)
90 }
91 } catch (e) {
92 logger.error(`session: resumeSession failed`, {message: e})
93 } finally {
94 setIsReady(true)
95 }
96 }
97 const account = readLastActiveAccount()
98 onLaunch(account)
99 }, [resumeSession])
100
101 useEffect(() => {
102 return listenSessionDropped(() => {
103 Toast.show(
104 _(msg`Sorry! Your session expired. Please sign in again.`),
105 'info',
106 )
107 })
108 }, [_])
109
110 // wait for session to resume
111 if (!isReady || !hasCheckedReferrer) return <Splash isReady />
112
113 return (
114 <Alf theme={theme}>
115 <ThemeProvider theme={theme}>
116 <ContextMenuProvider>
117 <VideoVolumeProvider>
118 <ActiveVideoProvider>
119 <React.Fragment
120 // Resets the entire tree below when it changes:
121 key={currentAccount?.did}>
122 <QueryProvider currentDid={currentAccount?.did}>
123 <PolicyUpdateOverlayProvider>
124 <StatsigProvider>
125 <LiveEventsProvider>
126 <AgeAssuranceV2Provider>
127 <ComposerProvider>
128 <MessagesProvider>
129 {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
130 <LabelDefsProvider>
131 <ModerationOptsProvider>
132 <LoggedOutViewProvider>
133 <SelectedFeedProvider>
134 <HiddenRepliesProvider>
135 <HomeBadgeProvider>
136 <UnreadNotifsProvider>
137 <BackgroundNotificationPreferencesProvider>
138 <MutedThreadsProvider>
139 <SafeAreaProvider>
140 <ProgressGuideProvider>
141 <ServiceConfigProvider>
142 <EmailVerificationProvider>
143 <HideBottomBarBorderProvider>
144 <IntentDialogProvider>
145 <Shell />
146 <ToastOutlet />
147 </IntentDialogProvider>
148 </HideBottomBarBorderProvider>
149 </EmailVerificationProvider>
150 </ServiceConfigProvider>
151 </ProgressGuideProvider>
152 </SafeAreaProvider>
153 </MutedThreadsProvider>
154 </BackgroundNotificationPreferencesProvider>
155 </UnreadNotifsProvider>
156 </HomeBadgeProvider>
157 </HiddenRepliesProvider>
158 </SelectedFeedProvider>
159 </LoggedOutViewProvider>
160 </ModerationOptsProvider>
161 </LabelDefsProvider>
162 </MessagesProvider>
163 </ComposerProvider>
164 </AgeAssuranceV2Provider>
165 </LiveEventsProvider>
166 </StatsigProvider>
167 </PolicyUpdateOverlayProvider>
168 </QueryProvider>
169 </React.Fragment>
170 </ActiveVideoProvider>
171 </VideoVolumeProvider>
172 </ContextMenuProvider>
173 </ThemeProvider>
174 </Alf>
175 )
176}
177
178function App() {
179 const [isReady, setReady] = useState(false)
180
181 React.useEffect(() => {
182 Promise.all([initPersistedState(), Geo.resolve()]).then(() =>
183 setReady(true),
184 )
185 }, [])
186
187 if (!isReady) {
188 return <Splash isReady />
189 }
190
191 /*
192 * NOTE: only nothing here can depend on other data or session state, since
193 * that is set up in the InnerApp component above.
194 */
195 return (
196 <Geo.Provider>
197 <A11yProvider>
198 <OnboardingProvider>
199 <SessionProvider>
200 <PrefsStateProvider>
201 <I18nProvider>
202 <ShellStateProvider>
203 <ModalStateProvider>
204 <DialogStateProvider>
205 <LightboxStateProvider>
206 <PortalProvider>
207 <StarterPackProvider>
208 <InnerApp />
209 </StarterPackProvider>
210 </PortalProvider>
211 </LightboxStateProvider>
212 </DialogStateProvider>
213 </ModalStateProvider>
214 </ShellStateProvider>
215 </I18nProvider>
216 </PrefsStateProvider>
217 </SessionProvider>
218 </OnboardingProvider>
219 </A11yProvider>
220 </Geo.Provider>
221 )
222}
223
224export default Sentry.wrap(App)