From 7e716fb35eb0b70d7aa1a48c16e293120abce015 Mon Sep 17 00:00:00 2001 From: sbenmoussati <51402489+sbenmoussati@users.noreply.github.com> Date: Tue, 7 Mar 2023 16:28:02 +0100 Subject: [PATCH 1/2] SDA-4070 IDLE presence status bugfix --- src/app/presence-status-handler.ts | 143 ++++++++++++++++-------- src/app/stores/presence-status-store.ts | 37 +++--- src/app/window-utils.ts | 17 +-- src/common/api-interface.ts | 19 +++- src/renderer/ssf-api.ts | 10 +- 5 files changed, 148 insertions(+), 78 deletions(-) diff --git a/src/app/presence-status-handler.ts b/src/app/presence-status-handler.ts index da0010b2..87ee67ec 100644 --- a/src/app/presence-status-handler.ts +++ b/src/app/presence-status-handler.ts @@ -1,6 +1,7 @@ import { app, Menu, nativeImage, WebContents } from 'electron'; import { - EPresenceStatus, + EPresenceStatusCategory, + EPresenceStatusGroup, IPresenceStatus, IThumbarButton, } from '../common/api-interface'; @@ -27,63 +28,88 @@ class PresenceStatus { { click: () => { logger.info('presence-status-handler: Available Clicked'); - this.setPresenceStatus(webContents, EPresenceStatus.AVAILABLE); + this.handlePresenceChange( + EPresenceStatusCategory.AVAILABLE, + EPresenceStatusGroup.ONLINE, + webContents, + ); }, icon: nativeImage.createFromPath( presenceStatusStore.generateImagePath( - EPresenceStatus.AVAILABLE, + EPresenceStatusGroup.ONLINE, 'thumbnail', ), ), - tooltip: i18n.t(EPresenceStatus.AVAILABLE, this.NAMESPACE)(), + tooltip: i18n.t(EPresenceStatusCategory.AVAILABLE, this.NAMESPACE)(), }, { click: () => { logger.info('presence-status-handler: Busy Clicked'); - this.setPresenceStatus(webContents, EPresenceStatus.BUSY); + this.handlePresenceChange( + EPresenceStatusCategory.BUSY, + EPresenceStatusGroup.BUSY, + webContents, + ); }, icon: nativeImage.createFromPath( presenceStatusStore.generateImagePath( - EPresenceStatus.BUSY, + EPresenceStatusGroup.BUSY, 'thumbnail', ), ), - tooltip: i18n.t(EPresenceStatus.BUSY, this.NAMESPACE)(), + tooltip: i18n.t(EPresenceStatusCategory.BUSY, this.NAMESPACE)(), }, { click: () => { logger.info('presence-status-handler: Be Right Back Clicked'); - this.setPresenceStatus(webContents, EPresenceStatus.BE_RIGHT_BACK); + this.handlePresenceChange( + EPresenceStatusCategory.BE_RIGHT_BACK, + EPresenceStatusGroup.IDLE, + webContents, + ); }, icon: nativeImage.createFromPath( presenceStatusStore.generateImagePath( - EPresenceStatus.BE_RIGHT_BACK, + EPresenceStatusGroup.IDLE, 'thumbnail', ), ), - tooltip: i18n.t(EPresenceStatus.BE_RIGHT_BACK, this.NAMESPACE)(), + tooltip: i18n.t( + EPresenceStatusCategory.BE_RIGHT_BACK, + this.NAMESPACE, + )(), }, { click: () => { logger.info('presence-status-handler: Out of Office Clicked'); - this.setPresenceStatus(webContents, EPresenceStatus.OUT_OF_OFFICE); + this.handlePresenceChange( + EPresenceStatusCategory.OUT_OF_OFFICE, + EPresenceStatusGroup.ABSENT, + webContents, + ); }, icon: nativeImage.createFromPath( presenceStatusStore.generateImagePath( - EPresenceStatus.OUT_OF_OFFICE, + EPresenceStatusGroup.ABSENT, 'thumbnail', ), ), - tooltip: i18n.t(EPresenceStatus.OUT_OF_OFFICE, this.NAMESPACE)(), + tooltip: i18n.t( + EPresenceStatusCategory.OUT_OF_OFFICE, + this.NAMESPACE, + )(), }, ]; }; public setMyPresence = (myPresence: IPresenceStatus) => { - const currentPresenceStatus = presenceStatusStore.getStatus(); + const currentPresence = presenceStatusStore.getPresence(); const count = presenceStatusStore.getNotificationCount(); - if (currentPresenceStatus !== myPresence.category) { - presenceStatusStore.setStatus(myPresence.category); + if ( + currentPresence.statusCategory !== myPresence.statusCategory || + currentPresence.statusGroup !== myPresence.statusGroup + ) { + presenceStatusStore.setPresence(myPresence); this.updateSystemTrayPresence(); } showBadgeCount(count); @@ -95,10 +121,10 @@ class PresenceStatus { * @param count {number} */ public updateSystemTrayPresence = (): void => { - const status = presenceStatusStore.getStatus(); + const presence = presenceStatusStore.getPresence(); let tray = presenceStatusStore.getCurrentTray(); const backgroundImage = presenceStatusStore.generateImagePath( - status, + presence.statusGroup, 'tray', ); if (!backgroundImage) { @@ -111,7 +137,6 @@ class PresenceStatus { 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([ @@ -121,39 +146,57 @@ class PresenceStatus { enabled: false, }, { - label: i18n.t(EPresenceStatus.AVAILABLE, presenceNamespace)(), + label: i18n.t(EPresenceStatusCategory.AVAILABLE, presenceNamespace)(), type: 'checkbox', visible: isMana, - checked: currentStatus === EPresenceStatus.AVAILABLE, + checked: presence.statusGroup === EPresenceStatusGroup.ONLINE, click: () => { - this.handlePresenceChange(EPresenceStatus.AVAILABLE); + this.handlePresenceChange( + EPresenceStatusCategory.AVAILABLE, + EPresenceStatusGroup.ONLINE, + ); }, }, { - label: i18n.t(EPresenceStatus.BUSY, presenceNamespace)(), + label: i18n.t(EPresenceStatusCategory.BUSY, presenceNamespace)(), type: 'checkbox', visible: isMana, - checked: currentStatus === EPresenceStatus.BUSY, + checked: presence.statusGroup === EPresenceStatusGroup.BUSY, click: () => { - this.handlePresenceChange(EPresenceStatus.BUSY); + this.handlePresenceChange( + EPresenceStatusCategory.BUSY, + EPresenceStatusGroup.BUSY, + ); }, }, { - label: i18n.t(EPresenceStatus.BE_RIGHT_BACK, presenceNamespace)(), + label: i18n.t( + EPresenceStatusCategory.BE_RIGHT_BACK, + presenceNamespace, + )(), type: 'checkbox', visible: isMana, - checked: currentStatus === EPresenceStatus.BE_RIGHT_BACK, + checked: presence.statusGroup === EPresenceStatusGroup.IDLE, click: () => { - this.handlePresenceChange(EPresenceStatus.BE_RIGHT_BACK); + this.handlePresenceChange( + EPresenceStatusCategory.BE_RIGHT_BACK, + EPresenceStatusGroup.IDLE, + ); }, }, { - label: i18n.t(EPresenceStatus.OUT_OF_OFFICE, presenceNamespace)(), + label: i18n.t( + EPresenceStatusCategory.OUT_OF_OFFICE, + presenceNamespace, + )(), type: 'checkbox', visible: isMana, - checked: currentStatus === EPresenceStatus.OUT_OF_OFFICE, + checked: presence.statusGroup === EPresenceStatusGroup.OFFLINE, click: () => { - this.handlePresenceChange(EPresenceStatus.OUT_OF_OFFICE); + this.handlePresenceChange( + EPresenceStatusCategory.OUT_OF_OFFICE, + EPresenceStatusGroup.OFFLINE, + ); }, }, { type: 'separator', visible: isMana }, @@ -165,27 +208,31 @@ class PresenceStatus { tray?.setContextMenu(contextMenu); }; - private handlePresenceChange = (currentStatus: EPresenceStatus) => { - const status = { - category: currentStatus, - statusGroup: '', + private handlePresenceChange = ( + statusCategory: EPresenceStatusCategory, + statusGroup: EPresenceStatusGroup, + webContents?: WebContents, + ) => { + const status: IPresenceStatus = { + statusCategory, + statusGroup, timestamp: Date.now(), }; - presenceStatus.setMyPresence(status); - const mainWebContents = windowHandler.getMainWebContents(); - if (mainWebContents) { - mainWebContents.send('send-presence-status-data', currentStatus); + if (webContents) { + webContents.send('send-presence-status-data', statusCategory); + presenceStatusStore.setPresence(status); + this.updateSystemTrayPresence(); + } else { + presenceStatus.setMyPresence(status); + const mainWebContents = windowHandler.getMainWebContents(); + if (mainWebContents) { + mainWebContents.send( + 'send-presence-status-data', + status.statusCategory, + ); + } } }; - - private setPresenceStatus = ( - webContents: WebContents, - status: EPresenceStatus, - ) => { - webContents.send('send-presence-status-data', status); - presenceStatusStore.setStatus(status); - this.updateSystemTrayPresence(); - }; } const presenceStatus = new PresenceStatus(); diff --git a/src/app/stores/presence-status-store.ts b/src/app/stores/presence-status-store.ts index c0b31d5a..d180ac18 100644 --- a/src/app/stores/presence-status-store.ts +++ b/src/app/stores/presence-status-store.ts @@ -1,7 +1,9 @@ import { nativeTheme, Tray } from 'electron'; import * as path from 'path'; import { - EPresenceStatus, + EPresenceStatusCategory, + EPresenceStatusGroup, + IPresenceStatus, IStatusBadge, ITray, } from '../../common/api-interface'; @@ -11,23 +13,25 @@ import { isMac, isWindowsOS } from '../../common/env'; export class PresenceStatus { private presenceStatus: IStatusBadge = { - status: EPresenceStatus.NO_PRESENCE, + statusCategory: EPresenceStatusCategory.NO_PRESENCE, + statusGroup: EPresenceStatusGroup.OFFLINE, count: 0, }; private tray: ITray = { current: null, }; - public setStatus = (status: EPresenceStatus) => { - this.presenceStatus.status = status; + public setPresence = (presence: IPresenceStatus) => { + this.presenceStatus.statusCategory = presence.statusCategory; + this.presenceStatus.statusGroup = presence.statusGroup; }; public setNotificationCount = (count: number) => { this.presenceStatus.count = count; }; - public getStatus = () => { - return this.presenceStatus.status; + public getPresence = () => { + return this.presenceStatus; }; public getNotificationCount = () => { @@ -46,7 +50,10 @@ export class PresenceStatus { } }; - public generateImagePath = (status: EPresenceStatus, place: string) => { + public generateImagePath = ( + statusGroup: EPresenceStatusGroup, + place: string, + ) => { let backgroundImage: string = ''; const os = isWindowsOS ? 'windows' : isMac ? 'macOS' : 'linux'; const theme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark'; @@ -65,30 +72,30 @@ export class PresenceStatus { default: break; } - switch (status) { - case EPresenceStatus.AVAILABLE: + switch (statusGroup) { + case EPresenceStatusGroup.ONLINE: backgroundImage = `../../../${assetsPath}/${`available${iconPlace}.${fileExtension}`}`; break; - case EPresenceStatus.BUSY: + case EPresenceStatusGroup.BUSY: backgroundImage = `../../../${assetsPath}/busy${iconPlace}.${fileExtension}`; break; - case EPresenceStatus.BE_RIGHT_BACK || EPresenceStatus.AWAY: + case EPresenceStatusGroup.IDLE: backgroundImage = `../../../${assetsPath}/brb${iconPlace}.${fileExtension}`; break; - case EPresenceStatus.OFFLINE: + case EPresenceStatusGroup.OFFLINE: backgroundImage = `../../../${assetsPath}/offline${iconPlace}.${fileExtension}`; break; - case EPresenceStatus.OUT_OF_OFFICE: + case EPresenceStatusGroup.ABSENT: backgroundImage = `../../../${assetsPath}/out-of-office${iconPlace}.${fileExtension}`; break; - case EPresenceStatus.IN_A_MEETING: + case EPresenceStatusGroup.MEETING: backgroundImage = `../../../${assetsPath}/in-a-meeting${iconPlace}.${fileExtension}`; break; - case EPresenceStatus.NO_PRESENCE: + case EPresenceStatusGroup.HIDE_PRESENCE: backgroundImage = `../../../${assetsPath}/no-status${iconPlace}.${fileExtension}`; break; default: diff --git a/src/app/window-utils.ts b/src/app/window-utils.ts index 27b9d627..d2d68716 100644 --- a/src/app/window-utils.ts +++ b/src/app/window-utils.ts @@ -20,7 +20,7 @@ import * as path from 'path'; import { format, parse } from 'url'; import { apiName, - EPresenceStatus, + EPresenceStatusGroup, // IStatusBadge, } from '../common/api-interface'; @@ -288,14 +288,14 @@ export const showBadgeCount = (count: number): void => { mainWebContents.send('create-badge-data-url', { count }); return; } else { - const status = presenceStatusStore.getStatus(); + const status = presenceStatusStore.getPresence(); const backgroundImage = presenceStatusStore.generateImagePath( - status, + status.statusGroup, 'taskbar', ); if (backgroundImage) { - setStatusBadge(backgroundImage, status); + setStatusBadge(backgroundImage, status.statusGroup); } } }; @@ -336,13 +336,16 @@ export const initSysTray = () => { */ export const setStatusBadge = ( path: string, - status?: EPresenceStatus, + statusGroup?: EPresenceStatusGroup, ): void => { const mainWindow = windowHandler.getMainWindow(); - if (mainWindow && path && status) { + if (mainWindow && path && statusGroup) { const img = nativeImage.createFromPath(path); // for accessibility screen readers - const desc = `Your current status is ${i18n.t(status, 'PresenceStatus')()}`; + const desc = `Your current status group is ${i18n.t( + statusGroup, + 'PresenceStatus', + )()}`; mainWindow.setOverlayIcon(img, desc); logger.info('window-utils: Taskbar Presence Updated'); } diff --git a/src/common/api-interface.ts b/src/common/api-interface.ts index 90f34dfc..d98994cd 100644 --- a/src/common/api-interface.ts +++ b/src/common/api-interface.ts @@ -177,7 +177,8 @@ export interface IThumbarButton { } export interface IStatusBadge extends IBadgeCount { - status: EPresenceStatus; + statusCategory: EPresenceStatusCategory; + statusGroup: EPresenceStatusGroup; } export interface ITray { @@ -189,7 +190,7 @@ export interface IPresenceStore { presenceStatus: IPresenceStatus; } -export enum EPresenceStatus { +export enum EPresenceStatusCategory { 'ONLINE' = 'ONLINE', 'OFFLINE' = 'OFFLINE', 'AWAY' = 'AWAY', @@ -204,9 +205,19 @@ export enum EPresenceStatus { 'NO_PRESENCE' = 'NO_PRESENCE', } +export enum EPresenceStatusGroup { + ONLINE = 'online', + BUSY = 'busy', + IDLE = 'idle', + OFFLINE = 'offline', + ABSENT = 'absent', + MEETING = 'meeting', + HIDE_PRESENCE = 'hide', +} + export interface IPresenceStatus { - category: EPresenceStatus; - statusGroup: string; + statusCategory: EPresenceStatusCategory; + statusGroup: EPresenceStatusGroup; timestamp: number; } diff --git a/src/renderer/ssf-api.ts b/src/renderer/ssf-api.ts index c9ed892e..e91f674a 100644 --- a/src/renderer/ssf-api.ts +++ b/src/renderer/ssf-api.ts @@ -13,7 +13,7 @@ import { apiCmds, apiName, ConfigUpdateType, - EPresenceStatus, + EPresenceStatusCategory, IBoundsChange, ICloud9Pipe, ICPUUsage, @@ -60,7 +60,7 @@ export interface ILocalObject { >; c9PipeEventCallback?: (event: string, arg?: any) => void; c9MessageCallback?: (status: IShellStatus) => void; - updateMyPresenceCallback?: (presence: EPresenceStatus) => void; + updateMyPresenceCallback?: (presence: EPresenceStatusCategory) => void; } const local: ILocalObject = { @@ -374,7 +374,9 @@ export class SSFApi { * It will only trigger if you hit any button at presence-status-handler * */ - public updateMyPresence(callback: (category: EPresenceStatus) => void) { + public updateMyPresence( + callback: (category: EPresenceStatusCategory) => void, + ) { if (typeof callback === 'function') { local.updateMyPresenceCallback = callback; } @@ -932,7 +934,7 @@ local.ipcRenderer.on( local.ipcRenderer.on( 'send-presence-status-data', - (_event: Event, arg: EPresenceStatus) => { + (_event: Event, arg: EPresenceStatusCategory) => { if (typeof local.updateMyPresenceCallback === 'function') { local.updateMyPresenceCallback(arg); } From 907ac3d997e4f291ac324ca16c714cb4090b6cd4 Mon Sep 17 00:00:00 2001 From: sbenmoussati Date: Tue, 7 Mar 2023 16:43:47 +0100 Subject: [PATCH 2/2] simplification --- src/app/main-api-handler.ts | 4 +--- src/app/presence-status-handler.ts | 28 ++++++---------------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/app/main-api-handler.ts b/src/app/main-api-handler.ts index eb91d57c..6e547361 100644 --- a/src/app/main-api-handler.ts +++ b/src/app/main-api-handler.ts @@ -295,10 +295,8 @@ ipcMain.on( // Update App Menu const appMenu = windowHandler.appMenu; const mainWindow = windowHandler.getMainWindow(); - if (mainWebContents) { - const items = presenceStatus.createThumbarButtons(mainWebContents); - + const items = presenceStatus.createThumbarButtons(); mainWindow?.setThumbarButtons(items); logger.info('main-api-handler: Add actions preview menu'); } diff --git a/src/app/presence-status-handler.ts b/src/app/presence-status-handler.ts index 87ee67ec..b3fd6a76 100644 --- a/src/app/presence-status-handler.ts +++ b/src/app/presence-status-handler.ts @@ -1,4 +1,4 @@ -import { app, Menu, nativeImage, WebContents } from 'electron'; +import { app, Menu, nativeImage } from 'electron'; import { EPresenceStatusCategory, EPresenceStatusGroup, @@ -21,9 +21,7 @@ export interface IListItem { class PresenceStatus { private NAMESPACE = 'PresenceStatus'; - public createThumbarButtons = ( - webContents: WebContents, - ): IThumbarButton[] => { + public createThumbarButtons = (): IThumbarButton[] => { return [ { click: () => { @@ -31,7 +29,6 @@ class PresenceStatus { this.handlePresenceChange( EPresenceStatusCategory.AVAILABLE, EPresenceStatusGroup.ONLINE, - webContents, ); }, icon: nativeImage.createFromPath( @@ -48,7 +45,6 @@ class PresenceStatus { this.handlePresenceChange( EPresenceStatusCategory.BUSY, EPresenceStatusGroup.BUSY, - webContents, ); }, icon: nativeImage.createFromPath( @@ -65,7 +61,6 @@ class PresenceStatus { this.handlePresenceChange( EPresenceStatusCategory.BE_RIGHT_BACK, EPresenceStatusGroup.IDLE, - webContents, ); }, icon: nativeImage.createFromPath( @@ -85,7 +80,6 @@ class PresenceStatus { this.handlePresenceChange( EPresenceStatusCategory.OUT_OF_OFFICE, EPresenceStatusGroup.ABSENT, - webContents, ); }, icon: nativeImage.createFromPath( @@ -211,26 +205,16 @@ class PresenceStatus { private handlePresenceChange = ( statusCategory: EPresenceStatusCategory, statusGroup: EPresenceStatusGroup, - webContents?: WebContents, ) => { const status: IPresenceStatus = { statusCategory, statusGroup, timestamp: Date.now(), }; - if (webContents) { - webContents.send('send-presence-status-data', statusCategory); - presenceStatusStore.setPresence(status); - this.updateSystemTrayPresence(); - } else { - presenceStatus.setMyPresence(status); - const mainWebContents = windowHandler.getMainWebContents(); - if (mainWebContents) { - mainWebContents.send( - 'send-presence-status-data', - status.statusCategory, - ); - } + presenceStatus.setMyPresence(status); + const mainWebContents = windowHandler.getMainWebContents(); + if (mainWebContents) { + mainWebContents.send('send-presence-status-data', status.statusCategory); } }; }