From bc19503419724dcd65d3095942216318361e4371 Mon Sep 17 00:00:00 2001 From: infiinte-persistence Date: Fri, 10 Jul 2020 14:26:05 +0800 Subject: [PATCH] Allow zooming on Desktop ## Issue Closes 4501 `Font size` ## New behavior The Desktop app can now zoom the same way as browsers: - Zoom In: "Ctrl+=" or "Ctrl+numpadPlus" or "Ctrl+WheelUp" - Zoom Out: "Ctrl+-" or "Ctrl+numpadMinus" or "Ctrl+WheelDown" - Zoom Reset: "Ctrl+0" or "Ctrl+numpad0" ## Code changes (1) Electron provides this functionality through the `zoomIn|zoomOut|resetZoom` roles in the Menu, so it would have been a quick job. However, given that Electron currently does not support having multiple accelerators for one item, we can't add `Ctrl+WheelUp` to the mix and would have to implement our own handler and use `webFrame`. Given that we need to add code anyways, we handle both keyboard and mouse cases through the same handler, hence the existence of `zoomWindow.js`. It also provides the opportunity to few a few quirks with Electron's default implementation (e.g. stuck at both extremes) (2) I recall there is another Issue for adding keyboard shortcuts. Given that these shortcuts are universally used in browsers, they are probably "reserved", so shouldn't clash with that task. --- CHANGELOG.md | 1 + electron/menu/setupBarMenu.js | 33 +++++++++++++++++++++++ ui/component/app/view.jsx | 49 +++++++++++++++++++++++++++++++++++ ui/index.jsx | 5 ++++ ui/util/zoomWindow.js | 42 ++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 ui/util/zoomWindow.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e1026b5f2..1b033f672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - New channel create/edit page ([#4445](https://github.com/lbryio/lbry-desktop/pull/4445)) - Add dialog to copy various types of links for a claim _community pr!_ ([#4474](https://github.com/lbryio/lbry-desktop/pull/4474)) - Add password reset link to settings page for logged in users _community pr!_ ([#4473](https://github.com/lbryio/lbry-desktop/pull/4473)) +- Allow zooming on Desktop _community pr!_ ([#4513](https://github.com/lbryio/lbry-desktop/pull/4513)) ### Changed diff --git a/electron/menu/setupBarMenu.js b/electron/menu/setupBarMenu.js index 794430a0c..26f9bd602 100644 --- a/electron/menu/setupBarMenu.js +++ b/electron/menu/setupBarMenu.js @@ -1,4 +1,5 @@ import { app, Menu, shell } from 'electron'; +import { changeZoomFactor, ZOOM } from 'util/zoomWindow'; export default () => { const template = [ @@ -22,6 +23,38 @@ export default () => { label: 'View', submenu: [ { role: 'reload' }, + { + label: 'Zoom', + submenu: [ + { + label: 'Zoom In', + accelerator: 'CmdOrCtrl+=', + click: (menuItem, browserWindow) => { + if (browserWindow) { + browserWindow.webContents.send('zoom-window', ZOOM.INCREMENT); + } + }, + }, + { + label: 'Zoom Out', + accelerator: 'CmdOrCtrl+-', + click: (menuItem, browserWindow) => { + if (browserWindow) { + browserWindow.webContents.send('zoom-window', ZOOM.DECREMENT); + } + }, + }, + { + label: 'Reset Zoom', + accelerator: 'CmdOrCtrl+0', + click: (menuItem, browserWindow) => { + if (browserWindow) { + browserWindow.webContents.send('zoom-window', ZOOM.RESET); + } + }, + }, + ], + }, { label: 'Developer', submenu: [{ role: 'forcereload' }, { role: 'toggledevtools' }], diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index f61bded1e..1241f334c 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -17,6 +17,9 @@ import Nag from 'component/common/nag'; import REWARDS from 'rewards'; import usePersistedState from 'effects/use-persisted-state'; import FileDrop from 'component/fileDrop'; +// @if TARGET='app' +import { changeZoomFactor, ZOOM } from 'util/zoomWindow'; +// @endif // @if TARGET='web' import OpenInAppLink from 'web/component/openInAppLink'; import YoutubeWelcome from 'web/component/youtubeReferralWelcome'; @@ -172,6 +175,52 @@ function App(props: Props) { return () => window.removeEventListener('keydown', handleKeyPress); }, []); + // Enable ctrl +/- zooming on Desktop. + // @if TARGET='app' + useEffect(() => { + const handleKeyPress = e => { + if (e.ctrlKey && !e.shiftKey) { + switch (e.code) { + case 'NumpadAdd': + case 'Equal': + e.preventDefault(); + changeZoomFactor(ZOOM.INCREMENT); + break; + case 'NumpadSubtract': + case 'Minus': + e.preventDefault(); + changeZoomFactor(ZOOM.DECREMENT); + break; + case 'Numpad0': + case 'Digit0': + e.preventDefault(); + changeZoomFactor(ZOOM.RESET); + break; + default: + // Do nothing + break; + } + } + }; + window.addEventListener('keydown', handleKeyPress); + return () => window.removeEventListener('keydown', handleKeyPress); + }, []); + + useEffect(() => { + const handleWheel = e => { + if (e.ctrlKey && !e.shiftKey) { + if (e.deltaY < 0) { + changeZoomFactor(ZOOM.INCREMENT); + } else { + changeZoomFactor(ZOOM.DECREMENT); + } + } + }; + window.addEventListener('wheel', handleWheel); + return () => window.removeEventListener('wheel', handleWheel); + }, []); + // @endif + useEffect(() => { if (referredRewardAvailable && sanitizedReferrerParam && isRewardApproved) { setReferrer(sanitizedReferrerParam, true); diff --git a/ui/index.jsx b/ui/index.jsx index 68b566aab..b4bb646af 100644 --- a/ui/index.jsx +++ b/ui/index.jsx @@ -6,6 +6,7 @@ import SnackBar from 'component/snackBar'; // @if TARGET='app' import SplashScreen from 'component/splash'; import * as ACTIONS from 'constants/action_types'; +import { changeZoomFactor } from 'util/zoomWindow'; // @endif import { ipcRenderer, remote, shell } from 'electron'; import moment from 'moment'; @@ -193,6 +194,10 @@ ipcRenderer.on('open-menu', (event, uri) => { } }); +ipcRenderer.on('zoom-window', (event, action) => { + changeZoomFactor(action); +}); + const { dock } = remote.app; ipcRenderer.on('window-is-focused', () => { diff --git a/ui/util/zoomWindow.js b/ui/util/zoomWindow.js new file mode 100644 index 000000000..84f843e33 --- /dev/null +++ b/ui/util/zoomWindow.js @@ -0,0 +1,42 @@ +import { webFrame } from 'electron'; +const isDev = process.env.NODE_ENV !== 'production'; + +export const ZOOM = { + INCREMENT: 'INCREMENT', + DECREMENT: 'DECREMENT', + RESET: 'RESET', +}; + +function getNextZoomFactor(curFactor, isIncreasing) { + const zoomTable = [0.25, 0.33, 0.5, 0.67, 0.75, 0.8, 0.9, 1.0, 1.1, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0]; + + curFactor = curFactor.toPrecision(3); + let i = zoomTable.length; + while (curFactor < zoomTable[--i]) {} + + if (isIncreasing) { + return zoomTable[Math.min(zoomTable.length - 1, i + 1)]; + } else { + return zoomTable[Math.max(0, i - 1)]; + } +} + +export function changeZoomFactor(action) { + const ZOOM_DFLT_FACTOR = 1.0; + const curFactor = webFrame.getZoomFactor(); + + switch (action) { + case ZOOM.INCREMENT: + webFrame.setZoomFactor(getNextZoomFactor(curFactor, true)); + break; + case ZOOM.DECREMENT: + webFrame.setZoomFactor(getNextZoomFactor(curFactor, false)); + break; + case ZOOM.RESET: + webFrame.setZoomFactor(ZOOM_DFLT_FACTOR); + break; + default: + if (isDev) throw new Error('changeZoomFactor: unexpected action'); + break; + } +}