diff --git a/native/components/full-screen-view-modal.react.js b/native/components/full-screen-view-modal.react.js --- a/native/components/full-screen-view-modal.react.js +++ b/native/components/full-screen-view-modal.react.js @@ -21,7 +21,7 @@ Gesture, } from 'react-native-gesture-handler'; import Orientation from 'react-native-orientation-locker'; -import Animated from 'react-native-reanimated'; +import Animated, { useSharedValue } from 'react-native-reanimated'; import type { EventResult } from 'react-native-reanimated'; import { SafeAreaView } from 'react-native-safe-area-context'; @@ -67,7 +67,6 @@ eq, neq, greaterThan, - lessThan, add, sub, multiply, @@ -144,6 +143,13 @@ NativeMethods, >; +type ButtonDimensions = { + +x: number, + +y: number, + +width: number, + +height: number, +}; + type BaseProps = { +navigation: | AppNavigationProp<'ImageModal'> @@ -168,20 +174,14 @@ +updateCloseButtonEnabled: ([number]) => void, +updateActionLinksEnabled: ([number]) => void, +gesture: ExclusiveGesture, + +closeButtonRef: { current: ?React.ElementRef<TouchableOpacityInstance> }, + +mediaIconsRef: { current: ?React.ElementRef<typeof View> }, + +onCloseButtonLayout: () => void, + +onMediaIconsLayout: () => void, }; class FullScreenViewModal extends React.PureComponent<Props> { - closeButton: ?React.ElementRef<TouchableOpacityInstance>; - mediaIconsContainer: ?React.ElementRef<typeof View>; - closeButtonX: Value = new Value(-1); - closeButtonY: Value = new Value(-1); - closeButtonWidth: Value = new Value(0); - closeButtonHeight: Value = new Value(0); closeButtonLastState: Value = new Value(1); - mediaIconsX: Value = new Value(-1); - mediaIconsY: Value = new Value(-1); - mediaIconsWidth: Value = new Value(0); - mediaIconsHeight: Value = new Value(0); actionLinksLastState: Value = new Value(1); centerX: Value; @@ -282,10 +282,12 @@ cond( and( gestureJustStarted(panState), - this.outsideButtons( - sub(panAbsoluteX, panTranslationX), - sub(panAbsoluteY, panTranslationY), - ), + // TODO: migrate this in the next diffs + // this.outsideButtons( + // sub(panAbsoluteX, panTranslationX), + // sub(panAbsoluteY, panTranslationY), + // ), + 1, ), set(curPanActive, 1), ), @@ -532,37 +534,6 @@ ); } - outsideButtons(x: Node, y: Node): Node { - const { - closeButtonX, - closeButtonY, - closeButtonWidth, - closeButtonHeight, - closeButtonLastState, - mediaIconsX, - mediaIconsY, - mediaIconsWidth, - mediaIconsHeight, - actionLinksLastState, - } = this; - return and( - or( - eq(closeButtonLastState, 0), - lessThan(x, closeButtonX), - greaterThan(x, add(closeButtonX, closeButtonWidth)), - lessThan(y, closeButtonY), - greaterThan(y, add(closeButtonY, closeButtonHeight)), - ), - or( - eq(actionLinksLastState, 0), - lessThan(x, mediaIconsX), - greaterThan(x, add(mediaIconsX, mediaIconsWidth)), - lessThan(y, mediaIconsY), - greaterThan(y, add(mediaIconsY, mediaIconsHeight)), - ), - ); - } - panUpdate( // Inputs panActive: Node, @@ -594,7 +565,9 @@ const lastTapY = new Value(0); const fingerJustReleased = and( gestureJustEnded(singleTapState), - this.outsideButtons(lastTapX, lastTapY), + // TODO: migrate this in the next diffs + //this.outsideButtons(lastTapX, lastTapY), + 1, ); const wasZoomed = new Value(0); @@ -718,7 +691,9 @@ const fingerJustReleased = and( gestureJustEnded(doubleTapState), - this.outsideButtons(doubleTapX, doubleTapY), + // TODO: migrate this in the next diffs + // this.outsideButtons(doubleTapX, doubleTapY), + 1, ); return cond( @@ -1024,8 +999,8 @@ > <View style={styles.mediaIconsRow} - onLayout={this.onMediaIconsLayout} - ref={this.mediaIconsRef} + onLayout={this.props.onMediaIconsLayout} + ref={this.props.mediaIconsRef} > {saveButton} {copyButton} @@ -1051,8 +1026,8 @@ <TouchableOpacity onPress={this.close} disabled={!this.props.closeButtonEnabled} - onLayout={this.onCloseButtonLayout} - ref={this.closeButtonRef} + onLayout={this.props.onCloseButtonLayout} + ref={this.props.closeButtonRef} > <Text style={styles.closeButton}>×</Text> </TouchableOpacity> @@ -1070,43 +1045,6 @@ close = () => { this.props.navigation.goBackOnce(); }; - - closeButtonRef = ( - closeButton: ?React.ElementRef<typeof TouchableOpacity>, - ) => { - this.closeButton = (closeButton: any); - }; - - mediaIconsRef = (mediaIconsContainer: ?React.ElementRef<typeof View>) => { - this.mediaIconsContainer = mediaIconsContainer; - }; - - onCloseButtonLayout = () => { - const { closeButton } = this; - if (!closeButton) { - return; - } - closeButton.measure((x, y, width, height, pageX, pageY) => { - this.closeButtonX.setValue(pageX); - this.closeButtonY.setValue(pageY); - this.closeButtonWidth.setValue(width); - this.closeButtonHeight.setValue(height); - }); - }; - - onMediaIconsLayout = () => { - const { mediaIconsContainer } = this; - if (!mediaIconsContainer) { - return; - } - - mediaIconsContainer.measure((x, y, width, height, pageX, pageY) => { - this.mediaIconsX.setValue(pageX); - this.mediaIconsY.setValue(pageY); - this.mediaIconsWidth.setValue(width); - this.mediaIconsHeight.setValue(height); - }); - }; } const styles = StyleSheet.create({ @@ -1228,6 +1166,80 @@ [actionLinksEnabled], ); + const closeButtonRef = + React.useRef<?React.ElementRef<TouchableOpacityInstance>>(); + const mediaIconsRef = React.useRef<?React.ElementRef<typeof View>>(); + + const closeButtonDimensions = useSharedValue({ + x: -1, + y: -1, + width: 0, + height: 0, + }); + + const mediaIconsDimensions = useSharedValue({ + x: -1, + y: -1, + width: 0, + height: 0, + }); + + const closeButtonLastState = useSharedValue<boolean>(true); + const actionLinksLastState = useSharedValue<boolean>(true); + + const onCloseButtonLayout = React.useCallback(() => { + const closeButton = closeButtonRef.current; + if (!closeButton) { + return; + } + closeButton.measure((x, y, width, height, pageX, pageY) => { + closeButtonDimensions.value = { x: pageX, y: pageY, width, height }; + }); + }, [closeButtonDimensions]); + + const onMediaIconsLayout = React.useCallback(() => { + const mediaIconsContainer = mediaIconsRef.current; + if (!mediaIconsContainer) { + return; + } + + mediaIconsContainer.measure((x, y, width, height, pageX, pageY) => { + mediaIconsDimensions.value = { x: pageX, y: pageY, width, height }; + }); + }, [mediaIconsDimensions]); + + // TODO: use this in the next diffs + // eslint-disable-next-line no-unused-vars + const outsideButtons = React.useCallback( + (x: number, y: number): boolean => { + 'worklet'; + const isOutsideButton = (dim: ButtonDimensions) => { + return ( + x < dim.x || + x > dim.x + dim.width || + y < dim.y || + y > dim.y + dim.height + ); + }; + + const isOutsideCloseButton = isOutsideButton( + closeButtonDimensions.value, + ); + const isOutsideMediaIcons = isOutsideButton(mediaIconsDimensions.value); + + return ( + (closeButtonLastState.value === false || isOutsideCloseButton) && + (actionLinksLastState.value === false || isOutsideMediaIcons) + ); + }, + [ + actionLinksLastState, + closeButtonDimensions, + closeButtonLastState, + mediaIconsDimensions, + ], + ); + const gesture = React.useMemo(() => { const pinchGesture = Gesture.Pinch(); const panGesture = Gesture.Pan().averageTouches(true); @@ -1252,6 +1264,10 @@ updateCloseButtonEnabled={updateCloseButtonEnabled} updateActionLinksEnabled={updateActionLinksEnabled} gesture={gesture} + closeButtonRef={closeButtonRef} + mediaIconsRef={mediaIconsRef} + onCloseButtonLayout={onCloseButtonLayout} + onMediaIconsLayout={onMediaIconsLayout} /> ); });