gestures setup
This commit is contained in:
+105
-225
@@ -1,239 +1,119 @@
|
|||||||
import 'react-native-url-polyfill/auto'
|
import {useState} from 'react'
|
||||||
import '#/lib/sentry' // must be near top
|
import {ScrollView, Text, View} from 'react-native'
|
||||||
import '#/lib/bitdrift' // must be near top
|
|
||||||
import '#/view/icons'
|
|
||||||
|
|
||||||
import React, {useEffect, useState} from 'react'
|
|
||||||
import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
|
||||||
import {RootSiblingParent} from 'react-native-root-siblings'
|
|
||||||
import {
|
import {
|
||||||
initialWindowMetrics,
|
Gesture,
|
||||||
SafeAreaProvider,
|
GestureDetector,
|
||||||
} from 'react-native-safe-area-context'
|
GestureHandlerRootView,
|
||||||
import * as ScreenOrientation from 'expo-screen-orientation'
|
} from 'react-native-gesture-handler'
|
||||||
import * as SplashScreen from 'expo-splash-screen'
|
import PagerView from 'react-native-pager-view'
|
||||||
import * as SystemUI from 'expo-system-ui'
|
import Animated, {
|
||||||
import {msg} from '@lingui/macro'
|
useAnimatedStyle,
|
||||||
import {useLingui} from '@lingui/react'
|
useSharedValue,
|
||||||
|
} from 'react-native-reanimated'
|
||||||
|
|
||||||
import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController'
|
export default function App() {
|
||||||
import {QueryProvider} from '#/lib/react-query'
|
const val = useSharedValue(0)
|
||||||
import {Provider as StatsigProvider, tryFetchGates} from '#/lib/statsig/statsig'
|
const [swipeEnabled, setSwipeEnabled] = useState(true)
|
||||||
import {s} from '#/lib/styles'
|
|
||||||
import {ThemeProvider} from '#/lib/ThemeContext'
|
|
||||||
import I18nProvider from '#/locale/i18nProvider'
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {isAndroid, isIOS} from '#/platform/detection'
|
|
||||||
import {Provider as A11yProvider} from '#/state/a11y'
|
|
||||||
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
|
||||||
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
|
||||||
import {listenSessionDropped} from '#/state/events'
|
|
||||||
import {
|
|
||||||
beginResolveGeolocation,
|
|
||||||
ensureGeolocationResolved,
|
|
||||||
Provider as GeolocationProvider,
|
|
||||||
} from '#/state/geolocation'
|
|
||||||
import {Provider as HomeBadgeProvider} from '#/state/home-badge'
|
|
||||||
import {Provider as InvitesStateProvider} from '#/state/invites'
|
|
||||||
import {Provider as LightboxStateProvider} from '#/state/lightbox'
|
|
||||||
import {MessagesProvider} from '#/state/messages'
|
|
||||||
import {Provider as ModalStateProvider} from '#/state/modals'
|
|
||||||
import {init as initPersistedState} from '#/state/persisted'
|
|
||||||
import {Provider as PrefsStateProvider} from '#/state/preferences'
|
|
||||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
|
||||||
import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
|
|
||||||
import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
|
|
||||||
import {
|
|
||||||
Provider as SessionProvider,
|
|
||||||
SessionAccount,
|
|
||||||
useSession,
|
|
||||||
useSessionApi,
|
|
||||||
} from '#/state/session'
|
|
||||||
import {readLastActiveAccount} from '#/state/session/util'
|
|
||||||
import {Provider as ShellStateProvider} from '#/state/shell'
|
|
||||||
import {Provider as ComposerProvider} from '#/state/shell/composer'
|
|
||||||
import {Provider as LightStatusBarProvider} from '#/state/shell/light-status-bar'
|
|
||||||
import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
|
|
||||||
import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
|
|
||||||
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
|
|
||||||
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
|
|
||||||
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
|
|
||||||
import {Provider as TrendingConfigProvider} from '#/state/trending-config'
|
|
||||||
import {TestCtrls} from '#/view/com/testing/TestCtrls'
|
|
||||||
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
|
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
|
||||||
import {Shell} from '#/view/shell'
|
|
||||||
import {ThemeProvider as Alf} from '#/alf'
|
|
||||||
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
|
||||||
import {NuxDialogs} from '#/components/dialogs/nuxs'
|
|
||||||
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
|
|
||||||
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
|
|
||||||
import {Provider as PortalProvider} from '#/components/Portal'
|
|
||||||
import {Splash} from '#/Splash'
|
|
||||||
import {BottomSheetProvider} from '../modules/bottom-sheet'
|
|
||||||
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync()
|
let pan = Gesture.Pan()
|
||||||
if (isIOS) {
|
.onBegin(() => {
|
||||||
SystemUI.setBackgroundColorAsync('black')
|
'worklet'
|
||||||
}
|
console.log('begin')
|
||||||
if (isAndroid) {
|
val.set(0)
|
||||||
// iOS is handled by the config plugin -sfn
|
})
|
||||||
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP)
|
.onUpdate(e => {
|
||||||
}
|
'worklet'
|
||||||
|
console.log('update')
|
||||||
/**
|
val.set(e.translationX)
|
||||||
* Begin geolocation ASAP
|
})
|
||||||
*/
|
.onEnd(() => {
|
||||||
beginResolveGeolocation()
|
'worklet'
|
||||||
|
console.log('end')
|
||||||
function InnerApp() {
|
val.set(0)
|
||||||
const [isReady, setIsReady] = React.useState(false)
|
})
|
||||||
const {currentAccount} = useSession()
|
.onFinalize(() => {
|
||||||
const {resumeSession} = useSessionApi()
|
'worklet'
|
||||||
const theme = useColorModeTheme()
|
console.log('finalize')
|
||||||
const {_} = useLingui()
|
val.set(0)
|
||||||
|
|
||||||
const hasCheckedReferrer = useStarterPackEntry()
|
|
||||||
|
|
||||||
// init
|
|
||||||
useEffect(() => {
|
|
||||||
async function onLaunch(account?: SessionAccount) {
|
|
||||||
try {
|
|
||||||
if (account) {
|
|
||||||
await resumeSession(account)
|
|
||||||
} else {
|
|
||||||
await tryFetchGates(undefined, 'prefer-fresh-gates')
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(`session: resume failed`, {message: e})
|
|
||||||
} finally {
|
|
||||||
setIsReady(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const account = readLastActiveAccount()
|
|
||||||
onLaunch(account)
|
|
||||||
}, [resumeSession])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return listenSessionDropped(() => {
|
|
||||||
Toast.show(
|
|
||||||
_(msg`Sorry! Your session expired. Please log in again.`),
|
|
||||||
'info',
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}, [_])
|
|
||||||
|
|
||||||
|
if (swipeEnabled) {
|
||||||
|
pan = pan.failOffsetX(-1).activeOffsetX(5)
|
||||||
|
} else {
|
||||||
|
pan = pan.failOffsetX([0, 0]).failOffsetY([0, 0])
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = useAnimatedStyle(() => {
|
||||||
|
return {
|
||||||
|
flex: 1,
|
||||||
|
transform: [
|
||||||
|
{
|
||||||
|
translateX: val.value,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<Alf theme={theme}>
|
<GestureHandlerRootView>
|
||||||
<ThemeProvider theme={theme}>
|
<GestureDetector gesture={pan}>
|
||||||
<Splash isReady={isReady && hasCheckedReferrer}>
|
<Animated.View style={style}>
|
||||||
<RootSiblingParent>
|
<Pager pan={pan} setSwipeEnabled={setSwipeEnabled}>
|
||||||
<VideoVolumeProvider>
|
<InnerScrollView pan={pan} />
|
||||||
<React.Fragment
|
</Pager>
|
||||||
// Resets the entire tree below when it changes:
|
</Animated.View>
|
||||||
key={currentAccount?.did}>
|
</GestureDetector>
|
||||||
<QueryProvider currentDid={currentAccount?.did}>
|
|
||||||
<ComposerProvider>
|
|
||||||
<StatsigProvider>
|
|
||||||
<MessagesProvider>
|
|
||||||
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
|
|
||||||
<LabelDefsProvider>
|
|
||||||
<ModerationOptsProvider>
|
|
||||||
<LoggedOutViewProvider>
|
|
||||||
<SelectedFeedProvider>
|
|
||||||
<HiddenRepliesProvider>
|
|
||||||
<HomeBadgeProvider>
|
|
||||||
<UnreadNotifsProvider>
|
|
||||||
<BackgroundNotificationPreferencesProvider>
|
|
||||||
<MutedThreadsProvider>
|
|
||||||
<ProgressGuideProvider>
|
|
||||||
<TrendingConfigProvider>
|
|
||||||
<GestureHandlerRootView
|
|
||||||
style={s.h100pct}>
|
|
||||||
<IntentDialogProvider>
|
|
||||||
<TestCtrls />
|
|
||||||
<Shell />
|
|
||||||
<NuxDialogs />
|
|
||||||
</IntentDialogProvider>
|
|
||||||
</GestureHandlerRootView>
|
</GestureHandlerRootView>
|
||||||
</TrendingConfigProvider>
|
|
||||||
</ProgressGuideProvider>
|
|
||||||
</MutedThreadsProvider>
|
|
||||||
</BackgroundNotificationPreferencesProvider>
|
|
||||||
</UnreadNotifsProvider>
|
|
||||||
</HomeBadgeProvider>
|
|
||||||
</HiddenRepliesProvider>
|
|
||||||
</SelectedFeedProvider>
|
|
||||||
</LoggedOutViewProvider>
|
|
||||||
</ModerationOptsProvider>
|
|
||||||
</LabelDefsProvider>
|
|
||||||
</MessagesProvider>
|
|
||||||
</StatsigProvider>
|
|
||||||
</ComposerProvider>
|
|
||||||
</QueryProvider>
|
|
||||||
</React.Fragment>
|
|
||||||
</VideoVolumeProvider>
|
|
||||||
</RootSiblingParent>
|
|
||||||
</Splash>
|
|
||||||
</ThemeProvider>
|
|
||||||
</Alf>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function App() {
|
function Pager({children, pan, setSwipeEnabled}) {
|
||||||
const [isReady, setReady] = useState(false)
|
const native = Gesture.Native().requireExternalGestureToFail(pan)
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
|
|
||||||
setReady(true),
|
|
||||||
)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
if (!isReady) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: only nothing here can depend on other data or session state, since
|
|
||||||
* that is set up in the InnerApp component above.
|
|
||||||
*/
|
|
||||||
return (
|
return (
|
||||||
<GeolocationProvider>
|
<GestureDetector gesture={native}>
|
||||||
<A11yProvider>
|
<PagerView
|
||||||
<KeyboardControllerProvider>
|
overdrag={true}
|
||||||
<SessionProvider>
|
initialPage={0}
|
||||||
<PrefsStateProvider>
|
style={{
|
||||||
<I18nProvider>
|
flex: 1,
|
||||||
<ShellStateProvider>
|
backgroundColor: 'green',
|
||||||
<InvitesStateProvider>
|
}}
|
||||||
<ModalStateProvider>
|
onPageSelected={e => {
|
||||||
<DialogStateProvider>
|
setSwipeEnabled(e.nativeEvent.position === 0)
|
||||||
<LightboxStateProvider>
|
}}>
|
||||||
<PortalProvider>
|
{children}
|
||||||
<BottomSheetProvider>
|
{children}
|
||||||
<StarterPackProvider>
|
{children}
|
||||||
<SafeAreaProvider
|
</PagerView>
|
||||||
initialMetrics={initialWindowMetrics}>
|
</GestureDetector>
|
||||||
<LightStatusBarProvider>
|
|
||||||
<InnerApp />
|
|
||||||
</LightStatusBarProvider>
|
|
||||||
</SafeAreaProvider>
|
|
||||||
</StarterPackProvider>
|
|
||||||
</BottomSheetProvider>
|
|
||||||
</PortalProvider>
|
|
||||||
</LightboxStateProvider>
|
|
||||||
</DialogStateProvider>
|
|
||||||
</ModalStateProvider>
|
|
||||||
</InvitesStateProvider>
|
|
||||||
</ShellStateProvider>
|
|
||||||
</I18nProvider>
|
|
||||||
</PrefsStateProvider>
|
|
||||||
</SessionProvider>
|
|
||||||
</KeyboardControllerProvider>
|
|
||||||
</A11yProvider>
|
|
||||||
</GeolocationProvider>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
function InnerScrollView({pan}) {
|
||||||
|
const native = Gesture.Native().blocksExternalGesture(pan)
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
paddingTop: 200,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}>
|
||||||
|
<GestureDetector gesture={native}>
|
||||||
|
<ScrollView
|
||||||
|
horizontal
|
||||||
|
pagingEnabled
|
||||||
|
style={{
|
||||||
|
width: 300,
|
||||||
|
backgroundColor: 'yellow',
|
||||||
|
height: 200,
|
||||||
|
}}>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
width: 1000,
|
||||||
|
}}>
|
||||||
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
||||||
|
27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
||||||
|
</Text>
|
||||||
|
</ScrollView>
|
||||||
|
</GestureDetector>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user