diff --git a/src/app/main.ts b/src/app/main.ts index 98cbb9b3..32ba66c1 100644 --- a/src/app/main.ts +++ b/src/app/main.ts @@ -14,6 +14,7 @@ import { protocolHandler } from './protocol-handler'; import { ICustomBrowserWindow, windowHandler } from './window-handler'; import { autoLaunchInstance } from './auto-launch-controller'; +import { presenceStatusStore } from './stores'; // Set automatic period substitution to false because of a bug in draft js on the client app // See https://perzoinc.atlassian.net/browse/SDA-2215 for more details @@ -171,6 +172,7 @@ app.on('window-all-closed', () => { */ app.on('quit', () => { logger.info(`main: quitting the app!`); + presenceStatusStore.destroyCurrentTray(); cleanUpAppCache(); }); diff --git a/src/app/presence-status-handler.ts b/src/app/presence-status-handler.ts index 2b1c74fe..727c9273 100644 --- a/src/app/presence-status-handler.ts +++ b/src/app/presence-status-handler.ts @@ -1,4 +1,4 @@ -import { nativeImage, WebContents } from 'electron'; +import { app, Menu, nativeImage, WebContents } from 'electron'; import { EPresenceStatus, IPresenceStatus, @@ -7,7 +7,8 @@ import { import { i18n } from '../common/i18n'; import { logger } from '../common/logger'; import { presenceStatusStore } from './stores'; -import { showBadgeCount, showSystemTrayPresence } from './window-utils'; +import { windowHandler } from './window-handler'; +import { initSysTray, showBadgeCount } from './window-utils'; export interface IListItem { name: string; @@ -79,11 +80,98 @@ class PresenceStatus { }; public setMyPresence = (myPresence: IPresenceStatus) => { + const currentPresenceStatus = presenceStatusStore.getStatus(); const count = presenceStatusStore.getNotificationCount(); - - presenceStatusStore.setStatus(myPresence.category); + if (currentPresenceStatus !== myPresence.category) { + presenceStatusStore.setStatus(myPresence.category); + this.updateSystemTrayPresence(); + } showBadgeCount(count); - showSystemTrayPresence(myPresence.category); + }; + + /** + * Shows the badge count + * + * @param count {number} + */ + public updateSystemTrayPresence = (): void => { + const status = presenceStatusStore.getStatus(); + let tray = presenceStatusStore.getCurrentTray(); + const backgroundImage = presenceStatusStore.generateImagePath( + status, + 'tray', + ); + if (!backgroundImage) { + return; + } + if (!tray) { + tray = initSysTray(); + logger.info('presence-status-handler: create and save Symphony tray'); + } else { + tray.setImage(backgroundImage); + logger.info('presence-status-handler: new Symphony status updated'); + } + const currentStatus = presenceStatusStore.getStatus(); + const presenceNamespace = 'PresenceStatus'; + const isMana = !!windowHandler.isMana; + const contextMenu = Menu.buildFromTemplate([ + { + label: i18n.t('My presence')(), + visible: isMana, + submenu: [ + { + label: i18n.t(EPresenceStatus.AVAILABLE, presenceNamespace)(), + type: 'checkbox', + checked: currentStatus === EPresenceStatus.AVAILABLE, + click: () => { + this.handlePresenceChange(EPresenceStatus.AVAILABLE); + }, + }, + { + label: i18n.t(EPresenceStatus.BUSY, presenceNamespace)(), + type: 'checkbox', + checked: currentStatus === EPresenceStatus.BUSY, + click: () => { + this.handlePresenceChange(EPresenceStatus.BUSY); + }, + }, + { + label: i18n.t(EPresenceStatus.BE_RIGHT_BACK, presenceNamespace)(), + type: 'checkbox', + checked: currentStatus === EPresenceStatus.BE_RIGHT_BACK, + click: () => { + this.handlePresenceChange(EPresenceStatus.BE_RIGHT_BACK); + }, + }, + { + label: i18n.t(EPresenceStatus.OUT_OF_OFFICE, presenceNamespace)(), + type: 'checkbox', + checked: currentStatus === EPresenceStatus.OUT_OF_OFFICE, + click: () => { + this.handlePresenceChange(EPresenceStatus.OUT_OF_OFFICE); + }, + }, + ], + }, + { + label: i18n.t('Quit Symphony')(), + click: () => app.quit(), + }, + ]); + tray?.setContextMenu(contextMenu); + }; + + private handlePresenceChange = (currentStatus: EPresenceStatus) => { + const status = { + category: currentStatus, + statusGroup: '', + timestamp: Date.now(), + }; + presenceStatus.setMyPresence(status); + const mainWebContents = windowHandler.getMainWebContents(); + if (mainWebContents) { + mainWebContents.send('send-presence-status-data', currentStatus); + } }; private setPresenceStatus = ( @@ -92,6 +180,7 @@ class PresenceStatus { ) => { webContents.send('send-presence-status-data', status); presenceStatusStore.setStatus(status); + this.updateSystemTrayPresence(); }; } diff --git a/src/app/stores/presence-status-store.ts b/src/app/stores/presence-status-store.ts index 38793f49..8b80fb92 100644 --- a/src/app/stores/presence-status-store.ts +++ b/src/app/stores/presence-status-store.ts @@ -1,16 +1,17 @@ -import { Tray } from 'electron'; +import { nativeTheme, Tray } from 'electron'; import * as path from 'path'; import { EPresenceStatus, IStatusBadge, ITray, } from '../../common/api-interface'; +import { isMac, isWindowsOS } from '../../common/env'; // Flags can be read more here https://www.electronjs.org/docs/latest/api/browser-window#winsetthumbarbuttonsbuttons-windows export class PresenceStatus { private presenceStatus: IStatusBadge = { - status: EPresenceStatus.AVAILABLE, + status: EPresenceStatus.NO_PRESENCE, count: 0, }; private tray: ITray = { @@ -37,9 +38,19 @@ export class PresenceStatus { public getCurrentTray = () => this.tray.current; + public destroyCurrentTray = () => { + if (this.tray.current) { + this.tray.current.removeAllListeners(); + this.tray.current.destroy(); + this.tray.current = null; + } + }; + public generateImagePath = (status: EPresenceStatus, place: string) => { let backgroundImage: string = ''; - const assetsPath = 'src/renderer/assets/presence-status'; + const os = isWindowsOS ? 'windows' : isMac ? 'macOS' : 'linux'; + const theme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark'; + const assetsPath = `src/renderer/assets/presence-status/${os}/${theme}`; switch (status) { case EPresenceStatus.AVAILABLE: @@ -71,7 +82,15 @@ export class PresenceStatus { place === 'tray' ? 'out-of-office-tray.png' : 'out-of-office.png' }`; break; - + case EPresenceStatus.IN_A_MEETING: + backgroundImage = `../../../${assetsPath}/${ + place === 'tray' ? 'in-a-meeting-tray.png' : 'in-a-meeting.png' + }`; + break; + case EPresenceStatus.NO_PRESENCE: + backgroundImage = + place === 'tray' ? `../../../${assetsPath}/no-status-tray.png` : ''; + break; default: break; } diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts index eed280ad..e5eaa4bd 100644 --- a/src/app/window-handler.ts +++ b/src/app/window-handler.ts @@ -9,6 +9,7 @@ import { dialog, Event, ipcMain, + nativeTheme, RenderProcessGoneDetails, screen, shell, @@ -43,6 +44,7 @@ import { import crashHandler from './crash-handler'; import LocalMenuShortcuts from './local-menu-shortcuts'; import { mainEvents } from './main-event-handler'; +import { presenceStatus } from './presence-status-handler'; import { exportLogs } from './reports-handler'; import { SpellChecker } from './spell-check-handler'; import { winStore } from './stores'; @@ -60,6 +62,7 @@ import { getWindowByName, handleCertificateProxyVerification, handleDownloadManager, + initSysTray, injectStyles, isSymphonyReachable, loadBrowserViews, @@ -455,6 +458,12 @@ export class WindowHandler { mainEvents.publish('maximize'); } this.mainWindow.show(); + initSysTray(); + if (isMac) { + nativeTheme.on('updated', () => { + presenceStatus.updateSystemTrayPresence(); + }); + } // check for build expiry in case of test builds this.checkExpiry(this.mainWindow); diff --git a/src/app/window-utils.ts b/src/app/window-utils.ts index f90381b0..b6155379 100644 --- a/src/app/window-utils.ts +++ b/src/app/window-utils.ts @@ -3,7 +3,9 @@ import { BrowserView, BrowserWindow, dialog, + Menu, nativeImage, + nativeTheme, Rectangle, screen, shell, @@ -299,25 +301,30 @@ export const showBadgeCount = (count: number): void => { }; /** - * Shows the badge count - * - * @param count {number} + * Creates sys tray */ -export const showSystemTrayPresence = (status: EPresenceStatus): void => { - const tray = presenceStatusStore.getCurrentTray(); - const backgroundImage = presenceStatusStore.generateImagePath(status, 'tray'); - if (!backgroundImage) { - return; - } - if (!tray) { - const symphonyTray = new Tray(backgroundImage); - presenceStatusStore.setCurrentTray(symphonyTray); - symphonyTray.setToolTip('Symphony'); - logger.info('main-api-handler: create and save Symphony tray'); - } else { - tray.setImage(backgroundImage); - logger.info('main-api-handler: new Symphony status updated'); - } +export const initSysTray = () => { + const defaultSysTrayIcon = 'no-status-tray.png'; + const os = isWindowsOS ? 'windows' : isMac ? 'macOS' : 'linux'; + const theme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark'; + logger.info('theme: ', theme, nativeTheme.themeSource); + const assetsPath = `renderer/assets/presence-status/${os}/${theme}`; + const defaultSysTrayIconPath = path.join( + __dirname, + `../${assetsPath}/${defaultSysTrayIcon}`, + ); + const backgroundImage = nativeImage.createFromPath(defaultSysTrayIconPath); + const tray = new Tray(backgroundImage); + const contextMenu = Menu.buildFromTemplate([ + { + label: i18n.t('Quit Symphony')(), + click: () => app.quit(), + }, + ]); + tray.setContextMenu(contextMenu); + tray.setToolTip('Symphony'); + presenceStatusStore.setCurrentTray(tray); + return tray; }; /** diff --git a/src/common/api-interface.ts b/src/common/api-interface.ts index 59acaee8..90f34dfc 100644 --- a/src/common/api-interface.ts +++ b/src/common/api-interface.ts @@ -201,6 +201,7 @@ export enum EPresenceStatus { 'IN_A_MEETING' = 'IN_A_MEETING', 'BE_RIGHT_BACK' = 'BE_RIGHT_BACK', 'OFF_WORK' = 'OFF_WORK', + 'NO_PRESENCE' = 'NO_PRESENCE', } export interface IPresenceStatus { diff --git a/src/locale/en-US.json b/src/locale/en-US.json index ca7c1eb9..e1c7bbf7 100644 --- a/src/locale/en-US.json +++ b/src/locale/en-US.json @@ -250,5 +250,6 @@ "AVAILABLE": "Available", "OUT_OF_OFFICE": "Out of office", "BE_RIGHT_BACK": "Be right back" - } + }, + "My presence": "My presence" } diff --git a/src/locale/en.json b/src/locale/en.json index ebeb1a28..508ed76f 100644 --- a/src/locale/en.json +++ b/src/locale/en.json @@ -250,5 +250,6 @@ "AVAILABLE": "Available", "OUT_OF_OFFICE": "Out of office", "BE_RIGHT_BACK": "Be right back" - } + }, + "My presence": "My presence" } diff --git a/src/renderer/assets/presence-status/macOS/dark/brb-tray.png b/src/renderer/assets/presence-status/macOS/dark/brb-tray.png new file mode 100644 index 00000000..c4a44537 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/brb-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/dark/busy-tray.png b/src/renderer/assets/presence-status/macOS/dark/busy-tray.png new file mode 100644 index 00000000..6d7cc203 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/busy-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/dark/in-a-meeting-tray.png b/src/renderer/assets/presence-status/macOS/dark/in-a-meeting-tray.png new file mode 100644 index 00000000..974d1ec3 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/in-a-meeting-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/dark/no-status-tray.png b/src/renderer/assets/presence-status/macOS/dark/no-status-tray.png new file mode 100644 index 00000000..7edf738a Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/no-status-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/dark/offline-tray.png b/src/renderer/assets/presence-status/macOS/dark/offline-tray.png new file mode 100644 index 00000000..91cb03dd Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/offline-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/dark/online-tray.png b/src/renderer/assets/presence-status/macOS/dark/online-tray.png new file mode 100644 index 00000000..bd3e7b85 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/online-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/dark/out-of-office-tray.png b/src/renderer/assets/presence-status/macOS/dark/out-of-office-tray.png new file mode 100644 index 00000000..3328c9c0 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/dark/out-of-office-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/brb-tray.png b/src/renderer/assets/presence-status/macOS/light/brb-tray.png new file mode 100644 index 00000000..3f955f8c Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/brb-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/busy-tray.png b/src/renderer/assets/presence-status/macOS/light/busy-tray.png new file mode 100644 index 00000000..0dc4cd20 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/busy-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/in-a-meeting-tray.png b/src/renderer/assets/presence-status/macOS/light/in-a-meeting-tray.png new file mode 100644 index 00000000..6edd4d1d Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/in-a-meeting-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/no-status-tray.png b/src/renderer/assets/presence-status/macOS/light/no-status-tray.png new file mode 100644 index 00000000..aa1549de Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/no-status-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/offline-tray.png b/src/renderer/assets/presence-status/macOS/light/offline-tray.png new file mode 100644 index 00000000..11d35d7e Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/offline-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/online-tray.png b/src/renderer/assets/presence-status/macOS/light/online-tray.png new file mode 100644 index 00000000..f3e9ff9e Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/online-tray.png differ diff --git a/src/renderer/assets/presence-status/macOS/light/out-of-office-tray.png b/src/renderer/assets/presence-status/macOS/light/out-of-office-tray.png new file mode 100644 index 00000000..c14531d9 Binary files /dev/null and b/src/renderer/assets/presence-status/macOS/light/out-of-office-tray.png differ diff --git a/src/renderer/assets/presence-status/brb-tray.png b/src/renderer/assets/presence-status/windows/dark/brb-tray.png similarity index 100% rename from src/renderer/assets/presence-status/brb-tray.png rename to src/renderer/assets/presence-status/windows/dark/brb-tray.png diff --git a/src/renderer/assets/presence-status/brb.png b/src/renderer/assets/presence-status/windows/dark/brb.png similarity index 100% rename from src/renderer/assets/presence-status/brb.png rename to src/renderer/assets/presence-status/windows/dark/brb.png diff --git a/src/renderer/assets/presence-status/busy-tray.png b/src/renderer/assets/presence-status/windows/dark/busy-tray.png similarity index 100% rename from src/renderer/assets/presence-status/busy-tray.png rename to src/renderer/assets/presence-status/windows/dark/busy-tray.png diff --git a/src/renderer/assets/presence-status/busy.png b/src/renderer/assets/presence-status/windows/dark/busy.png similarity index 100% rename from src/renderer/assets/presence-status/busy.png rename to src/renderer/assets/presence-status/windows/dark/busy.png diff --git a/src/renderer/assets/presence-status/in-a-call-tray.png b/src/renderer/assets/presence-status/windows/dark/in-a-call-tray.png similarity index 100% rename from src/renderer/assets/presence-status/in-a-call-tray.png rename to src/renderer/assets/presence-status/windows/dark/in-a-call-tray.png diff --git a/src/renderer/assets/presence-status/in-a-meeting.png b/src/renderer/assets/presence-status/windows/dark/in-a-meeting.png similarity index 100% rename from src/renderer/assets/presence-status/in-a-meeting.png rename to src/renderer/assets/presence-status/windows/dark/in-a-meeting.png diff --git a/src/renderer/assets/presence-status/no-status.png b/src/renderer/assets/presence-status/windows/dark/no-status-tray.png similarity index 100% rename from src/renderer/assets/presence-status/no-status.png rename to src/renderer/assets/presence-status/windows/dark/no-status-tray.png diff --git a/src/renderer/assets/presence-status/offline-tray.png b/src/renderer/assets/presence-status/windows/dark/offline-tray.png similarity index 100% rename from src/renderer/assets/presence-status/offline-tray.png rename to src/renderer/assets/presence-status/windows/dark/offline-tray.png diff --git a/src/renderer/assets/presence-status/offline.png b/src/renderer/assets/presence-status/windows/dark/offline.png similarity index 100% rename from src/renderer/assets/presence-status/offline.png rename to src/renderer/assets/presence-status/windows/dark/offline.png diff --git a/src/renderer/assets/presence-status/online-tray.png b/src/renderer/assets/presence-status/windows/dark/online-tray.png similarity index 100% rename from src/renderer/assets/presence-status/online-tray.png rename to src/renderer/assets/presence-status/windows/dark/online-tray.png diff --git a/src/renderer/assets/presence-status/online.png b/src/renderer/assets/presence-status/windows/dark/online.png similarity index 100% rename from src/renderer/assets/presence-status/online.png rename to src/renderer/assets/presence-status/windows/dark/online.png diff --git a/src/renderer/assets/presence-status/out-of-office-tray.png b/src/renderer/assets/presence-status/windows/dark/out-of-office-tray.png similarity index 100% rename from src/renderer/assets/presence-status/out-of-office-tray.png rename to src/renderer/assets/presence-status/windows/dark/out-of-office-tray.png diff --git a/src/renderer/assets/presence-status/out-of-office.png b/src/renderer/assets/presence-status/windows/dark/out-of-office.png similarity index 100% rename from src/renderer/assets/presence-status/out-of-office.png rename to src/renderer/assets/presence-status/windows/dark/out-of-office.png diff --git a/src/renderer/assets/presence-status/windows/light/brb-tray.png b/src/renderer/assets/presence-status/windows/light/brb-tray.png new file mode 100644 index 00000000..a23d86cc Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/brb-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/brb.png b/src/renderer/assets/presence-status/windows/light/brb.png new file mode 100644 index 00000000..17f10b8f Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/brb.png differ diff --git a/src/renderer/assets/presence-status/windows/light/busy-tray.png b/src/renderer/assets/presence-status/windows/light/busy-tray.png new file mode 100644 index 00000000..7e503584 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/busy-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/busy.png b/src/renderer/assets/presence-status/windows/light/busy.png new file mode 100644 index 00000000..0c310550 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/busy.png differ diff --git a/src/renderer/assets/presence-status/windows/light/in-a-call-tray.png b/src/renderer/assets/presence-status/windows/light/in-a-call-tray.png new file mode 100644 index 00000000..0352053a Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/in-a-call-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/in-a-meeting.png b/src/renderer/assets/presence-status/windows/light/in-a-meeting.png new file mode 100644 index 00000000..dacc3b85 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/in-a-meeting.png differ diff --git a/src/renderer/assets/presence-status/windows/light/no-status-tray.png b/src/renderer/assets/presence-status/windows/light/no-status-tray.png new file mode 100644 index 00000000..8c91b5fd Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/no-status-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/offline-tray.png b/src/renderer/assets/presence-status/windows/light/offline-tray.png new file mode 100644 index 00000000..d22fcca3 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/offline-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/offline.png b/src/renderer/assets/presence-status/windows/light/offline.png new file mode 100644 index 00000000..3cde8e14 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/offline.png differ diff --git a/src/renderer/assets/presence-status/windows/light/online-tray.png b/src/renderer/assets/presence-status/windows/light/online-tray.png new file mode 100644 index 00000000..359182d5 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/online-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/online.png b/src/renderer/assets/presence-status/windows/light/online.png new file mode 100644 index 00000000..c94fe5f4 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/online.png differ diff --git a/src/renderer/assets/presence-status/windows/light/out-of-office-tray.png b/src/renderer/assets/presence-status/windows/light/out-of-office-tray.png new file mode 100644 index 00000000..7bfe9443 Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/out-of-office-tray.png differ diff --git a/src/renderer/assets/presence-status/windows/light/out-of-office.png b/src/renderer/assets/presence-status/windows/light/out-of-office.png new file mode 100644 index 00000000..057681fa Binary files /dev/null and b/src/renderer/assets/presence-status/windows/light/out-of-office.png differ