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
|