Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 277 lines 12 kB view raw
1import '#/logger/sentry/setup' 2import '#/view/icons' 3 4import {Fragment, useEffect, useState} from 'react' 5import {GestureHandlerRootView} from 'react-native-gesture-handler' 6import {KeyboardProvider as KeyboardControllerProvider} from 'react-native-keyboard-controller' 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 {useLingui} from '@lingui/react/macro' 15import * as Sentry from '@sentry/react-native' 16 17import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder' 18import {QueryProvider} from '#/lib/react-query' 19import {ThemeProvider} from '#/lib/ThemeContext' 20import {Provider as TranslateOnDeviceProvider} from '#/lib/translation' 21import I18nProvider from '#/locale/i18nProvider' 22import {logger} from '#/logger' 23import {Provider as A11yProvider} from '#/state/a11y' 24import { 25 prefetchAppConfig, 26 Provider as AppConfigProvider, 27} from '#/state/appConfig' 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 {Shell} from '#/view/shell' 60import {atoms as a, 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 * as Toast from '#/components/Toast' 69import {ToastOutlet} from '#/components/Toast' 70import { 71 prefetchAgeAssuranceConfig, 72 Provider as AgeAssuranceV2Provider, 73} from '#/ageAssurance' 74import { 75 AnalyticsContext, 76 AnalyticsFeaturesContext, 77 features, 78 setupDeviceId, 79} from '#/analytics' 80import {IS_ANDROID, IS_IOS} from '#/env' 81import {SettingsSyncGate} from '#/features/settingsSync' 82import { 83 prefetchLiveEvents, 84 Provider as LiveEventsProvider, 85} from '#/features/liveEvents/context' 86import * as Geo from '#/geolocation' 87import {Splash} from '#/Splash' 88import {BottomSheetProvider} from '../modules/bottom-sheet' 89import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' 90 91void SplashScreen.preventAutoHideAsync() 92if (IS_IOS) { 93 void SystemUI.setBackgroundColorAsync('black') 94} 95if (IS_ANDROID) { 96 // iOS is handled by the config plugin -sfn 97 ScreenOrientation.lockAsync( 98 ScreenOrientation.OrientationLock.PORTRAIT_UP, 99 ).catch(error => 100 logger.debug('Could not lock orientation', {safeMessage: error}), 101 ) 102} 103 104/** 105 * Begin geolocation ASAP 106 */ 107void Geo.resolve() 108void prefetchAgeAssuranceConfig() 109void prefetchLiveEvents() 110void prefetchAppConfig() 111 112function InnerApp() { 113 const [isReady, setIsReady] = useState(false) 114 const {currentAccount} = useSession() 115 const {resumeSession} = useSessionApi() 116 const theme = useColorModeTheme() 117 const {t: l} = useLingui() 118 const hasCheckedReferrer = useStarterPackEntry() 119 120 // init 121 useEffect(() => { 122 async function onLaunch(account?: SessionAccount) { 123 try { 124 if (account) { 125 await resumeSession(account) 126 } else { 127 await features.init 128 } 129 } catch (e) { 130 logger.error(`session: resume failed`, {message: e}) 131 } finally { 132 setIsReady(true) 133 } 134 } 135 const account = readLastActiveAccount() 136 void onLaunch(account) 137 }, [resumeSession]) 138 139 useEffect(() => { 140 return listenSessionDropped(() => { 141 Toast.show(l`Sorry! Your session expired. Please sign in again.`, { 142 type: 'info', 143 }) 144 }) 145 }, [l]) 146 147 return ( 148 <Alf theme={theme}> 149 <ThemeProvider theme={theme}> 150 <ContextMenuProvider> 151 <Splash isReady={isReady && hasCheckedReferrer}> 152 <VideoVolumeProvider> 153 <Fragment 154 // Resets the entire tree below when it changes: 155 key={currentAccount?.did}> 156 <AnalyticsFeaturesContext> 157 <QueryProvider currentDid={currentAccount?.did}> 158 <SettingsSyncGate> 159 <PolicyUpdateOverlayProvider> 160 <LiveEventsProvider> 161 <AgeAssuranceV2Provider> 162 <ComposerProvider> 163 <MessagesProvider> 164 {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 165 <LabelDefsProvider> 166 <ModerationOptsProvider> 167 <LoggedOutViewProvider> 168 <SelectedFeedProvider> 169 <HiddenRepliesProvider> 170 <HomeBadgeProvider> 171 <UnreadNotifsProvider> 172 <BackgroundNotificationPreferencesProvider> 173 <MutedThreadsProvider> 174 <ProgressGuideProvider> 175 <ServiceAccountManager> 176 <EmailVerificationProvider> 177 <HideBottomBarBorderProvider> 178 <GestureHandlerRootView 179 style={a.h_full}> 180 <GlobalGestureEventsProvider> 181 <IntentDialogProvider> 182 <TranslateOnDeviceProvider> 183 <TestCtrls /> 184 <Shell /> 185 <ToastOutlet /> 186 </TranslateOnDeviceProvider> 187 </IntentDialogProvider> 188 </GlobalGestureEventsProvider> 189 </GestureHandlerRootView> 190 </HideBottomBarBorderProvider> 191 </EmailVerificationProvider> 192 </ServiceAccountManager> 193 </ProgressGuideProvider> 194 </MutedThreadsProvider> 195 </BackgroundNotificationPreferencesProvider> 196 </UnreadNotifsProvider> 197 </HomeBadgeProvider> 198 </HiddenRepliesProvider> 199 </SelectedFeedProvider> 200 </LoggedOutViewProvider> 201 </ModerationOptsProvider> 202 </LabelDefsProvider> 203 </MessagesProvider> 204 </ComposerProvider> 205 </AgeAssuranceV2Provider> 206 </LiveEventsProvider> 207 </PolicyUpdateOverlayProvider> 208 </SettingsSyncGate> 209 </QueryProvider> 210 </AnalyticsFeaturesContext> 211 </Fragment> 212 </VideoVolumeProvider> 213 </Splash> 214 </ContextMenuProvider> 215 </ThemeProvider> 216 </Alf> 217 ) 218} 219 220function App() { 221 const [isReady, setIsReady] = useState(false) 222 223 useEffect(() => { 224 void Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then( 225 () => setIsReady(true), 226 ) 227 }, []) 228 229 if (!isReady) { 230 return null 231 } 232 233 /* 234 * NOTE: only nothing here can depend on other data or session state, since 235 * that is set up in the InnerApp component above. 236 */ 237 return ( 238 <Geo.Provider> 239 <AppConfigProvider> 240 <A11yProvider> 241 <KeyboardControllerProvider preload={false}> 242 <OnboardingProvider> 243 <AnalyticsContext> 244 <SessionProvider> 245 <PrefsStateProvider> 246 <I18nProvider> 247 <ShellStateProvider> 248 <ModalStateProvider> 249 <DialogStateProvider> 250 <LightboxStateProvider> 251 <PortalProvider> 252 <BottomSheetProvider> 253 <StarterPackProvider> 254 <SafeAreaProvider 255 initialMetrics={initialWindowMetrics}> 256 <InnerApp /> 257 </SafeAreaProvider> 258 </StarterPackProvider> 259 </BottomSheetProvider> 260 </PortalProvider> 261 </LightboxStateProvider> 262 </DialogStateProvider> 263 </ModalStateProvider> 264 </ShellStateProvider> 265 </I18nProvider> 266 </PrefsStateProvider> 267 </SessionProvider> 268 </AnalyticsContext> 269 </OnboardingProvider> 270 </KeyboardControllerProvider> 271 </A11yProvider> 272 </AppConfigProvider> 273 </Geo.Provider> 274 ) 275} 276 277export default Sentry.wrap(App)