Skip to content

Commit

Permalink
GH button/hold to swap improvements (#5976)
Browse files Browse the repository at this point in the history
* Make GH button gesture handlers more lightweight, add ref props

* Prevent long press race condition

* Remove redundant long press disabling

* Add comment explaining buffer

* Edit comment

* Make ref types more specific
  • Loading branch information
christianbaroni authored Aug 2, 2024
1 parent f02a232 commit d8bea90
Showing 1 changed file with 52 additions and 27 deletions.
79 changes: 52 additions & 27 deletions src/__swaps__/screens/Swap/components/GestureHandlerButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import ConditionalWrap from 'conditional-wrap';
import React, { useMemo } from 'react';
import React, { MutableRefObject, useMemo } from 'react';
import { StyleProp, ViewProps, ViewStyle } from 'react-native';
import {
Gesture,
GestureDetector,
GestureStateChangeEvent,
LongPressGesture,
LongPressGestureHandlerEventPayload,
TapGesture,
TapGestureHandlerEventPayload,
} from 'react-native-gesture-handler';
import Animated, { AnimatedStyle, runOnJS } from 'react-native-reanimated';
Expand All @@ -19,6 +21,7 @@ export type GestureHandlerButtonProps = {
disableButtonPressWrapper?: boolean;
disabled?: boolean;
longPressDuration?: number;
longPressRef?: MutableRefObject<LongPressGesture>;
onLongPressEndWorklet?: (success?: boolean) => void;
onLongPressJS?: (e?: GestureStateChangeEvent<LongPressGestureHandlerEventPayload>) => void;
onLongPressWorklet?: (e?: GestureStateChangeEvent<LongPressGestureHandlerEventPayload>) => void;
Expand All @@ -28,6 +31,7 @@ export type GestureHandlerButtonProps = {
pointerEvents?: ViewProps['pointerEvents'];
scaleTo?: number;
style?: StyleProp<ViewStyle> | AnimatedStyle;
tapRef?: MutableRefObject<TapGesture>;
};

/**
Expand All @@ -53,6 +57,7 @@ export function GestureHandlerButton({
disableButtonPressWrapper = false,
disabled = false,
longPressDuration = LONG_PRESS_DURATION_IN_MS,
longPressRef,
onLongPressEndWorklet,
onLongPressJS,
onLongPressWorklet,
Expand All @@ -62,40 +67,60 @@ export function GestureHandlerButton({
pointerEvents = 'box-only',
scaleTo = 0.86,
style,
tapRef,
}: GestureHandlerButtonProps) {
const gesture = useMemo(
() =>
Gesture.Race(
Gesture.Tap()
.enabled(!disabled)
.onBegin(e => {
if (onPressStartWorklet) onPressStartWorklet(e);
})
.onEnd(e => {
if (onPressWorklet) onPressWorklet(e);
if (onPressJS) runOnJS(onPressJS)(e);
}),
Gesture.LongPress()
.enabled(!disabled && !!(onLongPressEndWorklet || onLongPressJS || onLongPressWorklet))
.minDuration(longPressDuration)
.onStart(e => {
if (onLongPressWorklet) onLongPressWorklet(e);
if (onLongPressJS) runOnJS(onLongPressJS)(e);
})
.onFinalize((_, success) => {
if (onLongPressEndWorklet) onLongPressEndWorklet(success);
})
),
[disabled, longPressDuration, onLongPressEndWorklet, onLongPressJS, onLongPressWorklet, onPressJS, onPressStartWorklet, onPressWorklet]
);
const gesture = useMemo(() => {
const tap = Gesture.Tap()
.enabled(!disabled)
.onBegin(e => {
if (onPressStartWorklet) onPressStartWorklet(e);
})
.onEnd(e => {
if (onPressWorklet) onPressWorklet(e);
if (onPressJS) runOnJS(onPressJS)(e);
});

if (tapRef) tap.withRef(tapRef);

const longPressEnabled = !!(onLongPressEndWorklet || onLongPressJS || onLongPressWorklet);

if (!longPressEnabled) return tap;

const longPress = Gesture.LongPress()
.enabled(!disabled)
.minDuration(longPressDuration)
.onStart(e => {
if (onLongPressWorklet) onLongPressWorklet(e);
if (onLongPressJS) runOnJS(onLongPressJS)(e);
})
.onFinalize((_, success) => {
if (onLongPressEndWorklet) onLongPressEndWorklet(success);
});

if (longPressRef) longPress.withRef(longPressRef);

return Gesture.Race(tap, longPress);
}, [
disabled,
longPressDuration,
longPressRef,
onLongPressEndWorklet,
onLongPressJS,
onLongPressWorklet,
onPressJS,
onPressStartWorklet,
onPressWorklet,
tapRef,
]);

return (
<ConditionalWrap
condition={IS_IOS}
wrap={children => (
<ButtonPressAnimation
disabled={disabled}
minLongPressDuration={longPressDuration}
// This buffer ensures the native iOS button press wrapper doesn't cancel the RNGH long press events before they fire
minLongPressDuration={longPressDuration * 1.2}
scaleTo={disableButtonPressWrapper ? 1 : scaleTo}
style={buttonPressWrapperStyleIOS}
useLateHaptic={disableButtonPressWrapper}
Expand Down

0 comments on commit d8bea90

Please sign in to comment.