diff options
-rw-r--r-- | patches/react-native-pager-view+6.6.1.patch | 72 | ||||
-rw-r--r-- | src/view/com/pager/Pager.tsx | 42 |
2 files changed, 40 insertions, 74 deletions
diff --git a/patches/react-native-pager-view+6.6.1.patch b/patches/react-native-pager-view+6.6.1.patch deleted file mode 100644 index 8e94570cf..000000000 --- a/patches/react-native-pager-view+6.6.1.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff --git a/node_modules/react-native-pager-view/android/build/tmp/kotlin-classes/debug/com/reactnativepagerview/NestedScrollableHost.class b/node_modules/react-native-pager-view/android/build/tmp/kotlin-classes/debug/com/reactnativepagerview/NestedScrollableHost.class -new file mode 100644 -index 0000000..b64fccc -Binary files /dev/null and b/node_modules/react-native-pager-view/android/build/tmp/kotlin-classes/debug/com/reactnativepagerview/NestedScrollableHost.class differ -diff --git a/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt b/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt -index 91d9946..87b58d0 100644 ---- a/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt -+++ b/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt -@@ -8,6 +8,7 @@ import android.view.ViewConfiguration - import android.widget.FrameLayout - import androidx.viewpager2.widget.ViewPager2 - import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL -+import com.facebook.react.uimanager.events.NativeGestureUtil - import kotlin.math.absoluteValue - import kotlin.math.sign - -@@ -27,6 +28,7 @@ class NestedScrollableHost : FrameLayout { - private var touchSlop = 0 - private var initialX = 0f - private var initialY = 0f -+ private var nativeGestureStarted: Boolean = false - private val parentViewPager: ViewPager2? - get() { - var v: View? = parent as? View -@@ -57,17 +59,14 @@ class NestedScrollableHost : FrameLayout { - } - - private fun handleInterceptTouchEvent(e: MotionEvent) { -- val orientation = parentViewPager?.orientation ?: return -- -- // Early return if child can't scroll in same direction as parent -- if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) { -- return -- } -+ val orientation = parentViewPager?.orientation - - if (e.action == MotionEvent.ACTION_DOWN) { - initialX = e.x - initialY = e.y -- parent.requestDisallowInterceptTouchEvent(true) -+ if (orientation != null) { -+ parent.requestDisallowInterceptTouchEvent(true) -+ } - } else if (e.action == MotionEvent.ACTION_MOVE) { - val dx = e.x - initialX - val dy = e.y - initialY -@@ -78,6 +77,10 @@ class NestedScrollableHost : FrameLayout { - val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f - - if (scaledDx > touchSlop || scaledDy > touchSlop) { -+ NativeGestureUtil.notifyNativeGestureStarted(this, e) -+ nativeGestureStarted = true -+ -+ if (orientation == null) return - if (isVpHorizontal == (scaledDy > scaledDx)) { - // Gesture is perpendicular, allow all parents to intercept - parent.requestDisallowInterceptTouchEvent(false) -@@ -94,4 +97,14 @@ class NestedScrollableHost : FrameLayout { - } - } - } -+ -+ override fun onTouchEvent(e: MotionEvent): Boolean { -+ if (e.actionMasked == MotionEvent.ACTION_UP) { -+ if (nativeGestureStarted) { -+ NativeGestureUtil.notifyNativeGestureEnded(this, e) -+ nativeGestureStarted = false -+ } -+ } -+ return super.onTouchEvent(e) -+ } - } diff --git a/src/view/com/pager/Pager.tsx b/src/view/com/pager/Pager.tsx index f62bffc53..772cb1715 100644 --- a/src/view/com/pager/Pager.tsx +++ b/src/view/com/pager/Pager.tsx @@ -1,4 +1,4 @@ -import React, {forwardRef, useCallback, useContext} from 'react' +import React, {Children, 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' @@ -17,6 +17,7 @@ import Animated, { } from 'react-native-reanimated' import {useFocusEffect} from '@react-navigation/native' +import {isAndroid} from '#/platform/detection' import {useSetDrawerSwipeDisabled} from '#/state/shell' import {atoms as a, native} from '#/alf' @@ -148,7 +149,11 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>( style={[a.flex_1]} initialPage={initialPage} onPageScroll={handlePageScroll}> - {children} + {isAndroid + ? Children.map(children, child => ( + <CaptureSwipesAndroid>{child}</CaptureSwipesAndroid> + )) + : children} </AnimatedPagerView> </GestureDetector> </View> @@ -156,6 +161,39 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>( }, ) +// HACK. +// This works around https://github.com/callstack/react-native-pager-view/issues/960. +// It appears that the Pressables inside the pager get confused if there's enough work +// happening on the JS thread, and mistakingly interpret a pager swipe as a tap. +// We can prevent this by stealing all horizontal movements from the tree inside. +function CaptureSwipesAndroid({children}: {children: React.ReactNode}) { + const lastTouchStart = React.useRef<{x: number; y: number} | null>(null) + return ( + <View + onTouchStart={e => { + lastTouchStart.current = { + x: e.nativeEvent.pageX, + y: e.nativeEvent.pageY, + } + }} + onMoveShouldSetResponderCapture={e => { + const coords = lastTouchStart.current + if (!coords) { + return false + } + const dx = Math.abs(e.nativeEvent.pageX - coords.x) + if (dx > 0) { + // This is a horizontal movement and will result in a swipe. + // Prevent pager children from receiving this touch. + return true + } + return false + }}> + {children} + </View> + ) +} + function usePagerHandlers( handlers: { onPageScroll: (e: PagerViewOnPageScrollEventData) => void |