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