diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-08-01 17:32:52 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-08-08 08:12:47 -0300 |
| commit | b7fccae454943a113022fe4403ca9a6920ffec13 (patch) | |
| tree | 8bcc6709f88652f47bfc9434acc1f6d1291c2af6 | |
| parent | 2c4d95cea476a0f038b731e13088d547465971c3 (diff) | |
| download | mullvadvpn-b7fccae454943a113022fe4403ca9a6920ffec13.tar.xz mullvadvpn-b7fccae454943a113022fe4403ca9a6920ffec13.zip | |
Implement system notifications of connection state
| -rw-r--r-- | app/app.js | 20 | ||||
| -rw-r--r-- | app/notification-controller.js | 25 | ||||
| -rw-r--r-- | flow-libs/notification.js.flow | 51 |
3 files changed, 96 insertions, 0 deletions
diff --git a/app/app.js b/app/app.js index 501bfac780..3171d69b76 100644 --- a/app/app.js +++ b/app/app.js @@ -11,6 +11,7 @@ import makeRoutes from './routes'; import { log } from './lib/platform'; import ReconnectionBackoff from './lib/reconnection-backoff'; import { DaemonRpc } from './lib/daemon-rpc'; +import NotificationController from './notification-controller'; import { setShutdownHandler } from './shutdown-handler'; import { NoAccountError } from './errors'; @@ -30,6 +31,7 @@ import type { ConnectionState } from './redux/connection/reducers'; import type { TrayIconType } from './tray-icon-controller'; export default class AppRenderer { + _notificationController = new NotificationController(); _daemonRpc: DaemonRpcProtocol = new DaemonRpc(); _reconnectBackoff = new ReconnectionBackoff(); _credentials: ?RpcCredentials; @@ -523,6 +525,24 @@ export default class AppRenderer { } this._updateTrayIcon(connectionState); + this._showNotification(connectionState); + } + + _showNotification(connectionState: ConnectionState) { + switch (connectionState) { + case 'connecting': + this._notificationController.show('Connecting'); + break; + case 'connected': + this._notificationController.show('Secured'); + break; + case 'disconnected': + this._notificationController.show('Unsecured'); + break; + default: + log.error(`Unexpected ConnectionState: ${(connectionState: empty)}`); + return; + } } async _authenticate(sharedSecret: string) { diff --git a/app/notification-controller.js b/app/notification-controller.js new file mode 100644 index 0000000000..62d6381e72 --- /dev/null +++ b/app/notification-controller.js @@ -0,0 +1,25 @@ +// @flow +import { remote } from 'electron'; + +export default class NotificationController { + _activeNotification: ?Notification; + + show(message: string) { + const lastNotification = this._activeNotification; + const newNotification = new Notification(remote.app.getName(), { body: message, silent: true }); + + this._activeNotification = newNotification; + + newNotification.addEventListener('show', () => { + // If the notification is closed too soon, it might still get shown. If that happens, close() + // should be called again so that it is closed immediately. + if (this._activeNotification !== newNotification) { + newNotification.close(); + } + }); + + if (lastNotification) { + lastNotification.close(); + } + } +} diff --git a/flow-libs/notification.js.flow b/flow-libs/notification.js.flow new file mode 100644 index 0000000000..bf5dda3af2 --- /dev/null +++ b/flow-libs/notification.js.flow @@ -0,0 +1,51 @@ +/* Notification */ +type NotificationPermission = 'default' | 'denied' | 'granted'; +type NotificationDirection = 'auto' | 'ltr' | 'rtl'; +type VibratePattern = number | Array<number>; +type NotificationAction = { action: string, title: string, icon?: string }; +type NotificationOptions = { + dir: NotificationDirection, + lang: string, + body: string, + tag: string, + image: string, + icon: string, + badge: string, + sound: string, + vibrate: VibratePattern, + timestamp: number, + renotify: boolean, + silent: boolean, + requireInteraction: boolean, + data: ?any, + actions: Array<NotificationAction>, +}; + +declare class Notification extends EventTarget { + constructor(title: string, options?: $Shape<NotificationOptions>): void; + static permission: NotificationPermission; + static requestPermission( + callback?: (perm: NotificationPermission) => mixed, + ): Promise<NotificationPermission>; + static maxActions: number; + onclick: (evt: Event) => any; + onerror: (evt: Event) => any; + title: string; + dir: NotificationDirection; + lang: string; + body: string; + tag: string; + image: string; + icon: string; + badge: string; + sound: string; + vibrate: Array<number>; + timestamp: number; + renotify: boolean; + silent: boolean; + requireInteraction: boolean; + data: any; + actions: Array<NotificationAction>; + + close(): void; +} |
