[APP-703] Android horizontal scroll registers as tap (#960)

* use Touchables from react-native-gesture-handler

* upgrade `react-native-gesture-handler` to latest version

* add FixedTouchableHighlight for android

* add workaround comment

* wait for animations to complete before loading data

* downgrade RNGH back to the version we had
zio/stable
Ansh 2023-07-06 18:41:27 -07:00 committed by GitHub
parent bf1785765d
commit df7552135a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 9 deletions

View File

@ -0,0 +1,42 @@
// FixedTouchableHighlight.tsx
import React, {ComponentProps, useRef} from 'react'
import {GestureResponderEvent, TouchableHighlight} from 'react-native'
type Position = {pageX: number; pageY: number}
export default function FixedTouchableHighlight({
onPress,
onPressIn,
...props
}: ComponentProps<typeof TouchableHighlight>) {
const _touchActivatePositionRef = useRef<Position | null>(null)
function _onPressIn(e: GestureResponderEvent) {
const {pageX, pageY} = e.nativeEvent
_touchActivatePositionRef.current = {
pageX,
pageY,
}
onPressIn?.(e)
}
function _onPress(e: GestureResponderEvent) {
const {pageX, pageY} = e.nativeEvent
const absX = Math.abs(_touchActivatePositionRef.current?.pageX! - pageX)
const absY = Math.abs(_touchActivatePositionRef.current?.pageY! - pageY)
const dragged = absX > 2 || absY > 2
if (!dragged) {
onPress?.(e)
}
}
return (
<TouchableHighlight onPressIn={_onPressIn} onPress={_onPress} {...props}>
{props.children}
</TouchableHighlight>
)
}

View File

@ -5,11 +5,11 @@ import {
GestureResponderEvent, GestureResponderEvent,
Platform, Platform,
StyleProp, StyleProp,
TouchableWithoutFeedback,
TouchableOpacity,
TextStyle, TextStyle,
View, View,
ViewStyle, ViewStyle,
TouchableOpacity,
TouchableWithoutFeedback,
} from 'react-native' } from 'react-native'
import { import {
useLinkProps, useLinkProps,
@ -22,8 +22,9 @@ import {NavigationProp} from 'lib/routes/types'
import {router} from '../../../routes' import {router} from '../../../routes'
import {useStores, RootStoreModel} from 'state/index' import {useStores, RootStoreModel} from 'state/index'
import {convertBskyAppUrlIfNeeded, isExternalUrl} from 'lib/strings/url-helpers' import {convertBskyAppUrlIfNeeded, isExternalUrl} from 'lib/strings/url-helpers'
import {isDesktopWeb} from 'platform/detection' import {isAndroid, isDesktopWeb} from 'platform/detection'
import {sanitizeUrl} from '@braintree/sanitize-url' import {sanitizeUrl} from '@braintree/sanitize-url'
import FixedTouchableHighlight from '../pager/FixedTouchableHighlight'
type Event = type Event =
| React.MouseEvent<HTMLAnchorElement, MouseEvent> | React.MouseEvent<HTMLAnchorElement, MouseEvent>
@ -65,6 +66,24 @@ export const Link = observer(function Link({
) )
if (noFeedback) { if (noFeedback) {
if (isAndroid) {
// workaround for Android not working well with left/right swipe gestures and TouchableWithoutFeedback
// https://github.com/callstack/react-native-pager-view/issues/424
return (
<FixedTouchableHighlight
testID={testID}
onPress={onPress}
// @ts-ignore web only -prf
href={asAnchor ? sanitizeUrl(href) : undefined}
accessible={accessible}
accessibilityRole="link"
{...props}>
<View style={style}>
{children ? children : <Text>{title || 'link'}</Text>}
</View>
</FixedTouchableHighlight>
)
}
return ( return (
<TouchableWithoutFeedback <TouchableWithoutFeedback
testID={testID} testID={testID}

View File

@ -1,5 +1,5 @@
import React, {useMemo} from 'react' import React, {useMemo} from 'react'
import {StyleSheet, View} from 'react-native' import {InteractionManager, StyleSheet, View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {makeRecordUri} from 'lib/strings/url-helpers' import {makeRecordUri} from 'lib/strings/url-helpers'
@ -31,11 +31,15 @@ export const PostThreadScreen = withAuthRequired(({route}: Props) => {
React.useCallback(() => { React.useCallback(() => {
store.shell.setMinimalShellMode(false) store.shell.setMinimalShellMode(false)
const threadCleanup = view.registerListeners() const threadCleanup = view.registerListeners()
InteractionManager.runAfterInteractions(() => {
if (!view.hasLoaded && !view.isLoading) { if (!view.hasLoaded && !view.isLoading) {
view.setup().catch(err => { view.setup().catch(err => {
store.log.error('Failed to fetch thread', err) store.log.error('Failed to fetch thread', err)
}) })
} }
})
return () => { return () => {
threadCleanup() threadCleanup()
} }