Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
117
fork

Configure Feed

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

at a876aae44ea07494ebea9727350aa060b81f317b 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 preload={false}> 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)