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