Add ZoomFactorService to keep windows in sync

This commit is contained in:
Jamie Kyle 2023-12-22 12:27:49 -08:00 committed by GitHub
parent 5354b23d08
commit 95842c6e0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 223 additions and 101 deletions

View file

@ -117,6 +117,7 @@ import { HourCyclePreference } from '../ts/types/I18N';
import { DBVersionFromFutureError } from '../ts/sql/migrations'; import { DBVersionFromFutureError } from '../ts/sql/migrations';
import type { ParsedSignalRoute } from '../ts/util/signalRoutes'; import type { ParsedSignalRoute } from '../ts/util/signalRoutes';
import { parseSignalRoute } from '../ts/util/signalRoutes'; import { parseSignalRoute } from '../ts/util/signalRoutes';
import { ZoomFactorService } from '../ts/services/ZoomFactorService';
const STICKER_CREATOR_PARTITION = 'sticker-creator'; const STICKER_CREATOR_PARTITION = 'sticker-creator';
@ -200,6 +201,7 @@ const defaultWebPrefs = {
'CSSPseudoDir', // status=experimental, needed for RTL (ex: :dir(rtl)) 'CSSPseudoDir', // status=experimental, needed for RTL (ex: :dir(rtl))
'CSSLogical', // status=experimental, needed for RTL (ex: margin-inline-start) 'CSSLogical', // status=experimental, needed for RTL (ex: margin-inline-start)
].join(','), ].join(','),
enablePreferredSizeMode: true,
}; };
const DISABLE_GPU = const DISABLE_GPU =
@ -394,6 +396,22 @@ async function getLocaleOverrideSetting(): Promise<string | null> {
return slowValue; return slowValue;
} }
const zoomFactorService = new ZoomFactorService({
async getZoomFactorSetting() {
const item = await sql.sqlCall('getItemById', 'zoomFactor');
if (typeof item?.value !== 'number') {
return null;
}
return item.value;
},
async setZoomFactorSetting(zoomFactor) {
await sql.sqlCall('createOrUpdateItem', {
id: 'zoomFactor',
value: zoomFactor,
});
},
});
let systemTrayService: SystemTrayService | undefined; let systemTrayService: SystemTrayService | undefined;
const systemTraySettingCache = new SystemTraySettingCache( const systemTraySettingCache = new SystemTraySettingCache(
sql, sql,
@ -523,7 +541,7 @@ async function handleUrl(rawTarget: string) {
} }
} }
function handleCommonWindowEvents( async function handleCommonWindowEvents(
window: BrowserWindow, window: BrowserWindow,
titleBarOverlay: TitleBarOverlayOptions | false = false titleBarOverlay: TitleBarOverlayOptions | false = false
) { ) {
@ -557,54 +575,7 @@ function handleCommonWindowEvents(
const focusInterval = setInterval(setWindowFocus, 10000); const focusInterval = setInterval(setWindowFocus, 10000);
window.on('closed', () => clearInterval(focusInterval)); window.on('closed', () => clearInterval(focusInterval));
// Works only for mainWindow and settings because they have `enablePreferredSizeMode` await zoomFactorService.syncWindow(window);
let lastZoomFactor = window.webContents.getZoomFactor();
const onZoomChanged = () => {
if (
window.isDestroyed() ||
!window.webContents ||
window.webContents.isDestroyed()
) {
return;
}
const zoomFactor = window.webContents.getZoomFactor();
if (lastZoomFactor === zoomFactor) {
return;
}
lastZoomFactor = zoomFactor;
if (!mainWindow) {
return;
}
if (window === mainWindow) {
drop(
settingsChannel?.invokeCallbackInMainWindow('persistZoomFactor', [
zoomFactor,
])
);
} else {
mainWindow.webContents.setZoomFactor(zoomFactor);
}
};
window.on('show', () => {
// Install handler here after we init zoomFactor otherwise an initial
// preferred-size-changed event emits with an undesired zoomFactor.
window.webContents.on('preferred-size-changed', onZoomChanged);
});
// Workaround to apply zoomFactor because webPreferences does not handle it
// https://github.com/electron/electron/issues/10572
// But main window emits ready-to-show before window.Events is available
// so set main window zoom in background.ts
if (window !== mainWindow) {
window.once('ready-to-show', async () => {
const zoomFactor =
(await settingsChannel?.getSettingFromMainWindow('zoomFactor')) ?? 1;
window.webContents.setZoomFactor(zoomFactor);
});
}
nativeThemeNotifier.addWindow(window); nativeThemeNotifier.addWindow(window);
@ -788,7 +759,6 @@ async function createWindow() {
), ),
spellcheck: await getSpellCheckSetting(), spellcheck: await getSpellCheckSetting(),
backgroundThrottling: true, backgroundThrottling: true,
enablePreferredSizeMode: true,
disableBlinkFeatures: 'Accelerated2dCanvas,AcceleratedSmallCanvases', disableBlinkFeatures: 'Accelerated2dCanvas,AcceleratedSmallCanvases',
}, },
icon: windowIcon, icon: windowIcon,
@ -917,7 +887,7 @@ async function createWindow() {
mainWindow.webContents.openDevTools(); mainWindow.webContents.openDevTools();
} }
handleCommonWindowEvents(mainWindow, titleBarOverlay); await handleCommonWindowEvents(mainWindow, titleBarOverlay);
// App dock icon bounce // App dock icon bounce
bounce.init(mainWindow); bounce.init(mainWindow);
@ -1293,7 +1263,7 @@ async function showScreenShareWindow(sourceName: string) {
screenShareWindow = new BrowserWindow(options); screenShareWindow = new BrowserWindow(options);
handleCommonWindowEvents(screenShareWindow); await handleCommonWindowEvents(screenShareWindow);
screenShareWindow.on('closed', () => { screenShareWindow.on('closed', () => {
screenShareWindow = undefined; screenShareWindow = undefined;
@ -1343,7 +1313,7 @@ async function showAbout() {
aboutWindow = new BrowserWindow(options); aboutWindow = new BrowserWindow(options);
handleCommonWindowEvents(aboutWindow, titleBarOverlay); await handleCommonWindowEvents(aboutWindow, titleBarOverlay);
aboutWindow.on('closed', () => { aboutWindow.on('closed', () => {
aboutWindow = undefined; aboutWindow = undefined;
@ -1389,13 +1359,12 @@ async function showSettingsWindow() {
contextIsolation: true, contextIsolation: true,
preload: join(__dirname, '../bundles/settings/preload.js'), preload: join(__dirname, '../bundles/settings/preload.js'),
nativeWindowOpen: true, nativeWindowOpen: true,
enablePreferredSizeMode: true,
}, },
}; };
settingsWindow = new BrowserWindow(options); settingsWindow = new BrowserWindow(options);
handleCommonWindowEvents(settingsWindow, titleBarOverlay); await handleCommonWindowEvents(settingsWindow, titleBarOverlay);
settingsWindow.on('closed', () => { settingsWindow.on('closed', () => {
settingsWindow = undefined; settingsWindow = undefined;
@ -1490,7 +1459,7 @@ async function showDebugLogWindow() {
debugLogWindow = new BrowserWindow(options); debugLogWindow = new BrowserWindow(options);
handleCommonWindowEvents(debugLogWindow, titleBarOverlay); await handleCommonWindowEvents(debugLogWindow, titleBarOverlay);
debugLogWindow.on('closed', () => { debugLogWindow.on('closed', () => {
debugLogWindow = undefined; debugLogWindow = undefined;
@ -1550,7 +1519,7 @@ function showPermissionsPopupWindow(forCalling: boolean, forCamera: boolean) {
permissionsPopupWindow = new BrowserWindow(options); permissionsPopupWindow = new BrowserWindow(options);
handleCommonWindowEvents(permissionsPopupWindow); await handleCommonWindowEvents(permissionsPopupWindow);
permissionsPopupWindow.on('closed', () => { permissionsPopupWindow.on('closed', () => {
removeDarkOverlay(); removeDarkOverlay();
@ -2122,6 +2091,9 @@ function setupMenu(options?: Partial<CreateTemplateOptionsType>) {
showKeyboardShortcuts, showKeyboardShortcuts,
showSettings: showSettingsWindow, showSettings: showSettingsWindow,
showWindow, showWindow,
zoomIn,
zoomOut,
zoomReset,
// overrides // overrides
...options, ...options,
@ -2815,16 +2787,6 @@ ipc.handle('executeMenuRole', async ({ sender }, untypedRole) => {
sender.toggleDevTools(); sender.toggleDevTools();
break; break;
case 'resetZoom':
sender.setZoomLevel(0);
break;
case 'zoomIn':
sender.setZoomLevel(sender.getZoomLevel() + 1);
break;
case 'zoomOut':
sender.setZoomLevel(sender.getZoomLevel() - 1);
break;
case 'togglefullscreen': case 'togglefullscreen':
senderWindow?.setFullScreen(!senderWindow?.isFullScreen()); senderWindow?.setFullScreen(!senderWindow?.isFullScreen());
break; break;
@ -2862,6 +2824,18 @@ ipc.handle('getMenuOptions', async () => {
}; };
}); });
async function zoomIn() {
await zoomFactorService.zoomIn();
}
async function zoomOut() {
await zoomFactorService.zoomOut();
}
async function zoomReset() {
await zoomFactorService.zoomReset();
}
ipc.handle('executeMenuAction', async (_event, action: MenuActionType) => { ipc.handle('executeMenuAction', async (_event, action: MenuActionType) => {
if (action === 'forceUpdate') { if (action === 'forceUpdate') {
drop(forceUpdate()); drop(forceUpdate());
@ -2891,6 +2865,12 @@ ipc.handle('executeMenuAction', async (_event, action: MenuActionType) => {
drop(showSettingsWindow()); drop(showSettingsWindow());
} else if (action === 'showWindow') { } else if (action === 'showWindow') {
showWindow(); showWindow();
} else if (action === 'zoomIn') {
drop(zoomIn());
} else if (action === 'zoomOut') {
drop(zoomOut());
} else if (action === 'zoomReset') {
drop(zoomReset());
} else { } else {
throw missingCaseError(action); throw missingCaseError(action);
} }
@ -2940,7 +2920,7 @@ async function showStickerCreatorWindow() {
stickerCreatorWindow = new BrowserWindow(options); stickerCreatorWindow = new BrowserWindow(options);
handleCommonWindowEvents(stickerCreatorWindow); await handleCommonWindowEvents(stickerCreatorWindow);
stickerCreatorWindow.once('ready-to-show', () => { stickerCreatorWindow.once('ready-to-show', () => {
stickerCreatorWindow?.show(); stickerCreatorWindow?.show();

View file

@ -38,6 +38,9 @@ export const createTemplate = (
showKeyboardShortcuts, showKeyboardShortcuts,
showSettings, showSettings,
openArtCreator, openArtCreator,
zoomIn,
zoomOut,
zoomReset,
} = options; } = options;
const template: MenuListType = [ const template: MenuListType = [
@ -106,17 +109,19 @@ export const createTemplate = (
label: i18n('icu:mainMenuView'), label: i18n('icu:mainMenuView'),
submenu: [ submenu: [
{ {
role: 'resetZoom', accelerator: 'CmdOrCtrl+0',
label: i18n('icu:viewMenuResetZoom'), label: i18n('icu:viewMenuResetZoom'),
click: zoomReset,
}, },
{ {
accelerator: 'CmdOrCtrl+=', accelerator: 'CmdOrCtrl+=',
role: 'zoomIn',
label: i18n('icu:viewMenuZoomIn'), label: i18n('icu:viewMenuZoomIn'),
click: zoomIn,
}, },
{ {
role: 'zoomOut', accelerator: 'CmdOrCtrl+-',
label: i18n('icu:viewMenuZoomOut'), label: i18n('icu:viewMenuZoomOut'),
click: zoomOut,
}, },
{ {
type: 'separator', type: 'separator',

View file

@ -1,7 +1,6 @@
// Copyright 2020 Signal Messenger, LLC // Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { webFrame } from 'electron';
import { isNumber, throttle, groupBy } from 'lodash'; import { isNumber, throttle, groupBy } from 'lodash';
import { render } from 'react-dom'; import { render } from 'react-dom';
import { batch as batchDispatch } from 'react-redux'; import { batch as batchDispatch } from 'react-redux';
@ -819,14 +818,13 @@ export async function startApp(): Promise<void> {
}, },
}); });
const zoomFactor = window.Events.getZoomFactor(); const zoomFactor = await window.Events.getZoomFactor();
webFrame.setZoomFactor(zoomFactor);
document.body.style.setProperty('--zoom-factor', zoomFactor.toString()); document.body.style.setProperty('--zoom-factor', zoomFactor.toString());
window.addEventListener('resize', () => { window.Events.onZoomFactorChange(newZoomFactor => {
document.body.style.setProperty( document.body.style.setProperty(
'--zoom-factor', '--zoom-factor',
webFrame.getZoomFactor().toString() newZoomFactor.toString()
); );
}); });

View file

@ -238,6 +238,9 @@ export function TitleBarContainer(props: PropsType): JSX.Element {
showKeyboardShortcuts: () => executeMenuAction('showKeyboardShortcuts'), showKeyboardShortcuts: () => executeMenuAction('showKeyboardShortcuts'),
showSettings: () => executeMenuAction('showSettings'), showSettings: () => executeMenuAction('showSettings'),
showWindow: () => executeMenuAction('showWindow'), showWindow: () => executeMenuAction('showWindow'),
zoomIn: () => executeMenuAction('zoomIn'),
zoomOut: () => executeMenuAction('zoomOut'),
zoomReset: () => executeMenuAction('zoomReset'),
}, },
i18n i18n
); );

View file

@ -0,0 +1,123 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { BrowserWindow } from 'electron';
import { ipcMain } from 'electron';
import EventEmitter from 'events';
const DEFAULT_ZOOM_FACTOR = 1.0;
// https://chromium.googlesource.com/chromium/src/+/938b37a6d2886bf8335fc7db792f1eb46c65b2ae/third_party/blink/common/page/page_zoom.cc
const ZOOM_LEVEL_MULTIPLIER_RATIO = 1.2;
function zoomLevelToZoomFactor(zoomLevel: number): number {
return ZOOM_LEVEL_MULTIPLIER_RATIO ** zoomLevel;
}
function zoomFactorToZoomLevel(zoomFactor: number) {
return Math.log(zoomFactor) / Math.log(ZOOM_LEVEL_MULTIPLIER_RATIO);
}
function zoomFactorEquals(a: number, b: number): boolean {
return Math.abs(a - b) <= 0.001;
}
type ZoomFactorServiceConfig = Readonly<{
getZoomFactorSetting: () => Promise<number | null>;
setZoomFactorSetting: (zoomFactor: number) => Promise<void>;
}>;
export class ZoomFactorService extends EventEmitter {
#config: ZoomFactorServiceConfig;
#cachedZoomFactor: number | null = null;
constructor(config: ZoomFactorServiceConfig) {
super();
this.#config = config;
ipcMain.handle('getZoomFactor', () => {
return this.getZoomFactor();
});
ipcMain.on('setZoomFactor', (_event, zoomFactor) => {
return this.setZoomFactor(zoomFactor);
});
}
async getZoomFactor(): Promise<number> {
if (this.#cachedZoomFactor != null) {
return this.#cachedZoomFactor;
}
const zoomFactorSetting = await this.#config.getZoomFactorSetting();
const zoomFactor = zoomFactorSetting ?? DEFAULT_ZOOM_FACTOR;
this.#cachedZoomFactor = zoomFactor;
return zoomFactor;
}
async getZoomLevel(): Promise<number> {
const zoomFactor = await this.getZoomFactor();
return zoomFactorToZoomLevel(zoomFactor);
}
async setZoomFactor(zoomFactor: number): Promise<void> {
if (
this.#cachedZoomFactor != null &&
zoomFactorEquals(this.#cachedZoomFactor, zoomFactor)
) {
return;
}
this.#cachedZoomFactor = zoomFactor;
await this.#config.setZoomFactorSetting(zoomFactor);
this.emit('zoomFactorChanged', zoomFactor);
}
async setZoomLevel(zoomLevel: number): Promise<void> {
const zoomFactor = zoomLevelToZoomFactor(zoomLevel);
await this.setZoomFactor(zoomFactor);
}
async zoomIn(): Promise<void> {
const zoomLevel = await this.getZoomLevel();
await this.setZoomLevel(zoomLevel + 1);
}
async zoomOut(): Promise<void> {
const zoomLevel = await this.getZoomLevel();
await this.setZoomLevel(zoomLevel - 1);
}
async zoomReset(): Promise<void> {
await this.setZoomLevel(0);
}
// Call this after creating a new window before you show it
async syncWindow(window: BrowserWindow): Promise<void> {
const onWindowChange = async () => {
const zoomFactor = window.webContents.getZoomFactor();
await this.setZoomFactor(zoomFactor);
};
const onServiceChange = (zoomFactor: number) => {
window.webContents.setZoomFactor(zoomFactor);
window.webContents.send('zoomFactorChanged', zoomFactor);
};
const initialZoomFactor = await this.getZoomFactor();
window.once('ready-to-show', () => {
// Workaround to apply zoomFactor because webPreferences does not handle it
// https://github.com/electron/electron/issues/10572
window.webContents.setZoomFactor(initialZoomFactor);
});
window.once('show', async () => {
// Install handler here after we init zoomFactor otherwise an initial
// preferred-size-changed event emits with an undesired zoomFactor.
window.webContents.on('preferred-size-changed', onWindowChange);
window.webContents.on('zoom-changed', onWindowChange);
this.on('zoomFactorChanged', onServiceChange);
});
window.on('close', () => {
window.webContents.off('preferred-size-changed', onWindowChange);
window.webContents.off('zoom-changed', onWindowChange);
this.off('zoomFactorChanged', onServiceChange);
});
}
}

View file

@ -25,6 +25,9 @@ const showDebugLog = stub();
const showKeyboardShortcuts = stub(); const showKeyboardShortcuts = stub();
const showSettings = stub(); const showSettings = stub();
const showWindow = stub(); const showWindow = stub();
const zoomIn = stub();
const zoomOut = stub();
const zoomReset = stub();
const getExpectedEditMenu = ( const getExpectedEditMenu = (
includeSpeech: boolean includeSpeech: boolean
@ -58,9 +61,9 @@ const getExpectedEditMenu = (
const getExpectedViewMenu = (): MenuItemConstructorOptions => ({ const getExpectedViewMenu = (): MenuItemConstructorOptions => ({
label: '&View', label: '&View',
submenu: [ submenu: [
{ label: 'Actual Size', role: 'resetZoom' }, { accelerator: 'CmdOrCtrl+0', label: 'Actual Size', click: zoomReset },
{ accelerator: 'CmdOrCtrl+=', label: 'Zoom In', role: 'zoomIn' }, { accelerator: 'CmdOrCtrl+=', label: 'Zoom In', click: zoomIn },
{ label: 'Zoom Out', role: 'zoomOut' }, { accelerator: 'CmdOrCtrl+-', label: 'Zoom Out', click: zoomOut },
{ type: 'separator' }, { type: 'separator' },
{ label: 'Toggle Full Screen', role: 'togglefullscreen' }, { label: 'Toggle Full Screen', role: 'togglefullscreen' },
{ type: 'separator' }, { type: 'separator' },
@ -227,6 +230,9 @@ describe('createTemplate', () => {
showKeyboardShortcuts, showKeyboardShortcuts,
showSettings, showSettings,
showWindow, showWindow,
zoomIn,
zoomOut,
zoomReset,
}; };
PLATFORMS.forEach(({ label, platform, expectedDefault }) => { PLATFORMS.forEach(({ label, platform, expectedDefault }) => {

View file

@ -28,6 +28,9 @@ export type MenuActionsType = Readonly<{
showKeyboardShortcuts: () => unknown; showKeyboardShortcuts: () => unknown;
showSettings: () => unknown; showSettings: () => unknown;
showWindow: () => unknown; showWindow: () => unknown;
zoomIn: () => unknown;
zoomOut: () => unknown;
zoomReset: () => unknown;
}>; }>;
export type MenuActionType = keyof MenuActionsType; export type MenuActionType = keyof MenuActionsType;

View file

@ -1,7 +1,7 @@
// Copyright 2020 Signal Messenger, LLC // Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { webFrame } from 'electron'; import { ipcRenderer } from 'electron';
import type { AudioDevice } from '@signalapp/ringrtc'; import type { AudioDevice } from '@signalapp/ringrtc';
import { noop } from 'lodash'; import { noop } from 'lodash';
@ -135,13 +135,16 @@ export type IPCEventsCallbacksType = {
customColor?: { id: string; value: CustomColorType } customColor?: { id: string; value: CustomColorType }
) => void; ) => void;
getDefaultConversationColor: () => DefaultConversationColorType; getDefaultConversationColor: () => DefaultConversationColorType;
persistZoomFactor: (factor: number) => Promise<void>;
}; };
type ValuesWithGetters = Omit< type ValuesWithGetters = Omit<
IPCEventsValuesType, IPCEventsValuesType,
// Async
| 'zoomFactor'
// Optional // Optional
'mediaPermissions' | 'mediaCameraPermissions' | 'autoLaunch' | 'mediaPermissions'
| 'mediaCameraPermissions'
| 'autoLaunch'
>; >;
type ValuesWithSetters = Omit< type ValuesWithSetters = Omit<
@ -167,6 +170,11 @@ export type IPCEventSetterType<Key extends keyof IPCEventsValuesType> =
export type IPCEventsGettersType = { export type IPCEventsGettersType = {
[Key in keyof ValuesWithGetters as IPCEventGetterType<Key>]: () => ValuesWithGetters[Key]; [Key in keyof ValuesWithGetters as IPCEventGetterType<Key>]: () => ValuesWithGetters[Key];
} & { } & {
// Async
getZoomFactor: () => Promise<ZoomFactorType>;
// Events
onZoomFactorChange: (callback: (zoomFactor: ZoomFactorType) => void) => void;
// Optional
getMediaPermissions?: () => Promise<boolean>; getMediaPermissions?: () => Promise<boolean>;
getMediaCameraPermissions?: () => Promise<boolean>; getMediaCameraPermissions?: () => Promise<boolean>;
getAutoLaunch?: () => Promise<boolean>; getAutoLaunch?: () => Promise<boolean>;
@ -212,9 +220,16 @@ export function createIPCEvents(
getDeviceName: () => window.textsecure.storage.user.getDeviceName(), getDeviceName: () => window.textsecure.storage.user.getDeviceName(),
getZoomFactor: () => window.storage.get('zoomFactor', 1), getZoomFactor: () => {
setZoomFactor: async (zoomFactor: ZoomFactorType) => { return ipcRenderer.invoke('getZoomFactor');
webFrame.setZoomFactor(zoomFactor); },
setZoomFactor: async zoomFactor => {
ipcRenderer.send('setZoomFactor', zoomFactor);
},
onZoomFactorChange: callback => {
ipcRenderer.on('zoomFactorChanged', (_event, zoomFactor) => {
callback(zoomFactor);
});
}, },
setPhoneNumberDiscoverabilitySetting, setPhoneNumberDiscoverabilitySetting,
@ -615,9 +630,6 @@ export function createIPCEvents(
getMediaPermissions: window.IPC.getMediaPermissions, getMediaPermissions: window.IPC.getMediaPermissions,
getMediaCameraPermissions: window.IPC.getMediaCameraPermissions, getMediaCameraPermissions: window.IPC.getMediaCameraPermissions,
persistZoomFactor: zoomFactor =>
window.storage.put('zoomFactor', zoomFactor),
...overrideEvents, ...overrideEvents,
}; };
} }

View file

@ -14,7 +14,6 @@ installCallback('resetAllChatColors');
installCallback('resetDefaultChatColor'); installCallback('resetDefaultChatColor');
installCallback('setGlobalDefaultConversationColor'); installCallback('setGlobalDefaultConversationColor');
installCallback('getDefaultConversationColor'); installCallback('getDefaultConversationColor');
installCallback('persistZoomFactor');
// Getters only. These are set by the primary device // Getters only. These are set by the primary device
installSetting('blockedCount', { installSetting('blockedCount', {

View file

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { contextBridge, ipcRenderer, webFrame } from 'electron'; import { contextBridge, ipcRenderer } from 'electron';
import { MinimalSignalContext } from '../minimalContext'; import { MinimalSignalContext } from '../minimalContext';
import type { PropsPreloadType } from '../../components/Preferences'; import type { PropsPreloadType } from '../../components/Preferences';
@ -423,16 +423,8 @@ async function renderPreferences() {
onWhoCanSeeMeChange: attachRenderCallback( onWhoCanSeeMeChange: attachRenderCallback(
settingPhoneNumberSharing.setValue settingPhoneNumberSharing.setValue
), ),
onZoomFactorChange: (zoomFactorValue: number) => {
// Zoom factor change doesn't require immediate rerender since it will: ipcRenderer.send('setZoomFactor', zoomFactorValue);
// 1. Update the zoom factor in the main window
// 2. Trigger `preferred-size-changed` in the main process
// 3. Finally result in `window.storage` update which will cause the
// rerender.
onZoomFactorChange: (value: number) => {
// Update Settings window zoom factor to match the selected value.
webFrame.setZoomFactor(value);
return settingZoomFactor.setValue(value);
}, },
hasCustomTitleBar: MinimalSignalContext.OS.hasCustomTitleBar(), hasCustomTitleBar: MinimalSignalContext.OS.hasCustomTitleBar(),
@ -442,7 +434,8 @@ async function renderPreferences() {
renderInBrowser(props); renderInBrowser(props);
} }
ipcRenderer.on('preferences-changed', () => renderPreferences()); ipcRenderer.on('preferences-changed', renderPreferences);
ipcRenderer.on('zoomFactorChanged', renderPreferences);
const Signal = { const Signal = {
SettingsWindowProps: { SettingsWindowProps: {