diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d8b6f59d66..549a99f093 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -30,6 +30,7 @@ import { CryptoService } from 'jslib/abstractions/crypto.service'; import { FolderService } from 'jslib/abstractions/folder.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { LockService } from 'jslib/abstractions/lock.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { SettingsService } from 'jslib/abstractions/settings.service'; @@ -72,9 +73,14 @@ export class AppComponent implements OnInit { private toasterService: ToasterService, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, private ngZone: NgZone, private lockService: LockService, private storageService: StorageService, - private cryptoService: CryptoService, private componentFactoryResolver: ComponentFactoryResolver) { } + private cryptoService: CryptoService, private componentFactoryResolver: ComponentFactoryResolver, + private messagingService: MessagingService) { } ngOnInit() { + setTimeout(async () => { + await this.updateAppMenu(); + }, 1000); + window.onmousemove = () => this.recordActivity(); window.onmousedown = () => this.recordActivity(); window.ontouchstart = () => this.recordActivity(); @@ -82,7 +88,11 @@ export class AppComponent implements OnInit { window.onscroll = () => this.recordActivity(); window.onkeypress = () => this.recordActivity(); - this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { + this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => { + if (message.command !== 'updateAppMenu') { + await this.updateAppMenu(); + } + this.ngZone.run(async () => { switch (message.command) { case 'loggedIn': @@ -115,6 +125,13 @@ export class AppComponent implements OnInit { this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); } + private async updateAppMenu() { + this.messagingService.send('updateAppMenu', { + isAuthenticated: await this.userService.isAuthenticated(), + isLocked: (await this.cryptoService.getKey()) == null, + }); + } + private async logOut(expired: boolean) { const userId = await this.userService.getUserId(); @@ -129,13 +146,14 @@ export class AppComponent implements OnInit { this.passwordGenerationService.clear(), ]); - this.authService.logOut(() => { + this.authService.logOut(async () => { this.analytics.eventTrack.next({ action: 'Logged Out' }); if (expired) { this.toasterService.popAsync('warning', this.i18nService.t('loggedOut'), this.i18nService.t('loginExpired')); } - this.router.navigate(['login']); + await this.router.navigate(['login']); + this.messagingService.send('loggedOut'); }); } diff --git a/src/main/menu.main.ts b/src/main/menu.main.ts index 0291a4119d..ff267f1b3c 100644 --- a/src/main/menu.main.ts +++ b/src/main/menu.main.ts @@ -13,11 +13,57 @@ import { import { Main } from '../main'; export class MenuMain { + menu: Menu; + updateMenuItem: MenuItem; + addNewLogin: MenuItem; + addNewItem: MenuItem; + addNewFolder: MenuItem; + syncVault: MenuItem; + settings: MenuItem; + lockNow: MenuItem; + logOut: MenuItem; + twoStepLogin: MenuItem; + changeEmail: MenuItem; + changeMasterPass: MenuItem; + premiumMembership: MenuItem; + passwordGenerator: MenuItem; + searchVault: MenuItem; + unlockedRequiredMenuItems: MenuItem[] = []; + constructor(private main: Main) { } init() { this.initContextMenu(); this.initApplicationMenu(); + + this.updateMenuItem = this.menu.getMenuItemById('checkForUpdates'); + this.addNewLogin = this.menu.getMenuItemById('addNewLogin'); + this.addNewItem = this.menu.getMenuItemById('addNewItem'); + this.addNewFolder = this.menu.getMenuItemById('addNewFolder'); + this.syncVault = this.menu.getMenuItemById('syncVault'); + this.settings = this.menu.getMenuItemById('settings'); + this.lockNow = this.menu.getMenuItemById('lockNow'); + this.logOut = this.menu.getMenuItemById('logOut'); + this.twoStepLogin = this.menu.getMenuItemById('twoStepLogin'); + this.changeEmail = this.menu.getMenuItemById('changeEmail'); + this.changeMasterPass = this.menu.getMenuItemById('changeMasterPass'); + this.premiumMembership = this.menu.getMenuItemById('premiumMembership'); + this.passwordGenerator = this.menu.getMenuItemById('passwordGenerator'); + this.searchVault = this.menu.getMenuItemById('searchVault'); + + this.unlockedRequiredMenuItems = [ + this.addNewLogin, this.addNewItem, this.addNewFolder, + this.syncVault, this.settings, this.lockNow, this.twoStepLogin, this.changeEmail, + this.changeMasterPass, this.premiumMembership, this.passwordGenerator, this.searchVault]; + this.updateApplicationMenuState(false, true); + } + + updateApplicationMenuState(isAuthenticated: boolean, isLocked: boolean) { + this.unlockedRequiredMenuItems.forEach((mi: MenuItem) => { + mi.enabled = isAuthenticated && !isLocked; + }); + + this.logOut.enabled = isAuthenticated; } private initContextMenu() { @@ -67,9 +113,11 @@ export class MenuMain { label: this.main.i18nService.t('addNewLogin'), click: () => this.main.messagingService.send('newLogin'), accelerator: 'CmdOrCtrl+N', + id: 'addNewLogin', }, { label: this.main.i18nService.t('addNewItem'), + id: 'addNewItem', submenu: [ { label: this.main.i18nService.t('typeLogin'), @@ -95,11 +143,13 @@ export class MenuMain { }, { label: this.main.i18nService.t('addNewFolder'), + id: 'addNewFolder', click: () => this.main.messagingService.send('newFolder'), }, { type: 'separator' }, { label: this.main.i18nService.t('syncVault'), + id: 'syncVault', click: () => this.main.messagingService.send('syncVault'), }, ], @@ -122,11 +172,13 @@ export class MenuMain { submenu: [ { label: this.main.i18nService.t('passwordGenerator'), + id: 'passwordGenerator', click: () => this.main.messagingService.send('openPasswordGenerator'), accelerator: 'CmdOrCtrl+G', }, { label: this.main.i18nService.t('searchVault'), + id: 'searchVault', click: () => this.main.messagingService.send('focusSearch'), accelerator: 'CmdOrCtrl+F', }, @@ -148,9 +200,11 @@ export class MenuMain { { label: this.main.i18nService.t('premiumMembership'), click: () => this.main.messagingService.send('premiumMembership'), + id: 'premiumMembership', }, { label: this.main.i18nService.t('changeMasterPass'), + id: 'changeMasterPass', click: () => { const result = dialog.showMessageBox(this.main.windowMain.win, { title: this.main.i18nService.t('changeMasterPass'), @@ -167,6 +221,7 @@ export class MenuMain { }, { label: this.main.i18nService.t('changeEmail'), + id: 'changeEmail', click: () => { const result = dialog.showMessageBox(this.main.windowMain.win, { title: this.main.i18nService.t('changeEmail'), @@ -183,6 +238,7 @@ export class MenuMain { }, { label: this.main.i18nService.t('twoStepLogin'), + id: 'twoStepLogin', click: () => { const result = dialog.showMessageBox(this.main.windowMain.win, { title: this.main.i18nService.t('twoStepLogin'), @@ -200,6 +256,7 @@ export class MenuMain { { type: 'separator' }, { label: this.main.i18nService.t('logOut'), + id: 'logOut', click: () => { const result = dialog.showMessageBox(this.main.windowMain.win, { title: this.main.i18nService.t('logOut'), @@ -336,10 +393,12 @@ export class MenuMain { { type: 'separator' }, { label: this.main.i18nService.t('settings'), + id: 'settings', click: () => this.main.messagingService.send('openSettings'), }, { label: this.main.i18nService.t('lockNow'), + id: 'lockNow', click: () => this.main.messagingService.send('lockVault'), accelerator: 'CmdOrCtrl+L', }, @@ -413,7 +472,7 @@ export class MenuMain { ]); } - const menu = Menu.buildFromTemplate(template); - Menu.setApplicationMenu(menu); + this.menu = Menu.buildFromTemplate(template); + Menu.setApplicationMenu(this.menu); } } diff --git a/src/main/messaging.main.ts b/src/main/messaging.main.ts index 9606aca803..e5422f1882 100644 --- a/src/main/messaging.main.ts +++ b/src/main/messaging.main.ts @@ -54,6 +54,9 @@ export class MessagingMain { case 'scheduleNextSync': this.scheduleNextSync(); break; + case 'updateAppMenu': + this.main.menuMain.updateApplicationMenuState(message.isAuthenticated, message.isLocked); + break; default: break; } diff --git a/src/main/updater.main.ts b/src/main/updater.main.ts index a45809bf17..74fb1903d5 100644 --- a/src/main/updater.main.ts +++ b/src/main/updater.main.ts @@ -14,17 +14,15 @@ const UpdaterCheckInterval = 12 * 60 * 60 * 1000; // 12 hours export class UpdaterMain { private doingUpdateCheck = false; private doingUpdateCheckWithFeedback = false; - private updateMenuItem: MenuItem; constructor(private main: Main) { } async init() { global.setTimeout(async () => await this.checkForUpdate(), UpdaterCheckInitalDelay); global.setInterval(async () => await this.checkForUpdate(), UpdaterCheckInterval); - this.updateMenuItem = Menu.getApplicationMenu().getMenuItemById('checkForUpdates'); autoUpdater.on('checking-for-update', () => { - this.updateMenuItem.enabled = false; + this.main.menuMain.updateMenuItem.enabled = false; this.doingUpdateCheck = true; }); @@ -60,7 +58,7 @@ export class UpdaterMain { }); autoUpdater.on('update-downloaded', (info) => { - this.updateMenuItem.label = this.main.i18nService.t('restartToUpdate'); + this.main.menuMain.updateMenuItem.label = this.main.i18nService.t('restartToUpdate'); const result = dialog.showMessageBox(this.main.windowMain.win, { type: 'info', @@ -103,7 +101,7 @@ export class UpdaterMain { private reset() { autoUpdater.autoDownload = true; - this.updateMenuItem.enabled = true; + this.main.menuMain.updateMenuItem.enabled = true; this.doingUpdateCheck = false; } }