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