Fix drawer swipe (#7007)
* Fix drawer swipe * Remove existing setDrawerSwipeDisabled management This is already pretty error-prone. And with tracking whether we're idle it's going to get more complicated. Let's pause and think. * Move setDrawerSwipeDisabled logic into Pager * Remove win/2 threshold It feels super arbitrary and breaks muscle memory. If the gesture is reliable, we shouldn't need it. * Maybe work around iOS freeze * Tweak gestures, add comments * Tune gestures
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import React, {forwardRef} from 'react'
|
||||
import React, {forwardRef, useCallback, useContext} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {DrawerGestureContext} from 'react-native-drawer-layout'
|
||||
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
|
||||
import PagerView, {
|
||||
PagerViewOnPageScrollEventData,
|
||||
PagerViewOnPageSelectedEvent,
|
||||
@@ -13,7 +15,9 @@ import Animated, {
|
||||
useHandler,
|
||||
useSharedValue,
|
||||
} from 'react-native-reanimated'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
import {useSetDrawerSwipeDisabled} from '#/state/shell'
|
||||
import {atoms as a, native} from '#/alf'
|
||||
|
||||
export type PageSelectedEvent = PagerViewOnPageSelectedEvent
|
||||
@@ -58,6 +62,18 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
||||
const [selectedPage, setSelectedPage] = React.useState(initialPage)
|
||||
const pagerView = React.useRef<PagerView>(null)
|
||||
|
||||
const [isIdle, setIsIdle] = React.useState(true)
|
||||
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
const canSwipeDrawer = selectedPage === 0 && isIdle
|
||||
setDrawerSwipeDisabled(!canSwipeDrawer)
|
||||
return () => {
|
||||
setDrawerSwipeDisabled(false)
|
||||
}
|
||||
}, [setDrawerSwipeDisabled, selectedPage, isIdle]),
|
||||
)
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
setPage: (index: number) => {
|
||||
pagerView.current?.setPage(index)
|
||||
@@ -96,6 +112,7 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
||||
},
|
||||
onPageScrollStateChanged(e: PageScrollStateChangedNativeEventData) {
|
||||
'worklet'
|
||||
runOnJS(setIsIdle)(e.pageScrollState === 'idle')
|
||||
if (dragState.get() === 'idle' && e.pageScrollState === 'settling') {
|
||||
// This is a programmatic scroll on Android.
|
||||
// Stay "idle" to match iOS and avoid confusing downstream code.
|
||||
@@ -113,6 +130,10 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
||||
[parentOnPageScrollStateChanged],
|
||||
)
|
||||
|
||||
const drawerGesture = useContext(DrawerGestureContext)!
|
||||
const nativeGesture =
|
||||
Gesture.Native().requireExternalGestureToFail(drawerGesture)
|
||||
|
||||
return (
|
||||
<View testID={testID} style={[a.flex_1, native(a.overflow_hidden)]}>
|
||||
{renderTabBar({
|
||||
@@ -121,13 +142,15 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
||||
dragProgress,
|
||||
dragState,
|
||||
})}
|
||||
<AnimatedPagerView
|
||||
ref={pagerView}
|
||||
style={[a.flex_1]}
|
||||
initialPage={initialPage}
|
||||
onPageScroll={handlePageScroll}>
|
||||
{children}
|
||||
</AnimatedPagerView>
|
||||
<GestureDetector gesture={nativeGesture}>
|
||||
<AnimatedPagerView
|
||||
ref={pagerView}
|
||||
style={[a.flex_1]}
|
||||
initialPage={initialPage}
|
||||
onPageScroll={handlePageScroll}>
|
||||
{children}
|
||||
</AnimatedPagerView>
|
||||
</GestureDetector>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user