summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2022-01-07 12:14:47 +0100
committerOskar Nyberg <oskar@mullvad.net>2022-01-19 15:50:23 +0100
commite1a4584b75e7a8c66ab12fa30cc2f668f0840cc0 (patch)
treecc9723aaabd902b46a4929f3a5943a8d58cd0c3c /gui/src
parent46677bbcce1f4954072ea5c54f61685d6a7b278a (diff)
downloadmullvadvpn-e1a4584b75e7a8c66ab12fa30cc2f668f0840cc0.tar.xz
mullvadvpn-e1a4584b75e7a8c66ab12fa30cc2f668f0840cc0.zip
Refactor tray related code
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/main/index.ts80
-rw-r--r--gui/src/main/tray-icon-controller.ts69
-rw-r--r--gui/src/shared/connect-helper.ts2
3 files changed, 96 insertions, 55 deletions
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')
);
}