Bluesky app fork with some witchin' additions 馃挮
at 5ee667f307bc459ba53cdaabdad00a0ea1ee6846 241 lines 10 kB view raw
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)