diff --git a/src/components/ZoomableImage.tsx b/src/components/ZoomableImage.tsx index acdd87d..0b613c8 100644 --- a/src/components/ZoomableImage.tsx +++ b/src/components/ZoomableImage.tsx @@ -6,6 +6,8 @@ import { Animated, PanResponder } from 'react-native'; // While zoomed in, responder termination is refused so the parent ScrollView // cannot steal the gesture — the photo pans instead of paging; swiping to the // next photo resumes after zooming back out (double tap or pinch below 1.15). +// Two-finger pinch only zooms once the photo is already zoomed in: at 100% the +// pinch stays inert, so the paging strip still behaves like a plain gallery. // // ponytail: pinch zooms around the image center, not the finger midpoint; // focal zoom needs per-touch location math against the image's screen rect. @@ -99,7 +101,8 @@ export default function ZoomableImage({ uri, width }: ZoomableImageProps) { onMoveShouldSetPanResponder: () => true, // Page the strip while zoom is off; once zoomed (or mid-pinch) the // image keeps the gesture for panning/zooming itself. - onPanResponderTerminationRequest: () => st.scale <= 1.001, + onPanResponderTerminationRequest: () => + st.scale <= 1.001 && st.pinchStart === null, onPanResponderGrant: () => { st.grantAt = Date.now(); st.moved = false; @@ -113,10 +116,13 @@ export default function ZoomableImage({ uri, width }: ZoomableImageProps) { const b = touches[1]; const dist = Math.hypot(a.pageX - b.pageX, a.pageY - b.pageY); if (!st.pinchStart) st.pinchStart = { scale: st.scale, dist: dist || 1 }; - const next = Math.max( - 1, - Math.min(MAX_SCALE, st.pinchStart.scale * (dist / st.pinchStart.dist)) - ); + const next = + st.pinchStart.scale > 1.001 + ? Math.max( + 1, + Math.min(MAX_SCALE, st.pinchStart.scale * (dist / st.pinchStart.dist)) + ) + : 1; st.scale = next; if (next <= 1.001) { st.tx = 0;