diff --git a/interface/app/$libraryId/Explorer/QuickPreview/index.tsx b/interface/app/$libraryId/Explorer/QuickPreview/index.tsx index 7527d1ac6..8de1afc4b 100644 --- a/interface/app/$libraryId/Explorer/QuickPreview/index.tsx +++ b/interface/app/$libraryId/Explorer/QuickPreview/index.tsx @@ -93,6 +93,9 @@ export const QuickPreview = () => { const [thumbnailLoading, setThumbnailLoading] = useState<'notLoaded' | 'loaded' | 'error'>( 'notLoaded' ); + // the purpose of these refs is to prevent "jittering" when zooming with trackpads, as the deltaY value can be very high + const deltaYRef = useRef(0); + const lastZoomTimeRef = useRef(0); const { t } = useLocale(); @@ -198,6 +201,55 @@ export const QuickPreview = () => { getQuickPreviewStore().itemIndex = 0; }; + const handleZoomIn = useCallback(() => { + setMagnification((currentMagnification) => + currentMagnification < 2 + ? currentMagnification + currentMagnification * 0.1 + : currentMagnification + ); + }, []); + + const handleZoomOut = useCallback(() => { + setMagnification((currentMagnification) => + currentMagnification > 0.5 ? currentMagnification / (1 + 0.1) : currentMagnification + ); + }, []); + + // pinch support for trackpads + const applyZoom = useCallback(() => { + if (deltaYRef.current < 0) { + handleZoomIn(); + } else if (deltaYRef.current > 0) { + handleZoomOut(); + } + deltaYRef.current = 0; + }, [handleZoomIn, handleZoomOut]); + + const handleWheel = useCallback( + (event: WheelEvent) => { + if (event.ctrlKey) { + event.preventDefault(); + deltaYRef.current += event.deltaY; + const now = Date.now(); + if (now - lastZoomTimeRef.current > 50) { + applyZoom(); + lastZoomTimeRef.current = now; + } + } + }, + [applyZoom] + ); + + useEffect(() => { + window.addEventListener('wheel', handleWheel, { passive: false }); + return () => { + window.removeEventListener('wheel', handleWheel); + }; + }, [handleWheel]); + + useShortcut('zoomIn', handleZoomIn); + useShortcut('zoomOut', handleZoomOut); + useShortcut('quickPreviewMoveBack', () => { if (isContextMenuOpen || isRenaming) return; handleMoveBetweenItems(-1); @@ -455,14 +507,7 @@ export const QuickPreview = () => {
{ - magnification < 2 && - setMagnification( - (currentMagnification) => - currentMagnification + - currentMagnification * 0.2 - ); - }} + onClick={handleZoomIn} // this is same formula as interest calculation > @@ -471,13 +516,7 @@ export const QuickPreview = () => { { - magnification > 0.5 && - setMagnification( - (currentMagnification) => - currentMagnification / (1 + 0.2) - ); - }} + onClick={handleZoomOut} // this is same formula as interest calculation > diff --git a/interface/hooks/useShortcut.ts b/interface/hooks/useShortcut.ts index 1bd51fd90..76a3f7194 100644 --- a/interface/hooks/useShortcut.ts +++ b/interface/hooks/useShortcut.ts @@ -155,6 +155,14 @@ const shortcuts = { toggleSidebar: { all: ['Control', 'KeyS'], macOS: ['Meta', 'KeyS'] + }, + zoomIn: { + macOS: ['Meta', '='], + all: ['Control', '='] + }, + zoomOut: { + macOS: ['Meta', '-'], + all: ['Control', '-'] } } satisfies Record; diff --git a/patches/@oscartbeaumont-sd__rspc-tauri@0.0.0-main-dc31e5b2.patch b/patches/@oscartbeaumont-sd__rspc-tauri@0.0.0-main-dc31e5b2.patch index ce63311a2..b21e28f95 100644 --- a/patches/@oscartbeaumont-sd__rspc-tauri@0.0.0-main-dc31e5b2.patch +++ b/patches/@oscartbeaumont-sd__rspc-tauri@0.0.0-main-dc31e5b2.patch @@ -7,7 +7,7 @@ index df70b20e9381e7bf44f9a35b11174e40ede80376..bc06927b7290891717c48999f79d0705 // @ts-ignore this.requestMap.set(id, resolve); - await window.appWindow.emit("plugin:rspc:transport", { -+ await window.getCurrent().emit("plugin:rspc:transport", { ++ await window.getCurrentWindow().emit("plugin:rspc:transport", { id, method: operation, params: { @@ -19,8 +19,8 @@ index a80ac6155a4a920173c442b4d7b458a46ab63624..03b3d9ee6d3691980584c1fd58c17f7c import { randomId, RSPCError } from '@oscartbeaumont-sd/rspc-client'; import { listen } from '@tauri-apps/api/event'; -import { appWindow } from '@tauri-apps/api/window'; -+import { getCurrent } from '@tauri-apps/api/window'; - ++import { getCurrentWindow } from '@tauri-apps/api/window'; + // @ts-nocheck No one asked class TauriTransport { @@ -15,7 +15,7 @@ class TauriTransport { @@ -28,7 +28,7 @@ index a80ac6155a4a920173c442b4d7b458a46ab63624..03b3d9ee6d3691980584c1fd58c17f7c // @ts-ignore this.requestMap.set(id, resolve); - await appWindow.emit("plugin:rspc:transport", { -+ await getCurrent().emit("plugin:rspc:transport", { ++ await getCurrentWindow().emit("plugin:rspc:transport", { id, method: operation, params: { @@ -41,7 +41,7 @@ index e597db7bf00a7e62f32266814345b257b8f8d0da..fa683640a0c0c9f1796ed1af1fd0d04c await listener; } - await window.appWindow.emit("plugin:rspc:transport", currentBatch); -+ await window.getCurrent().emit("plugin:rspc:transport", currentBatch); ++ await window.getCurrentWindow().emit("plugin:rspc:transport", currentBatch); })(); }); } @@ -53,8 +53,8 @@ index bd7ceb6927d187dd2ff7cf9a9364d7c312a75b88..844495e36aef0c1337e7393685c1a33f import { AlphaRSPCError } from '@oscartbeaumont-sd/rspc-client/v2'; import { listen } from '@tauri-apps/api/event'; -import { appWindow } from '@tauri-apps/api/window'; -+import { getCurrent } from '@tauri-apps/api/window'; - ++import { getCurrentWindow } from '@tauri-apps/api/window'; + // @ts-nocheck No one asked /** @@ -42,7 +42,7 @@ import { appWindow } from '@tauri-apps/api/window'; @@ -62,7 +62,7 @@ index bd7ceb6927d187dd2ff7cf9a9364d7c312a75b88..844495e36aef0c1337e7393685c1a33f await listener; } - await appWindow.emit("plugin:rspc:transport", currentBatch); -+ await getCurrent().emit("plugin:rspc:transport", currentBatch); ++ await getCurrentWindow().emit("plugin:rspc:transport", currentBatch); })(); }); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 014be1add..4ead2ad2c 100644 Binary files a/pnpm-lock.yaml and b/pnpm-lock.yaml differ diff --git a/scripts/setup.sh b/scripts/setup.sh index d746d5c24..eb942b4b4 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -185,7 +185,7 @@ case "$(uname)" in fi # Tauri dependencies - set -- openssl webkit2gtk4.1-devel openssl-dev curl wget file libappindicator-gtk3-devel librsvg2-devel libxdo-devel dbus-devel + set -- openssl webkit2gtk4.1-devel openssl-devel curl wget file libappindicator-gtk3-devel librsvg2-devel libxdo-devel dbus-devel # Webkit2gtk requires gstreamer plugins for video playback to work set -- "$@" gstreamer1-devel gstreamer1-plugins-base-devel gstreamer1-plugins-good \