diff --git a/src/components/Attachments/AttachmentCarousel/CarouselItem.js b/src/components/Attachments/AttachmentCarousel/CarouselItem.js index 5552f15320f3..abe371768879 100644 --- a/src/components/Attachments/AttachmentCarousel/CarouselItem.js +++ b/src/components/Attachments/AttachmentCarousel/CarouselItem.js @@ -37,15 +37,6 @@ const propTypes = { transactionID: PropTypes.string, }).isRequired, - /** Whether there is only one element in the attachment carousel */ - isSingleItem: PropTypes.bool.isRequired, - - /** The index of the carousel item */ - index: PropTypes.number.isRequired, - - /** The index of the currently active carousel item */ - activeIndex: PropTypes.number.isRequired, - /** onPress callback */ onPress: PropTypes.func, }; @@ -54,7 +45,7 @@ const defaultProps = { onPress: undefined, }; -function CarouselItem({item, index, activeIndex, isSingleItem, onPress}) { +function CarouselItem({item, onPress}) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isAttachmentHidden} = useContext(ReportAttachmentsContext); @@ -103,12 +94,8 @@ function CarouselItem({item, index, activeIndex, isSingleItem, onPress}) { diff --git a/src/components/Attachments/AttachmentCarousel/Pager/index.js b/src/components/Attachments/AttachmentCarousel/Pager/index.js index e0f652e47e4c..84f77dae4953 100644 --- a/src/components/Attachments/AttachmentCarousel/Pager/index.js +++ b/src/components/Attachments/AttachmentCarousel/Pager/index.js @@ -3,8 +3,9 @@ import React, {useEffect, useImperativeHandle, useMemo, useRef, useState} from ' import {View} from 'react-native'; import {createNativeWrapper} from 'react-native-gesture-handler'; import PagerView from 'react-native-pager-view'; -import Animated, {runOnJS, useAnimatedProps, useAnimatedReaction, useEvent, useHandler, useSharedValue} from 'react-native-reanimated'; +import Animated, {runOnJS, useAnimatedReaction, useEvent, useHandler, useSharedValue} from 'react-native-reanimated'; import _ from 'underscore'; +import CarouselItem from '@components/Attachments/AttachmentCarousel/CarouselItem'; import refPropTypes from '@components/refPropTypes'; import useThemeStyles from '@hooks/useThemeStyles'; import AttachmentCarouselPagerContext from './AttachmentCarouselPagerContext'; @@ -36,8 +37,9 @@ const pagerPropTypes = { url: PropTypes.string, }), ).isRequired, - renderItem: PropTypes.func.isRequired, - initialIndex: PropTypes.number, + activeSource: PropTypes.string.isRequired, + initialPage: PropTypes.number, + scrollEnabled: PropTypes.bool, onPageSelected: PropTypes.func, onTap: PropTypes.func, onScaleChanged: PropTypes.func, @@ -45,53 +47,61 @@ const pagerPropTypes = { }; const pagerDefaultProps = { - initialIndex: 0, + initialPage: 0, + scrollEnabled: true, onPageSelected: () => {}, onTap: () => {}, onScaleChanged: () => {}, forwardedRef: null, }; -function AttachmentCarouselPager({items, renderItem, initialIndex, onPageSelected, onTap, onScaleChanged, forwardedRef}) { +function AttachmentCarouselPager({items, activeSource, initialPage, scrollEnabled, onPageSelected, onTap, onScaleChanged, forwardedRef}) { const styles = useThemeStyles(); - const shouldPagerScroll = useSharedValue(true); const pagerRef = useRef(null); - const isSwipingInPager = useSharedValue(false); - const activeIndex = useSharedValue(initialIndex); + const activePage = useSharedValue(initialPage); + const [activePageState, setActivePageState] = useState(initialPage); + // Set active page initially and when initial page changes + useEffect(() => { + setActivePageState(initialPage); + activePage.value = initialPage; + }, [activePage, initialPage]); + + const itemsMeta = useMemo(() => _.map(items, (item, index) => ({source: item.source, index, isActive: index === activePageState})), [activePageState, items]); + + const isPagerSwiping = useSharedValue(false); const pageScrollHandler = usePageScrollHandler( { onPageScroll: (e) => { 'worklet'; - activeIndex.value = e.position; - isSwipingInPager.value = e.offset !== 0; + activePage.value = e.position; + isPagerSwiping.value = e.offset !== 0; }, }, [], ); - const [activePage, setActivePage] = useState(initialIndex); - - useEffect(() => { - setActivePage(initialIndex); - activeIndex.value = initialIndex; - }, [activeIndex, initialIndex]); - - // we use reanimated for this since onPageSelected is called - // in the middle of the pager animation + const [isPagerSwipingState, setPagerSwipingState] = useState(false); useAnimatedReaction( - () => isSwipingInPager.value, - (stillScrolling) => { - if (stillScrolling) { - return; - } - - runOnJS(setActivePage)(activeIndex.value); + () => [isPagerSwiping.value], + (isSwiping) => { + runOnJS(setPagerSwipingState)(isSwiping); }, ); + const contextValue = useMemo( + () => ({ + itemsMeta, + activePage: activePageState, + isPagerSwiping: isPagerSwipingState, + onTap, + onScaleChanged, + }), + [activePageState, isPagerSwipingState, itemsMeta, onScaleChanged, onTap], + ); + useImperativeHandle( forwardedRef, () => ({ @@ -100,19 +110,22 @@ function AttachmentCarouselPager({items, renderItem, initialIndex, onPageSelecte [], ); - const animatedProps = useAnimatedProps(() => ({ - scrollEnabled: shouldPagerScroll.value, - })); - - const contextValue = useMemo( - () => ({ - onTap, - onScaleChanged, - pagerRef, - shouldPagerScroll, - isSwipingInPager, - }), - [isSwipingInPager, shouldPagerScroll, onScaleChanged, onTap], + const Content = useMemo( + () => + _.map(items, (item, index) => ( + + + + )), + [activePageState, activeSource, items, styles.flex1], ); return ( @@ -120,21 +133,14 @@ function AttachmentCarouselPager({items, renderItem, initialIndex, onPageSelecte - {_.map(items, (item, index) => ( - - {renderItem({item, index, isActive: index === activePage})} - - ))} + {Content} ); diff --git a/src/components/Attachments/AttachmentCarousel/index.native.js b/src/components/Attachments/AttachmentCarousel/index.native.js index 8f168093c217..64262b38b0d1 100644 --- a/src/components/Attachments/AttachmentCarousel/index.native.js +++ b/src/components/Attachments/AttachmentCarousel/index.native.js @@ -13,7 +13,6 @@ import variables from '@styles/variables'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, propTypes} from './attachmentCarouselPropTypes'; import CarouselButtons from './CarouselButtons'; -import CarouselItem from './CarouselItem'; import extractAttachmentsFromReport from './extractAttachmentsFromReport'; import AttachmentCarouselPager from './Pager'; import useCarouselArrows from './useCarouselArrows'; @@ -88,25 +87,6 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, [autoHideArrows, page, updatePage], ); - /** - * Defines how a single attachment should be rendered - * @param {{ reportActionID: String, isAuthTokenRequired: Boolean, source: String, file: { name: String }, hasBeenFlagged: Boolean }} item - * @returns {JSX.Element} - */ - const renderItem = useCallback( - ({item, index, isActive}) => ( - setShouldShowArrows(!shouldShowArrows)} - /> - ), - [activeSource, attachments.length, page, setShouldShowArrows, shouldShowArrows], - ); - const handleScaleChange = useCallback( (newScale) => { const newIsZoomedOut = newScale === 1; @@ -122,11 +102,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, ); return ( - setShouldShowArrows(true)} - onMouseLeave={() => setShouldShowArrows(false)} - > + {page == null ? ( ) : ( @@ -152,8 +128,10 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, setShouldShowArrows(!shouldShowArrows)} onPageSelected={({nativeEvent: {position: newPage}}) => updatePage(newPage)} onScaleChanged={handleScaleChange} ref={pagerRef} diff --git a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js index f53b993f6053..05c27213557f 100755 --- a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js +++ b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js @@ -12,22 +12,7 @@ const propTypes = { ...withLocalizePropTypes, }; -function AttachmentViewImage({ - source, - file, - isAuthTokenRequired, - isUsedInCarousel, - isSingleCarouselItem, - carouselItemIndex, - carouselActiveItemIndex, - isFocused, - loadComplete, - onPress, - onError, - isImage, - onScaleChanged, - translate, -}) { +function AttachmentViewImage({source, file, isAuthTokenRequired, isFocused, loadComplete, onPress, onError, isImage, onScaleChanged, translate}) { const styles = useThemeStyles(); const children = ( ); diff --git a/src/components/Attachments/AttachmentView/index.js b/src/components/Attachments/AttachmentView/index.js index b0060afdb813..179d627a23fa 100755 --- a/src/components/Attachments/AttachmentView/index.js +++ b/src/components/Attachments/AttachmentView/index.js @@ -72,9 +72,6 @@ function AttachmentView({ translate, isFocused, isUsedInCarousel, - isSingleCarouselItem, - carouselItemIndex, - carouselActiveItemIndex, isUsedInAttachmentModal, isWorkspaceAvatar, fallbackSource, @@ -138,8 +135,6 @@ function AttachmentView({ isFocused={isFocused} isAuthTokenRequired={isAuthTokenRequired} encryptedSourceUrl={encryptedSourceUrl} - carouselItemIndex={carouselItemIndex} - carouselActiveItemIndex={carouselActiveItemIndex} onPress={onPress} onScaleChanged={onScaleChanged} onToggleKeyboard={onToggleKeyboard} @@ -169,9 +164,6 @@ function AttachmentView({ loadComplete={loadComplete} isFocused={isFocused} isUsedInCarousel={isUsedInCarousel} - isSingleCarouselItem={isSingleCarouselItem} - carouselItemIndex={carouselItemIndex} - carouselActiveItemIndex={carouselActiveItemIndex} isImage={isImage} onPress={onPress} onScaleChanged={onScaleChanged} diff --git a/src/components/Attachments/AttachmentView/propTypes.js b/src/components/Attachments/AttachmentView/propTypes.js index 286c903ccf5b..31750da53e77 100644 --- a/src/components/Attachments/AttachmentView/propTypes.js +++ b/src/components/Attachments/AttachmentView/propTypes.js @@ -17,18 +17,6 @@ const attachmentViewPropTypes = { /** Whether this AttachmentView is shown as part of a AttachmentCarousel */ isUsedInCarousel: PropTypes.bool, - /** When "isUsedInCarousel" is set to true, determines whether there is only one item in the carousel */ - isSingleCarouselItem: PropTypes.bool, - - /** Whether this AttachmentView is shown as part of an AttachmentModal */ - isUsedInAttachmentModal: PropTypes.bool, - - /** The index of the carousel item */ - carouselItemIndex: PropTypes.number, - - /** The index of the currently active carousel item */ - carouselActiveItemIndex: PropTypes.number, - /** Function for handle on press */ onPress: PropTypes.func, @@ -42,11 +30,8 @@ const attachmentViewDefaultProps = { name: '', }, isFocused: false, - isUsedInCarousel: false, - isSingleCarouselItem: false, - carouselItemIndex: 0, - carouselActiveItemIndex: 0, isSingleElement: false, + isUsedInCarousel: false, isUsedInAttachmentModal: false, onPress: undefined, onScaleChanged: () => {}, diff --git a/src/components/ImageView/index.native.js b/src/components/ImageView/index.native.js index 98349b213aa5..007bc753ec0d 100644 --- a/src/components/ImageView/index.native.js +++ b/src/components/ImageView/index.native.js @@ -11,9 +11,6 @@ const propTypes = { ...imageViewPropTypes, ...zoomRangePropTypes, - /** Function for handle on press */ - onPress: PropTypes.func, - /** Additional styles to add to the component */ style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), }; @@ -26,20 +23,14 @@ const defaultProps = { style: {}, }; -function ImageView({isAuthTokenRequired, url, onScaleChanged, onPress, style, zoomRange, onError, isUsedInCarousel, isSingleCarouselItem, carouselItemIndex, carouselActiveItemIndex}) { - const hasSiblingCarouselItems = isUsedInCarousel && !isSingleCarouselItem; - +function ImageView({isAuthTokenRequired, url, onScaleChanged, style, zoomRange, onError}) { return ( ); diff --git a/src/components/ImageView/propTypes.js b/src/components/ImageView/propTypes.js index 3809d9aed043..359626e4bd69 100644 --- a/src/components/ImageView/propTypes.js +++ b/src/components/ImageView/propTypes.js @@ -19,28 +19,12 @@ const imageViewPropTypes = { /** Whether this view is the active screen */ isFocused: PropTypes.bool, - - /** Whether this AttachmentView is shown as part of a AttachmentCarousel */ - isUsedInCarousel: PropTypes.bool, - - /** When "isUsedInCarousel" is set to true, determines whether there is only one item in the carousel */ - isSingleCarouselItem: PropTypes.bool, - - /** The index of the carousel item */ - carouselItemIndex: PropTypes.number, - - /** The index of the currently active carousel item */ - carouselActiveItemIndex: PropTypes.number, }; const imageViewDefaultProps = { isAuthTokenRequired: false, onError: () => {}, isFocused: true, - isUsedInCarousel: false, - isSingleCarouselItem: false, - carouselItemIndex: 0, - carouselActiveItemIndex: 0, }; export {imageViewPropTypes, imageViewDefaultProps}; diff --git a/src/components/Lightbox.js b/src/components/Lightbox.js index 366759cc6cd7..6f1f7a0c6437 100644 --- a/src/components/Lightbox.js +++ b/src/components/Lightbox.js @@ -1,8 +1,10 @@ /* eslint-disable es/no-optional-chaining */ +import _ from 'lodash'; import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react'; import {ActivityIndicator, PixelRatio, StyleSheet, View} from 'react-native'; import useStyleUtils from '@hooks/useStyleUtils'; +import AttachmentCarouselPagerContext from './Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext'; import * as AttachmentsPropTypes from './Attachments/propTypes'; import Image from './Image'; import MultiGestureCanvas from './MultiGestureCanvas'; @@ -25,9 +27,6 @@ const propTypes = { /** Triggers whenever the zoom scale changes */ onScaleChanged: PropTypes.func, - /** Function for handle on press */ - onPress: PropTypes.func, - /** Handles errors while displaying the image */ onError: PropTypes.func, @@ -37,15 +36,6 @@ const propTypes = { /** Whether source url requires authentication */ isAuthTokenRequired: PropTypes.bool, - /** Whether the Lightbox is used within a carousel component and there are other sibling elements */ - hasSiblingCarouselItems: PropTypes.bool, - - /** The index of the carousel item */ - index: PropTypes.number, - - /** The index of the currently active carousel item */ - activeIndex: PropTypes.number, - /** Additional styles to add to the component */ style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), }; @@ -54,20 +44,39 @@ const defaultProps = { ...zoomRangeDefaultProps, isAuthTokenRequired: false, - index: 0, - activeIndex: 0, - hasSiblingCarouselItems: false, onScaleChanged: () => {}, - onPress: () => {}, onError: () => {}, style: {}, }; const DEFAULT_IMAGE_SIZE = 200; -function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError, style, index, activeIndex, hasSiblingCarouselItems, zoomRange}) { +function Lightbox({isAuthTokenRequired, source, onScaleChanged, onError, style, zoomRange}) { const StyleUtils = useStyleUtils(); + const attachmentCarouselPagerContext = useContext(AttachmentCarouselPagerContext); + const {isUsedInCarousel, isSingleCarouselItem, page, activePage, onTap, isPagerSwiping} = useMemo(() => { + if (attachmentCarouselPagerContext == null) { + return { + isUsedInCarousel: false, + isSingleCarouselItem: true, + page: 0, + activePage: 0, + onTap: () => {}, + isPagerSwiping: false, + }; + } + + const foundPageIndex = _.findIndex(attachmentCarouselPagerContext.itemsMeta, (item) => item.source === source); + return { + ...attachmentCarouselPagerContext, + isUsedInCarousel: true, + isSingleCarouselItem: attachmentCarouselPagerContext.itemsMeta.length === 1, + page: foundPageIndex, + }; + }, [attachmentCarouselPagerContext, source]); + const hasSiblingCarouselItems = isUsedInCarousel && !isSingleCarouselItem; + const [containerSize, setContainerSize] = useState({width: 0, height: 0}); const isContainerLoaded = containerSize.width !== 0 && containerSize.height !== 0; @@ -77,8 +86,8 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError cachedDimensions.set(source, newDimensions); }; - const isItemActive = index === activeIndex; - const [isActive, setActive] = useState(isItemActive); + const isActivePage = page === activePage; + const [isActive, setActive] = useState(isActivePage); const [isImageLoaded, setImageLoaded] = useState(false); const isInactiveCarouselItem = hasSiblingCarouselItems && !isActive; @@ -92,9 +101,9 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError } const indexCanvasOffset = Math.floor((NUMBER_OF_CONCURRENT_LIGHTBOXES - 1) / 2) || 0; - const indexOutOfRange = index > activeIndex + indexCanvasOffset || index < activeIndex - indexCanvasOffset; + const indexOutOfRange = page > activePage + indexCanvasOffset || page < activePage - indexCanvasOffset; return !indexOutOfRange; - }, [activeIndex, index]); + }, [activePage, page]); const isLightboxVisible = isLightboxInRange && (isActive || isLightboxLoaded || isFallbackLoaded); // If the fallback image is currently visible, we want to hide the Lightbox until the fallback gets hidden, @@ -114,12 +123,12 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError // to prevent the image transformer from flashing while still rendering // Instead, we show the fallback image while the image transformer is loading the image useEffect(() => { - if (isItemActive) { + if (isActivePage) { setTimeout(() => setActive(true), 1); } else { setActive(false); } - }, [isItemActive]); + }, [isActivePage]); useEffect(() => { if (isLightboxVisible) { @@ -171,7 +180,6 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError return ( @@ -181,6 +189,8 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError - attachmentCarouselPagerContext || { - onTap: () => {}, - onScaleChanged: () => {}, - pagerRef: pagerRefFallback, - shouldPagerScroll: false, - isSwipingInPager: false, - }, - [attachmentCarouselPagerContext], - ); - - const onScaleChanged = useCallback( - (newScale) => { - onScaleChangedProp(newScale); - onScaleChangedContext(newScale); - }, - [onScaleChangedContext, onScaleChangedProp], - ); - // Based on the (original) content size and the canvas size, we calculate the horizontal and vertical scale factors // to fit the content inside the canvas // We later use the lower of the two scale factors to fit the content inside the canvas @@ -123,7 +92,8 @@ function MultiGestureCanvas({canvasSize, isActive = true, onScaleChanged: onScal zoomScale.value = 1; }); - const {singleTapGesture: basicSingleTapGesture, doubleTapGesture} = useTapGestures({ + const {singleTapGesture: baseSingleTapGesture, doubleTapGesture} = useTapGestures({ + areTransformationsEnabled, canvasSize, contentSize, minContentScale, @@ -138,9 +108,10 @@ function MultiGestureCanvas({canvasSize, isActive = true, onScaleChanged: onScal onScaleChanged, onTap, }); - const singleTapGesture = basicSingleTapGesture.requireExternalGestureToFail(doubleTapGesture, panGestureRef); + const singleTapGesture = baseSingleTapGesture.requireExternalGestureToFail(doubleTapGesture, panGestureRef); const panGesture = usePanGesture({ + areTransformationsEnabled, canvasSize, contentSize, zoomScale, @@ -149,13 +120,13 @@ function MultiGestureCanvas({canvasSize, isActive = true, onScaleChanged: onScal offsetY, panTranslateX, panTranslateY, - isSwipingInPager, stopAnimation, }) - .simultaneousWithExternalGesture(pagerRef, singleTapGesture, doubleTapGesture) + .simultaneousWithExternalGesture(singleTapGesture, doubleTapGesture) .withRef(panGestureRef); const pinchGesture = usePinchGesture({ + areTransformationsEnabled, canvasSize, zoomScale, zoomRange, @@ -164,20 +135,10 @@ function MultiGestureCanvas({canvasSize, isActive = true, onScaleChanged: onScal pinchTranslateX, pinchTranslateY, pinchScale, - isSwipingInPager, stopAnimation, onScaleChanged, }).simultaneousWithExternalGesture(panGesture, singleTapGesture, doubleTapGesture); - // Enables/disables the pager scroll based on the zoom scale - // When the content is zoomed in/out, the pager should be disabled - useAnimatedReaction( - () => zoomScale.value, - () => { - shouldPagerScroll.value = zoomScale.value === 1; - }, - ); - // Trigger a reset when the canvas gets inactive, but only if it was already mounted before const mounted = useRef(false); useEffect(() => { diff --git a/src/components/MultiGestureCanvas/propTypes.js b/src/components/MultiGestureCanvas/propTypes.js index f1961ec0e156..744dd07db0c8 100644 --- a/src/components/MultiGestureCanvas/propTypes.js +++ b/src/components/MultiGestureCanvas/propTypes.js @@ -29,6 +29,9 @@ const multiGestureCanvasPropTypes = { */ isActive: PropTypes.bool, + /** Whether pan, pinch and double tap transformations are enabled */ + areTransformationsEnabled: PropTypes.bool, + /** Handles scale changed event */ onScaleChanged: PropTypes.func, @@ -64,6 +67,7 @@ const multiGestureCanvasPropTypes = { const multiGestureCanvasDefaultProps = { isActive: true, + areTransformationsEnabled: true, onScaleChanged: () => undefined, contentSize: undefined, contentScaling: undefined, diff --git a/src/components/MultiGestureCanvas/usePanGesture.js b/src/components/MultiGestureCanvas/usePanGesture.js index aec24cb2e99e..27067511a135 100644 --- a/src/components/MultiGestureCanvas/usePanGesture.js +++ b/src/components/MultiGestureCanvas/usePanGesture.js @@ -8,7 +8,7 @@ import * as MultiGestureCanvasUtils from './utils'; // https://docs.swmansion.com/react-native-reanimated/docs/animations/withDecay/ const PAN_DECAY_DECELARATION = 0.9915; -const usePanGesture = ({canvasSize, contentSize, zoomScale, totalScale, offsetX, offsetY, panTranslateX, panTranslateY, isSwipingInPager, stopAnimation}) => { +const usePanGesture = ({areTransformationsEnabled, canvasSize, contentSize, zoomScale, totalScale, offsetX, offsetY, panTranslateX, panTranslateY, stopAnimation}) => { // The content size after fitting it to the canvas and zooming const zoomedContentWidth = useDerivedValue(() => contentSize.width * totalScale.value, [contentSize.width]); const zoomedContentHeight = useDerivedValue(() => contentSize.height * totalScale.value, [contentSize.height]); @@ -107,8 +107,8 @@ const usePanGesture = ({canvasSize, contentSize, zoomScale, totalScale, offsetX, .manualActivation(true) .averageTouches(true) .onTouchesMove((_evt, state) => { - // We only allow panning when the content is zoomed in - if (zoomScale.value <= 1 || isSwipingInPager.value) { + // We only allow panning when the content is zoomed in and the tranformations are enabled + if (zoomScale.value <= 1 || !areTransformationsEnabled) { return; } @@ -137,8 +137,8 @@ const usePanGesture = ({canvasSize, contentSize, zoomScale, totalScale, offsetX, panTranslateX.value = 0; panTranslateY.value = 0; - // If we are swiping (in the pager), we don't want to return to boundaries - if (isSwipingInPager.value) { + // If we the MultiGestureCanvas is disabled, we don't want to return to boundaries + if (!areTransformationsEnabled) { return; } diff --git a/src/components/MultiGestureCanvas/usePinchGesture.js b/src/components/MultiGestureCanvas/usePinchGesture.js index 21c5e55e0117..63f023251aa4 100644 --- a/src/components/MultiGestureCanvas/usePinchGesture.js +++ b/src/components/MultiGestureCanvas/usePinchGesture.js @@ -5,6 +5,7 @@ import {runOnJS, useAnimatedReaction, useSharedValue, withSpring} from 'react-na import * as MultiGestureCanvasUtils from './utils'; const usePinchGesture = ({ + areTransformationsEnabled, canvasSize, zoomScale, zoomRange, @@ -13,7 +14,6 @@ const usePinchGesture = ({ pinchTranslateX: totalPinchTranslateX, pinchTranslateY: totalPinchTranslateY, pinchScale, - isSwipingInPager, stopAnimation, onScaleChanged, }) => { @@ -71,8 +71,8 @@ const usePinchGesture = ({ const pinchGesture = Gesture.Pinch() .enabled(pinchEnabled) .onTouchesDown((_evt, state) => { - // We don't want to activate pinch gesture when we are swiping in the pager - if (!isSwipingInPager.value) { + // We don't want to activate pinch gesture when transformations are disabled + if (!areTransformationsEnabled) { return; } diff --git a/src/components/MultiGestureCanvas/useTapGestures.js b/src/components/MultiGestureCanvas/useTapGestures.js index eefe8c506b33..467b005fb1a2 100644 --- a/src/components/MultiGestureCanvas/useTapGestures.js +++ b/src/components/MultiGestureCanvas/useTapGestures.js @@ -6,7 +6,21 @@ import * as MultiGestureCanvasUtils from './utils'; const DOUBLE_TAP_SCALE = 3; -const useTapGestures = ({canvasSize, contentSize, minContentScale, maxContentScale, offsetX, offsetY, pinchScale, zoomScale, reset, stopAnimation, onScaleChanged, onTap}) => { +const useTapGestures = ({ + areTransformationsEnabled, + canvasSize, + contentSize, + minContentScale, + maxContentScale, + offsetX, + offsetY, + pinchScale, + zoomScale, + reset, + stopAnimation, + onScaleChanged, + onTap, +}) => { // The content size after scaling it with minimum scale to fit the content into the canvas const scaledContentWidth = useMemo(() => contentSize.width * minContentScale, [contentSize.width, minContentScale]); const scaledContentHeight = useMemo(() => contentSize.height * minContentScale, [contentSize.height, minContentScale]); @@ -88,6 +102,13 @@ const useTapGestures = ({canvasSize, contentSize, minContentScale, maxContentSca ); const doubleTapGesture = Gesture.Tap() + .onTouchesDown((_evt, state) => { + if (areTransformationsEnabled) { + return; + } + + state.fail(); + }) .numberOfTaps(2) .maxDelay(150) .maxDistance(20)