feat(media): two-finger pinch zoom in the media viewer (#164)
Zoom on a phone was only the +/- buttons; the pinch people try first did nothing. usePinchZoom tracks a two-finger gesture on the viewer's media area and scales from the zoom it started at (clamped 1×–5×, snapping back to exactly 1× when released near it, so one-finger swipe navigation re-arms). The area gets touch-action: none so the browser doesn't zoom the page instead. One-finger swipe and pan already ignore multi-touch. Verified on an emulated Pixel 7 with CDP two-point touch: spread 80→200 px gives 250 %, closing to 120 px gives 150 %, closing fully returns to 100 %, and a one-finger swipe afterwards still moves 2/2 → 1/2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c1661e48fa
commit
39589b40f3
@@ -24,6 +24,7 @@ import { useNearViewport } from '../../hooks/useNearViewport';
|
||||
import { useZoom } from '../../hooks/useZoom';
|
||||
import { usePan, Pan } from '../../hooks/usePan';
|
||||
import { useSwipeNav } from '../../hooks/useSwipeNav';
|
||||
import { usePinchZoom } from '../../hooks/usePinchZoom';
|
||||
import { IEncryptedFile, IImageInfo, IThumbnailContent } from '../../../types/matrix/common';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||
@@ -266,6 +267,14 @@ export function Lightbox({
|
||||
useCallback(() => setIndex((i) => Math.max(0, i - 1)), []),
|
||||
);
|
||||
const dialogRef = useRef<HTMLDivElement>(null);
|
||||
const onPinchStart = usePinchZoom(isImage, zoom, setZoom);
|
||||
const onMediaTouchStart = useCallback<React.TouchEventHandler<HTMLElement>>(
|
||||
(e) => {
|
||||
swipe.onTouchStart(e);
|
||||
onPinchStart(e);
|
||||
},
|
||||
[swipe, onPinchStart],
|
||||
);
|
||||
const toggleZoom = useCallback(() => setZoom((z) => (z === 1 ? 2 : 1)), [setZoom]);
|
||||
|
||||
// Reset zoom when navigating to another item (and thus pan, via usePan).
|
||||
@@ -455,9 +464,11 @@ export function Lightbox({
|
||||
alignItems="Center"
|
||||
justifyContent="Center"
|
||||
onWheel={handleWheel}
|
||||
onTouchStart={swipe.onTouchStart}
|
||||
onTouchStart={onMediaTouchStart}
|
||||
onTouchEnd={swipe.onTouchEnd}
|
||||
style={{ overflow: 'hidden', padding: config.space.S400 }}
|
||||
// Our own swipe/pinch/pan handle touch here; stop the browser from
|
||||
// zooming or scrolling the page underneath instead.
|
||||
style={{ overflow: 'hidden', padding: config.space.S400, touchAction: 'none' }}
|
||||
>
|
||||
{index > 0 && (
|
||||
<IconButton
|
||||
|
||||
Reference in New Issue
Block a user