mirror of
https://github.com/bitwarden/desktop.git
synced 2024-09-27 03:53:00 +02:00
more tray icon options
This commit is contained in:
parent
4fd597fc05
commit
9d969929de
2
jslib
2
jslib
@ -1 +1 @@
|
|||||||
Subproject commit 61e13daefafe53c4c4b33fa9419052bfc2cfc9cd
|
Subproject commit c6c5dd6d46526a36b65de3f5069e56d131843f7d
|
@ -32,6 +32,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<small class="help-block">{{'disableFaviconDesc' | i18n}}</small>
|
<small class="help-block">{{'disableFaviconDesc' | i18n}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label for="enableTray">
|
||||||
|
<input id="enableTray" type="checkbox" name="EnableTray"
|
||||||
|
[(ngModel)]="enableTray" (change)="saveTray()">
|
||||||
|
{{'enableTray' | i18n}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<small class="help-block">{{'enableTrayDesc' | i18n}}</small>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label for="enableMinToTray">
|
<label for="enableMinToTray">
|
||||||
|
@ -15,7 +15,7 @@ import { StorageService } from 'jslib/abstractions/storage.service';
|
|||||||
|
|
||||||
import { ConstantsService } from 'jslib/services/constants.service';
|
import { ConstantsService } from 'jslib/services/constants.service';
|
||||||
|
|
||||||
import { DesktopConstants } from '../../desktopConstants';
|
import { ElectronConstants } from 'jslib/electron/electronConstants';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
@ -26,6 +26,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
disableGa: boolean = false;
|
disableGa: boolean = false;
|
||||||
disableFavicons: boolean = false;
|
disableFavicons: boolean = false;
|
||||||
enableMinToTray: boolean = false;
|
enableMinToTray: boolean = false;
|
||||||
|
enableTray: boolean = false;
|
||||||
locale: string;
|
locale: string;
|
||||||
lockOptions: any[];
|
lockOptions: any[];
|
||||||
localeOptions: any[];
|
localeOptions: any[];
|
||||||
@ -58,7 +59,8 @@ export class SettingsComponent implements OnInit {
|
|||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.lockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey);
|
this.lockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey);
|
||||||
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
|
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
|
||||||
this.enableMinToTray = await this.storageService.get<boolean>(DesktopConstants.enableMinimizeToTrayKey);
|
this.enableMinToTray = await this.storageService.get<boolean>(ElectronConstants.enableMinimizeToTrayKey);
|
||||||
|
this.enableTray = await this.storageService.get<boolean>(ElectronConstants.enableTrayKey);
|
||||||
this.locale = await this.storageService.get<string>(ConstantsService.localeKey);
|
this.locale = await this.storageService.get<string>(ConstantsService.localeKey);
|
||||||
|
|
||||||
const disableGa = await this.storageService.get<boolean>(ConstantsService.disableGaKey);
|
const disableGa = await this.storageService.get<boolean>(ConstantsService.disableGaKey);
|
||||||
@ -88,10 +90,16 @@ export class SettingsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async saveMinToTray() {
|
async saveMinToTray() {
|
||||||
await this.storageService.save(DesktopConstants.enableMinimizeToTrayKey, this.enableMinToTray);
|
await this.storageService.save(ElectronConstants.enableMinimizeToTrayKey, this.enableMinToTray);
|
||||||
this.callAnalytics('MinimizeToTray', this.enableMinToTray);
|
this.callAnalytics('MinimizeToTray', this.enableMinToTray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveTray() {
|
||||||
|
await this.storageService.save(ElectronConstants.enableTrayKey, this.enableTray);
|
||||||
|
this.callAnalytics('Tray', this.enableTray);
|
||||||
|
this.messagingService.send(this.enableTray ? 'showTray' : 'removeTray');
|
||||||
|
}
|
||||||
|
|
||||||
async saveLocale() {
|
async saveLocale() {
|
||||||
await this.storageService.save(ConstantsService.localeKey, this.locale);
|
await this.storageService.save(ConstantsService.localeKey, this.locale);
|
||||||
this.analytics.eventTrack.next({ action: 'Set Locale ' + this.locale });
|
this.analytics.eventTrack.next({ action: 'Set Locale ' + this.locale });
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
export class DesktopConstants {
|
|
||||||
static readonly enableMinimizeToTrayKey: string = 'enableMinimizeToTray';
|
|
||||||
}
|
|
@ -771,10 +771,16 @@
|
|||||||
"message": "Website Icons provide a recognizable image next to each login item in your vault."
|
"message": "Website Icons provide a recognizable image next to each login item in your vault."
|
||||||
},
|
},
|
||||||
"enableMinToTray": {
|
"enableMinToTray": {
|
||||||
"message": "Minimize to Tray"
|
"message": "Minimize to Tray Icon"
|
||||||
},
|
},
|
||||||
"enableMinToTrayDesc": {
|
"enableMinToTrayDesc": {
|
||||||
"message": "When minimizing the window, run Bitwarden as a system tray icon."
|
"message": "When minimizing the window, show an icon in the system tray instead."
|
||||||
|
},
|
||||||
|
"enableTray": {
|
||||||
|
"message": "Enable Tray Icon"
|
||||||
|
},
|
||||||
|
"enableTrayDesc": {
|
||||||
|
"message": "Always show an icon in the system tray."
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"message": "Language"
|
"message": "Language"
|
||||||
@ -1037,5 +1043,8 @@
|
|||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"message": "Default"
|
"message": "Default"
|
||||||
|
},
|
||||||
|
"exit": {
|
||||||
|
"message": "Exit"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
src/main.ts
19
src/main.ts
@ -1,4 +1,8 @@
|
|||||||
import { app, BrowserWindow } from 'electron';
|
import {
|
||||||
|
app,
|
||||||
|
BrowserWindow,
|
||||||
|
MenuItemConstructorOptions,
|
||||||
|
} from 'electron';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { I18nService } from './services/i18n.service';
|
import { I18nService } from './services/i18n.service';
|
||||||
@ -17,8 +21,6 @@ import { ElectronStorageService } from 'jslib/electron/services/electronStorage.
|
|||||||
import { UpdaterMain } from 'jslib/electron/updater.main';
|
import { UpdaterMain } from 'jslib/electron/updater.main';
|
||||||
import { WindowMain } from 'jslib/electron/window.main';
|
import { WindowMain } from 'jslib/electron/window.main';
|
||||||
|
|
||||||
import { DesktopConstants } from './desktopConstants';
|
|
||||||
|
|
||||||
export class Main {
|
export class Main {
|
||||||
logService: ElectronLogService;
|
logService: ElectronLogService;
|
||||||
i18nService: I18nService;
|
i18nService: I18nService;
|
||||||
@ -76,9 +78,7 @@ export class Main {
|
|||||||
});
|
});
|
||||||
this.menuMain = new MenuMain(this);
|
this.menuMain = new MenuMain(this);
|
||||||
this.powerMonitorMain = new PowerMonitorMain(this);
|
this.powerMonitorMain = new PowerMonitorMain(this);
|
||||||
this.trayMain = new TrayMain(this.windowMain, 'Bitwarden', async () => {
|
this.trayMain = new TrayMain(this.windowMain, this.i18nService, this.storageService, 'Bitwarden');
|
||||||
return await this.storageService.get<boolean>(DesktopConstants.enableMinimizeToTrayKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.messagingService = new ElectronMainMessagingService(this.windowMain, (message) => {
|
this.messagingService = new ElectronMainMessagingService(this.windowMain, (message) => {
|
||||||
this.messagingMain.onMessage(message);
|
this.messagingMain.onMessage(message);
|
||||||
@ -95,7 +95,12 @@ export class Main {
|
|||||||
this.messagingMain.init();
|
this.messagingMain.init();
|
||||||
this.menuMain.init();
|
this.menuMain.init();
|
||||||
this.powerMonitorMain.init();
|
this.powerMonitorMain.init();
|
||||||
this.trayMain.init();
|
this.trayMain.init([{
|
||||||
|
label: this.i18nService.t('lockNow'),
|
||||||
|
enabled: false,
|
||||||
|
id: 'lockNow',
|
||||||
|
click: () => this.messagingService.send('lockVault'),
|
||||||
|
}]);
|
||||||
await this.updaterMain.init();
|
await this.updaterMain.init();
|
||||||
}, (e: any) => {
|
}, (e: any) => {
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
|
@ -21,6 +21,16 @@ export class MessagingMain {
|
|||||||
break;
|
break;
|
||||||
case 'updateAppMenu':
|
case 'updateAppMenu':
|
||||||
this.main.menuMain.updateApplicationMenuState(message.isAuthenticated, message.isLocked);
|
this.main.menuMain.updateApplicationMenuState(message.isAuthenticated, message.isLocked);
|
||||||
|
this.updateTrayMenu(message.isAuthenticated, message.isLocked);
|
||||||
|
break;
|
||||||
|
case 'showTray':
|
||||||
|
this.main.trayMain.showTray();
|
||||||
|
break;
|
||||||
|
case 'removeTray':
|
||||||
|
this.main.trayMain.removeTray();
|
||||||
|
break;
|
||||||
|
case 'hideToTray':
|
||||||
|
this.main.trayMain.hideToTray();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -42,4 +52,11 @@ export class MessagingMain {
|
|||||||
});
|
});
|
||||||
}, SyncInterval);
|
}, SyncInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateTrayMenu(isAuthenticated: boolean, isLocked: boolean) {
|
||||||
|
const lockNowTrayMenuItem = this.main.trayMain.contextMenu.getMenuItemById('lockNow');
|
||||||
|
if (lockNowTrayMenuItem != null) {
|
||||||
|
lockNowTrayMenuItem.enabled = isAuthenticated && !isLocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,26 @@
|
|||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
MenuItemConstructorOptions,
|
||||||
nativeImage,
|
nativeImage,
|
||||||
Tray,
|
Tray,
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||||
|
import { ElectronConstants } from 'jslib/electron/electronConstants';
|
||||||
import { WindowMain } from 'jslib/electron/window.main';
|
import { WindowMain } from 'jslib/electron/window.main';
|
||||||
|
|
||||||
import { DesktopConstants } from '../desktopConstants';
|
|
||||||
|
|
||||||
export class TrayMain {
|
export class TrayMain {
|
||||||
|
contextMenu: Menu;
|
||||||
|
|
||||||
private tray: Tray;
|
private tray: Tray;
|
||||||
private menu: Menu;
|
|
||||||
private icon: string | Electron.NativeImage;
|
private icon: string | Electron.NativeImage;
|
||||||
private pressedIcon: Electron.NativeImage;
|
private pressedIcon: Electron.NativeImage;
|
||||||
|
|
||||||
constructor(private windowMain: WindowMain, private appName: string, private minToTray: () => Promise<boolean>) {
|
constructor(private windowMain: WindowMain, private i18nService: I18nService,
|
||||||
|
private storageService: StorageService, private appName: string) {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
this.icon = path.join(__dirname, '/images/icon.ico');
|
this.icon = path.join(__dirname, '/images/icon.ico');
|
||||||
} else if (process.platform === 'darwin') {
|
} else if (process.platform === 'darwin') {
|
||||||
@ -28,52 +33,91 @@ export class TrayMain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
async init(additionalMenuItems: MenuItemConstructorOptions[] = null) {
|
||||||
if (process.platform === 'linux') {
|
const menuItemOptions: MenuItemConstructorOptions[] = [{
|
||||||
this.menu = Menu.buildFromTemplate([{
|
label: this.appName,
|
||||||
label: this.appName,
|
click: () => this.toggleWindow(),
|
||||||
click: () => this.open(),
|
},
|
||||||
}]);
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: this.i18nService.t('exit'),
|
||||||
|
click: () => this.closeWindow(),
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (additionalMenuItems != null) {
|
||||||
|
menuItemOptions.splice(1, 0, ...additionalMenuItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.contextMenu = Menu.buildFromTemplate(menuItemOptions);
|
||||||
|
if (await this.storageService.get<boolean>(ElectronConstants.enableTrayKey)) {
|
||||||
|
this.showTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.windowMain.win.on('minimize', async (e: Event) => {
|
this.windowMain.win.on('minimize', async (e: Event) => {
|
||||||
if (await this.minToTray()) {
|
if (await this.storageService.get<boolean>(ElectronConstants.enableMinimizeToTrayKey)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await this.handleHideEvent();
|
await this.hideToTray();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.windowMain.win.on('show', async (e: Event) => {
|
this.windowMain.win.on('show', async (e: Event) => {
|
||||||
await this.handleShowEvent();
|
const enableTray = await this.storageService.get<boolean>(ElectronConstants.enableTrayKey);
|
||||||
|
if (!enableTray) {
|
||||||
|
await this.removeTray(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleShowEvent() {
|
removeTray(showWindow = true) {
|
||||||
if (this.tray != null) {
|
if (this.tray != null) {
|
||||||
this.tray.destroy();
|
this.tray.destroy();
|
||||||
this.tray = null;
|
this.tray = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.windowMain.win != null && !this.windowMain.win.isVisible()) {
|
||||||
|
this.windowMain.win.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleHideEvent() {
|
hideToTray() {
|
||||||
|
this.showTray();
|
||||||
|
if (this.windowMain.win != null) {
|
||||||
|
this.windowMain.win.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showTray() {
|
||||||
|
if (this.tray != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.tray = new Tray(this.icon);
|
this.tray = new Tray(this.icon);
|
||||||
this.tray.setToolTip(this.appName);
|
this.tray.setToolTip(this.appName);
|
||||||
|
this.tray.on('click', () => this.toggleWindow());
|
||||||
|
|
||||||
if (this.pressedIcon != null) {
|
if (this.pressedIcon != null) {
|
||||||
this.tray.setPressedImage(this.pressedIcon);
|
this.tray.setPressedImage(this.pressedIcon);
|
||||||
}
|
}
|
||||||
if (this.menu != null) {
|
if (this.contextMenu != null) {
|
||||||
this.tray.setContextMenu(this.menu);
|
this.tray.setContextMenu(this.contextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tray.on('click', () => open());
|
|
||||||
this.windowMain.win.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private open() {
|
private toggleWindow() {
|
||||||
|
if (this.windowMain.win == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.windowMain.win.isVisible()) {
|
if (this.windowMain.win.isVisible()) {
|
||||||
this.windowMain.win.hide();
|
this.windowMain.win.hide();
|
||||||
} else {
|
} else {
|
||||||
this.windowMain.win.show();
|
this.windowMain.win.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private closeWindow() {
|
||||||
|
if (this.windowMain.win != null) {
|
||||||
|
this.windowMain.win.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user