diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-01-19 15:51:34 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-01-19 15:51:34 +0100 |
| commit | 4e64c21bf32fe0afedf5669c528d6c29823c1aae (patch) | |
| tree | 5470e7a722e8b615314a88eb5b9e90f2aedd8258 | |
| parent | 46677bbcce1f4954072ea5c54f61685d6a7b278a (diff) | |
| parent | 35b34264e87cf56f12f12fbf0bcdf3a37403396c (diff) | |
| download | mullvadvpn-4e64c21bf32fe0afedf5669c528d6c29823c1aae.tar.xz mullvadvpn-4e64c21bf32fe0afedf5669c528d6c29823c1aae.zip | |
Merge branch 'tray-context-menu-improvements'
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 80 | ||||
| -rw-r--r-- | gui/src/main/tray-icon-controller.ts | 69 | ||||
| -rw-r--r-- | gui/src/shared/connect-helper.ts | 2 |
4 files changed, 98 insertions, 55 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 089dc28808..661d111b53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,8 @@ Line wrap the file at 100 chars. Th environment variable `http_proxy` is set. This caused the app to fail to connect to the daemon. - Disable built-in DNS resolver in Electron. Prevents Electron from establishing connections to DNS servers set in system network preferences. +- Fix tray context menu showing or executing wrong actions, using wrong language or in other + ways not update properly. #### macOS - Resolve issues with the app blocking internet connectivity after sleep or when connecting to new diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index b5743b7c76..a3cd2dd5f8 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -14,7 +14,6 @@ import { Tray, } from 'electron'; import * as path from 'path'; -import { sprintf } from 'sprintf-js'; import util from 'util'; import config from '../config.json'; import { closeToExpiry, hasExpired } from '../shared/account-expiry'; @@ -513,11 +512,17 @@ class ApplicationMain { this.tunnelStateExpectation = new Expectation(async () => { this.trayIconController = new TrayIconController( tray, + windowController, this.trayIconType(this.tunnelState, this.settings.blockWhenDisconnected), this.guiSettings.monochromaticIcon, + () => setImmediate(() => void this.connectTunnel()), + () => setImmediate(() => void this.reconnectTunnel()), + () => setImmediate(() => void this.disconnectTunnel()), ); await this.trayIconController.updateTheme(); + this.setTrayContextMenu(); + if (process.platform === 'win32') { nativeTheme.on('updated', async () => { if (this.guiSettings.monochromaticIcon) { @@ -574,7 +579,7 @@ class ApplicationMain { this.setMacOsAppMenu(); break; case 'linux': - this.tray.setContextMenu(this.createTrayContextMenu()); + this.setTrayContextMenu(); this.setLinuxAppMenu(); this.windowController.window.setMenuBarVisibility(false); break; @@ -716,6 +721,7 @@ class ApplicationMain { // update the tray icon to indicate that the computer is not secure anymore this.updateTrayIcon({ state: 'disconnected' }, false); + this.setTrayContextMenu(); // notify renderer process if (this.windowController) { @@ -886,9 +892,7 @@ class ApplicationMain { this.tunnelState = newState; this.updateTrayIcon(newState, this.settings.blockWhenDisconnected); - if (process.platform === 'linux') { - this.tray?.setContextMenu(this.createTrayContextMenu()); - } + this.setTrayContextMenu(); this.notificationController.notifyTunnelState( newState, @@ -1563,6 +1567,8 @@ class ApplicationMain { } else if (oldAccount && newAccount && oldAccount !== newAccount) { this.accountDataCache.fetch(newAccount); } + + this.setTrayContextMenu(); } private updateAccountData() { @@ -1685,6 +1691,8 @@ class ApplicationMain { messages: messagesTranslations, relayLocations: relayLocationsTranslations, }; + + this.setTrayContextMenu(); } private blockPermissionRequests() { @@ -1882,54 +1890,6 @@ class ApplicationMain { Menu.setApplicationMenu(Menu.buildFromTemplate(template)); } - private createTrayContextMenu() { - const template: Electron.MenuItemConstructorOptions[] = [ - { - label: sprintf(messages.pgettext('tray-icon-context-menu', 'Open %(mullvadVpn)s'), { - mullvadVpn: 'Mullvad VPN', - }), - click: () => this.windowController?.show(), - }, - { type: 'separator' }, - { - label: this.getContextMenuActionButtonLabel(), - click: () => { - if (this.tunnelState.state === 'disconnected') { - // Workaround: gRPC calls are sometimes delayed by a few seconds and setImmediate - // mitigates this. https://github.com/grpc/grpc-node/issues/882 - setImmediate(() => void this.daemonRpc.connectTunnel()); - } else { - setImmediate(() => void this.daemonRpc.disconnectTunnel()); - } - }, - }, - { - label: messages.gettext('Reconnect'), - enabled: this.tunnelState.state === 'connected' || this.tunnelState.state === 'connecting', - click: () => setImmediate(() => void this.daemonRpc.reconnectTunnel()), - }, - ]; - - return Menu.buildFromTemplate(template); - } - - private getContextMenuActionButtonLabel() { - switch (this.tunnelState.state) { - case 'disconnected': - return messages.gettext('Connect'); - case 'connecting': - return messages.gettext('Cancel'); - case 'connected': - return messages.gettext('Disconnect'); - case 'disconnecting': - return ''; - case 'error': - return this.tunnelState.details.blockFailure - ? messages.gettext('Dismiss') - : messages.gettext('Cancel'); - } - } - private addContextMenu(windowController: WindowController) { const menuTemplate: Electron.MenuItemConstructorOptions[] = [ { role: 'cut' }, @@ -1991,7 +1951,11 @@ class ApplicationMain { // This needs to be executed on click since if it is added to the tray icon it will be // displayed on left click as well. this.tray?.on('right-click', () => - this.tray?.popUpContextMenu(this.createTrayContextMenu()), + this.trayIconController?.popUpContextMenu( + this.connectedToDaemon, + this.settings.accountToken, + this.tunnelState, + ), ); this.tray?.on('click', () => this.windowController?.show()); } else { @@ -2024,6 +1988,14 @@ class ApplicationMain { } } + private setTrayContextMenu() { + this.trayIconController?.setContextMenu( + this.connectedToDaemon, + this.settings.accountToken, + this.tunnelState, + ); + } + private installWindowsMenubarAppWindowHandlers(tray: Tray, windowController: WindowController) { if (!this.guiSettings.unpinnedWindow) { windowController.window?.on('blur', () => { diff --git a/gui/src/main/tray-icon-controller.ts b/gui/src/main/tray-icon-controller.ts index a16c2ad9fc..9890eba8ff 100644 --- a/gui/src/main/tray-icon-controller.ts +++ b/gui/src/main/tray-icon-controller.ts @@ -1,9 +1,14 @@ import { exec as execAsync } from 'child_process'; -import { nativeImage, NativeImage, Tray } from 'electron'; +import { Menu, nativeImage, NativeImage, Tray } from 'electron'; import path from 'path'; +import { sprintf } from 'sprintf-js'; import { promisify } from 'util'; +import { connectEnabled, disconnectEnabled, reconnectEnabled } from '../shared/connect-helper'; +import { AccountToken, TunnelState } from '../shared/daemon-rpc-types'; +import { messages } from '../shared/gettext'; import log from '../shared/logging'; import KeyframeAnimation from './keyframe-animation'; +import WindowController from './window-controller'; const exec = promisify(execAsync); @@ -23,8 +28,12 @@ export default class TrayIconController { constructor( private tray: Tray, + private windowController: WindowController, private iconTypeValue: TrayIconType, private useMonochromaticIconValue: boolean, + private connect: () => void, + private reconnect: () => void, + private disconnect: () => void, ) { this.loadImages(); } @@ -88,6 +97,28 @@ export default class TrayIconController { animation.play({ end: frame }); } + public setContextMenu( + connectedToDaemon: boolean, + accountToken: AccountToken | undefined, + tunnelState: TunnelState, + ) { + if (process.platform === 'linux') { + this.tray.setContextMenu( + this.createContextMenu(connectedToDaemon, accountToken, tunnelState), + ); + } + } + + public popUpContextMenu( + connectedToDaemon: boolean, + accountToken: AccountToken | undefined, + tunnelState: TunnelState, + ) { + this.tray.popUpContextMenu( + this.createContextMenu(connectedToDaemon, accountToken, tunnelState), + ); + } + private initAnimation() { const initialFrame = this.targetFrame(); const animation = new KeyframeAnimation(); @@ -178,4 +209,40 @@ export default class TrayIconController { return 8; } } + + private createContextMenu( + connectedToDaemon: boolean, + accountToken: AccountToken | undefined, + tunnelState: TunnelState, + ) { + const template: Electron.MenuItemConstructorOptions[] = [ + { + label: sprintf(messages.pgettext('tray-icon-context-menu', 'Open %(mullvadVpn)s'), { + mullvadVpn: 'Mullvad VPN', + }), + click: () => this.windowController.show(), + }, + { type: 'separator' }, + { + id: 'connect', + label: messages.gettext('Connect'), + enabled: connectEnabled(connectedToDaemon, accountToken, tunnelState.state), + click: this.connect, + }, + { + id: 'reconnect', + label: messages.gettext('Reconnect'), + enabled: reconnectEnabled(connectedToDaemon, accountToken, tunnelState.state), + click: this.reconnect, + }, + { + id: 'disconnect', + label: messages.gettext('Disconnect'), + enabled: disconnectEnabled(connectedToDaemon, tunnelState.state), + click: this.disconnect, + }, + ]; + + return Menu.buildFromTemplate(template); + } } diff --git a/gui/src/shared/connect-helper.ts b/gui/src/shared/connect-helper.ts index 214d22a59a..b1421cd8ef 100644 --- a/gui/src/shared/connect-helper.ts +++ b/gui/src/shared/connect-helper.ts @@ -8,6 +8,7 @@ export function connectEnabled( return ( connectedToDaemon && accountToken !== undefined && + accountToken !== '' && (tunnelState === 'disconnected' || tunnelState === 'disconnecting' || tunnelState === 'error') ); } @@ -20,6 +21,7 @@ export function reconnectEnabled( return ( connectedToDaemon && accountToken !== undefined && + accountToken !== '' && (tunnelState === 'connected' || tunnelState === 'connecting') ); } |
