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