Merge pull request #1750 from sbenmoussati/bugfix/presence-update

SDA-4070 IDLE presence status bugfix
This commit is contained in:
NguyenTranHoangSym 2023-03-07 23:25:23 -05:00 committed by GitHub
commit 4537fb3173
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 134 additions and 82 deletions

View File

@ -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');
}

View File

@ -1,6 +1,7 @@
import { app, Menu, nativeImage, WebContents } from 'electron';
import { app, Menu, nativeImage } from 'electron';
import {
EPresenceStatus,
EPresenceStatusCategory,
EPresenceStatusGroup,
IPresenceStatus,
IThumbarButton,
} from '../common/api-interface';
@ -20,70 +21,89 @@ export interface IListItem {
class PresenceStatus {
private NAMESPACE = 'PresenceStatus';
public createThumbarButtons = (
webContents: WebContents,
): IThumbarButton[] => {
public createThumbarButtons = (): IThumbarButton[] => {
return [
{
click: () => {
logger.info('presence-status-handler: Available Clicked');
this.setPresenceStatus(webContents, EPresenceStatus.AVAILABLE);
this.handlePresenceChange(
EPresenceStatusCategory.AVAILABLE,
EPresenceStatusGroup.ONLINE,
);
},
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,
);
},
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,
);
},
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,
);
},
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 +115,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 +131,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 +140,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 +202,21 @@ class PresenceStatus {
tray?.setContextMenu(contextMenu);
};
private handlePresenceChange = (currentStatus: EPresenceStatus) => {
const status = {
category: currentStatus,
statusGroup: '',
private handlePresenceChange = (
statusCategory: EPresenceStatusCategory,
statusGroup: EPresenceStatusGroup,
) => {
const status: IPresenceStatus = {
statusCategory,
statusGroup,
timestamp: Date.now(),
};
presenceStatus.setMyPresence(status);
const mainWebContents = windowHandler.getMainWebContents();
if (mainWebContents) {
mainWebContents.send('send-presence-status-data', currentStatus);
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();

View File

@ -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:

View File

@ -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');
}

View File

@ -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;
}

View File

@ -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);
}