[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 hadzio/stable
parent
bf1785765d
commit
df7552135a
|
@ -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>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue