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 @@ -57,7 +57,6 @@ clamp, gestureJustStarted, gestureJustEnded, - runTiming, clampV2, } from '../utils/animation-utils.js'; @@ -351,17 +350,6 @@ ); const updates = [ - this.recenter( - resetXClock, - resetYClock, - activeInteraction, - recenteredScale, - horizontalPanSpace, - verticalPanSpace, - curScale, - curX, - curY, - ), this.flingUpdate( resetXClock, resetYClock, @@ -441,56 +429,6 @@ return max(vertPop, 0); } - recenter( - // Inputs - resetXClock: Clock, - resetYClock: Clock, - activeInteraction: Node, - recenteredScale: Node, - horizontalPanSpace: Node, - verticalPanSpace: Node, - // Outputs - curScale: Value, - curX: Value, - curY: Value, - ): Node { - const resetScaleClock = new Clock(); - - const recenteredX = clamp( - curX, - multiply(-1, horizontalPanSpace), - horizontalPanSpace, - ); - const recenteredY = clamp( - curY, - multiply(-1, verticalPanSpace), - verticalPanSpace, - ); - - return cond( - activeInteraction, - [ - stopClock(resetScaleClock), - stopClock(resetXClock), - stopClock(resetYClock), - ], - [ - cond( - or(clockRunning(resetScaleClock), neq(recenteredScale, curScale)), - set(curScale, runTiming(resetScaleClock, curScale, recenteredScale)), - ), - cond( - or(clockRunning(resetXClock), neq(recenteredX, curX)), - set(curX, runTiming(resetXClock, curX, recenteredX)), - ), - cond( - or(clockRunning(resetYClock), neq(recenteredY, curY)), - set(curY, runTiming(resetYClock, curY, recenteredY)), - ), - ], - ); - } - flingUpdate( // Inputs resetXClock: Clock, @@ -1034,6 +972,8 @@ ); }); + const isRunningDismissAnimation = useSharedValue(false); + const panEnd = React.useCallback( ({ velocityX, velocityY }: PanGestureEvent) => { 'worklet'; @@ -1047,6 +987,7 @@ ); const shouldGoBack = velocity > 50 || 0.7 > progressiveOpacity.value; if (shouldGoBack && !pinchActive.value && roundedCurScale.value <= 1) { + isRunningDismissAnimation.value = true; curX.value = withDecay({ velocity: velocityX, ...decayConfig }); curY.value = withDecay({ velocity: velocityY, ...decayConfig }); cancelAnimation(curScale); @@ -1062,6 +1003,7 @@ pinchActive, roundedCurScale, curScale, + isRunningDismissAnimation, ], ); @@ -1139,6 +1081,8 @@ [outsideButtons, toggleActionLinks, toggleCloseButton, roundedCurScale], ); + const isRunningDoubleTapZoomAnimation = useSharedValue(false); + const doubleTapUpdate = React.useCallback( ({ x, y }: TapGestureEvent) => { 'worklet'; @@ -1171,7 +1115,12 @@ const targetX = tapXPercentClamped * imageWidth.value * targetScale; const targetY = tapYPercentClamped * imageHeight.value * targetScale; - curScale.value = withTiming(targetScale, defaultTimingConfig); + isRunningDoubleTapZoomAnimation.value = true; + curScale.value = withTiming( + targetScale, + defaultTimingConfig, + () => (isRunningDoubleTapZoomAnimation.value = false), + ); curX.value = withTiming(targetX, defaultTimingConfig); curY.value = withTiming(targetY, defaultTimingConfig); }, @@ -1187,6 +1136,7 @@ outsideButtons, roundedCurScale, getVerticalPanSpace, + isRunningDoubleTapZoomAnimation, ], ); @@ -1211,6 +1161,41 @@ return progressiveOpacity.value; }); + useAnimatedReaction( + () => + pinchActive.value || + panActive.value || + isRunningDismissAnimation.value || + isRunningDoubleTapZoomAnimation.value, + activeInteraction => { + if (activeInteraction) { + return; + } + const recenteredScale = Math.max(curScale.value, 1); + const horizontalPanSpace = getHorizontalPanSpace(recenteredScale); + const verticalPanSpace = getVerticalPanSpace(recenteredScale); + const recenteredX = clampV2( + curX.value, + -horizontalPanSpace, + horizontalPanSpace, + ); + const recenteredY = clampV2( + curY.value, + -verticalPanSpace, + verticalPanSpace, + ); + if (curScale.value !== recenteredScale) { + curScale.value = withTiming(recenteredScale, defaultTimingConfig); + } + if (curX.value !== recenteredX) { + curX.value = withTiming(recenteredX, defaultTimingConfig); + } + if (curY.value !== recenteredY) { + curY.value = withTiming(recenteredY, defaultTimingConfig); + } + }, + ); + const gesture = React.useMemo(() => { const pinchGesture = Gesture.Pinch() .onStart(pinchStart)