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