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.
This commit is contained in:
infiinte-persistence 2020-07-10 14:26:05 +08:00 committed by Sean Yesmunt
parent 2754c962a4
commit bc19503419
5 changed files with 130 additions and 0 deletions

View file

@ -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

View file

@ -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' }],

View file

@ -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);

View file

@ -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', () => {

42
ui/util/zoomWindow.js Normal file
View file

@ -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;
}
}