summaryrefslogtreecommitdiffhomepage
path: root/gui/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src/main')
-rw-r--r--gui/src/main/index.ts32
-rw-r--r--gui/src/main/notification-controller.ts18
2 files changed, 50 insertions, 0 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index 4df3b4c7a2..32620c3574 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -2,8 +2,10 @@ import { execFile } from 'child_process';
import { app, BrowserWindow, ipcMain, Menu, nativeImage, screen, Tray } from 'electron';
import log from 'electron-log';
import mkdirp from 'mkdirp';
+import moment from 'moment';
import * as path from 'path';
import * as uuid from 'uuid';
+import AccountExpiry from '../shared/account-expiry';
import BridgeSettingsBuilder from '../shared/bridge-settings-builder';
import {
AccountToken,
@@ -145,6 +147,8 @@ class ApplicationMain {
private wireguardPublicKey?: IWireguardPublicKey;
+ private accountExpiryNotificationTimeout?: NodeJS.Timeout;
+
private accountDataCache = new AccountDataCache(
(accountToken) => {
return this.daemonRpc.getAccountData(accountToken);
@@ -155,6 +159,8 @@ class ApplicationMain {
if (this.windowController) {
IpcMainEventChannel.account.notify(this.windowController.webContents, accountData);
}
+
+ this.notifyOfAccountExpiry();
},
);
@@ -1081,6 +1087,11 @@ class ApplicationMain {
private async logout(): Promise<void> {
try {
await this.daemonRpc.setAccount();
+
+ if (this.accountExpiryNotificationTimeout) {
+ global.clearTimeout(this.accountExpiryNotificationTimeout);
+ this.accountExpiryNotificationTimeout = undefined;
+ }
} catch (error) {
log.info(`Failed to logout: ${error.message}`);
@@ -1132,6 +1143,27 @@ class ApplicationMain {
}
}
+ private notifyOfAccountExpiry() {
+ if (this.accountData) {
+ const accountExpiry = new AccountExpiry(this.accountData.expiry, this.locale);
+ if (
+ accountExpiry &&
+ !this.accountExpiryNotificationTimeout &&
+ accountExpiry.willHaveExpiredAt(
+ moment()
+ .add(3, 'days')
+ .toDate(),
+ )
+ ) {
+ this.notificationController.closeToExpiryNotification(accountExpiry);
+ this.accountExpiryNotificationTimeout = global.setTimeout(() => {
+ this.accountExpiryNotificationTimeout = undefined;
+ this.notifyOfAccountExpiry();
+ }, 12 * 60 * 60 * 1000); // Every 12 hours
+ }
+ }
+ }
+
private async updateAccountHistory(): Promise<void> {
try {
this.setAccountHistory(await this.daemonRpc.getAccountHistory());
diff --git a/gui/src/main/notification-controller.ts b/gui/src/main/notification-controller.ts
index 98852029f3..69c0f9ec30 100644
--- a/gui/src/main/notification-controller.ts
+++ b/gui/src/main/notification-controller.ts
@@ -3,6 +3,7 @@ import os from 'os';
import path from 'path';
import { sprintf } from 'sprintf-js';
import config from '../config.json';
+import AccountExpiry from '../shared/account-expiry';
import { TunnelState } from '../shared/daemon-rpc-types';
import { messages } from '../shared/gettext';
@@ -156,6 +157,23 @@ export default class NotificationController {
this.scheduleNotification(notification);
}
+ public closeToExpiryNotification(accountExpiry: AccountExpiry) {
+ const duration = accountExpiry.durationUntilExpiry();
+ const notification = new Notification({
+ title: this.notificationTitle,
+ body: sprintf(
+ // TRANSLATORS: The system notification displayed to the user when the account credit is close to expiry.
+ // TRANSLATORS: Available placeholder:
+ // TRANSLATORS: %(duration)s - remaining time, e.g. "2 days"
+ messages.pgettext('notifications', 'Account credit expires in %(duration)s'),
+ { duration },
+ ),
+ silent: true,
+ icon: this.notificationIcon,
+ });
+ this.scheduleNotification(notification);
+ }
+
public cancelPendingNotifications() {
for (const notification of this.pendingNotifications) {
notification.close();