deer social fork for personal usage. but you might see a use idk. github mirror
1import '#/view/icons'
2import './style.css'
3
4import React, {useEffect, useState} from 'react'
5import {SafeAreaProvider} from 'react-native-safe-area-context'
6import {msg} from '@lingui/macro'
7import {useLingui} from '@lingui/react'
8
9import {QueryProvider} from '#/lib/react-query'
10import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
11import {ThemeProvider} from '#/lib/ThemeContext'
12import I18nProvider from '#/locale/i18nProvider'
13import {logger} from '#/logger'
14import {Provider as A11yProvider} from '#/state/a11y'
15import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
16import {Provider as DialogStateProvider} from '#/state/dialogs'
17import {Provider as EmailVerificationProvider} from '#/state/email-verification'
18import {listenSessionDropped} from '#/state/events'
19import {Provider as HomeBadgeProvider} from '#/state/home-badge'
20import {Provider as LightboxStateProvider} from '#/state/lightbox'
21import {MessagesProvider} from '#/state/messages'
22import {Provider as ModalStateProvider} from '#/state/modals'
23import {init as initPersistedState} from '#/state/persisted'
24import {Provider as PrefsStateProvider} from '#/state/preferences'
25import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
26import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
27import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
28import {Provider as ServiceConfigProvider} from '#/state/service-config'
29import {
30 Provider as SessionProvider,
31 type SessionAccount,
32 useSession,
33 useSessionApi,
34} from '#/state/session'
35import {readLastActiveAccount} from '#/state/session/util'
36import {Provider as ShellStateProvider} from '#/state/shell'
37import {Provider as ComposerProvider} from '#/state/shell/composer'
38import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
39import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
40import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
41import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
42import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
43import * as Toast from '#/view/com/util/Toast'
44import {Shell} from '#/view/shell/index'
45import {ThemeProvider as Alf} from '#/alf'
46import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
47import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
48import {NuxDialogs} from '#/components/dialogs/nuxs'
49import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
50import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
51import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
52import {Provider as PortalProvider} from '#/components/Portal'
53import {Provider as ActiveVideoProvider} from '#/components/Post/Embed/VideoEmbed/ActiveVideoWebContext'
54import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
55import {ToastOutlet} from '#/components/Toast'
56import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
57import {Provider as HideBottomBarBorderProvider} from './lib/hooks/useHideBottomBarBorder'
58
59function InnerApp() {
60 const [isReady, setIsReady] = React.useState(false)
61 const {currentAccount} = useSession()
62 const {resumeSession} = useSessionApi()
63 const theme = useColorModeTheme()
64 const {_} = useLingui()
65 const hasCheckedReferrer = useStarterPackEntry()
66
67 // init
68 useEffect(() => {
69 async function onLaunch(account?: SessionAccount) {
70 try {
71 if (account) {
72 await resumeSession(account)
73 }
74 } catch (e) {
75 logger.error(`session: resumeSession failed`, {message: e})
76 } finally {
77 setIsReady(true)
78 }
79 }
80 const account = readLastActiveAccount()
81 onLaunch(account)
82 }, [resumeSession])
83
84 useEffect(() => {
85 return listenSessionDropped(() => {
86 Toast.show(
87 _(msg`Sorry! Your session expired. Please sign in again.`),
88 'info',
89 )
90 })
91 }, [_])
92
93 // wait for session to resume
94 if (!isReady || !hasCheckedReferrer) return null
95
96 return (
97 <Alf theme={theme}>
98 <ThemeProvider theme={theme}>
99 <ContextMenuProvider>
100 <VideoVolumeProvider>
101 <ActiveVideoProvider>
102 <React.Fragment
103 // Resets the entire tree below when it changes:
104 key={currentAccount?.did}>
105 <QueryProvider currentDid={currentAccount?.did}>
106 <PolicyUpdateOverlayProvider>
107 <StatsigProvider>
108 <ComposerProvider>
109 <MessagesProvider>
110 {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
111 <LabelDefsProvider>
112 <ModerationOptsProvider>
113 <LoggedOutViewProvider>
114 <SelectedFeedProvider>
115 <HiddenRepliesProvider>
116 <HomeBadgeProvider>
117 <UnreadNotifsProvider>
118 <BackgroundNotificationPreferencesProvider>
119 <MutedThreadsProvider>
120 <SafeAreaProvider>
121 <ProgressGuideProvider>
122 <ServiceConfigProvider>
123 <EmailVerificationProvider>
124 <HideBottomBarBorderProvider>
125 <IntentDialogProvider>
126 <Shell />
127 <NuxDialogs />
128 <ToastOutlet />
129 </IntentDialogProvider>
130 </HideBottomBarBorderProvider>
131 </EmailVerificationProvider>
132 </ServiceConfigProvider>
133 </ProgressGuideProvider>
134 </SafeAreaProvider>
135 </MutedThreadsProvider>
136 </BackgroundNotificationPreferencesProvider>
137 </UnreadNotifsProvider>
138 </HomeBadgeProvider>
139 </HiddenRepliesProvider>
140 </SelectedFeedProvider>
141 </LoggedOutViewProvider>
142 </ModerationOptsProvider>
143 </LabelDefsProvider>
144 </MessagesProvider>
145 </ComposerProvider>
146 </StatsigProvider>
147 </PolicyUpdateOverlayProvider>
148 </QueryProvider>
149 </React.Fragment>
150 </ActiveVideoProvider>
151 </VideoVolumeProvider>
152 </ContextMenuProvider>
153 </ThemeProvider>
154 </Alf>
155 )
156}
157
158function App() {
159 const [isReady, setReady] = useState(false)
160
161 React.useEffect(() => {
162 Promise.all([initPersistedState()]).then(() => setReady(true))
163 }, [])
164
165 if (!isReady) {
166 return null
167 }
168
169 /*
170 * NOTE: only nothing here can depend on other data or session state, since
171 * that is set up in the InnerApp component above.
172 */
173 return (
174 <A11yProvider>
175 <SessionProvider>
176 <PrefsStateProvider>
177 <I18nProvider>
178 <ShellStateProvider>
179 <ModalStateProvider>
180 <DialogStateProvider>
181 <LightboxStateProvider>
182 <PortalProvider>
183 <StarterPackProvider>
184 <InnerApp />
185 </StarterPackProvider>
186 </PortalProvider>
187 </LightboxStateProvider>
188 </DialogStateProvider>
189 </ModalStateProvider>
190 </ShellStateProvider>
191 </I18nProvider>
192 </PrefsStateProvider>
193 </SessionProvider>
194 </A11yProvider>
195 )
196}
197
198export default App