diff --git a/src/common/utils.ts b/src/common/utils.ts index 6cf45ce4f..7cac9f4d0 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -349,3 +349,51 @@ export class DelayedFunctionQueue { } } } +export interface IFunctionQueue { + enqueue: (fn: () => void) => void; +} + +/** + * Creates a function queue that executes functions sequentially with a specified interval. + * + * @param {number} interval - The interval (in milliseconds) between function executions. + * @returns {IFunctionQueue} - An object representing the function queue. + */ +export const createSequentialFunctionQueue = ( + interval: number, +): IFunctionQueue => { + const queue: Array<() => void> = []; + let isProcessing: boolean = false; + + // Enqueue a function call + const enqueue = (fn: () => void): void => { + queue.push(fn); + processQueue(); + }; + + // Process the queue + const processQueue = (): void => { + if (isProcessing) { + return; + } + isProcessing = true; + + const processNext = (): void => { + if (queue.length === 0) { + isProcessing = false; + return; + } + const fn = queue.shift(); + if (fn) { + fn(); + } + // Schedule the next function execution after the interval + setTimeout(() => { + processNext(); + }, interval); + }; + processNext(); + }; + + return { enqueue }; +}; diff --git a/src/renderer/notification.ts b/src/renderer/notification.ts index 3ea94a310..8b5b2f00f 100644 --- a/src/renderer/notification.ts +++ b/src/renderer/notification.ts @@ -1,5 +1,4 @@ import { app, BrowserWindow, ipcMain } from 'electron'; -import * as debounce from 'lodash.debounce'; import { analytics } from '../app/bi/analytics-handler'; import { @@ -30,7 +29,6 @@ const animationQueue = new AnimationQueue(); const CONTAINER_HEIGHT = 104; // Notification container height const CONTAINER_HEIGHT_WITH_INPUT = 146; // Notification container height including input field const CONTAINER_WIDTH = 363; -const DEBOUNCE_DELAY = 50; interface ICustomBrowserWindow extends Electron.BrowserWindow { winName: string; notificationData: INotificationData; @@ -85,10 +83,6 @@ class Notification extends NotificationHandler { constructor(opts) { super(opts); - this.hideNotification = debounce( - this.hideNotification.bind(this), - DEBOUNCE_DELAY, - ); ipcMain.on('close-notification', (_event, windowId) => { const browserWindow = this.getNotificationWindow(windowId); if ( diff --git a/src/renderer/ssf-api.ts b/src/renderer/ssf-api.ts index 7b70e095e..370e54395 100644 --- a/src/renderer/ssf-api.ts +++ b/src/renderer/ssf-api.ts @@ -35,7 +35,11 @@ import { PhoneNumberProtocol, } from '../common/api-interface'; import { i18n, LocaleType } from '../common/i18n-preload'; -import { DelayedFunctionQueue, throttle } from '../common/utils'; +import { + createSequentialFunctionQueue, + DelayedFunctionQueue, + throttle, +} from '../common/utils'; import { getSource } from './desktop-capturer'; import SSFNotificationHandler from './notification-ssf-handler'; import { ScreenSnippetBcHandler } from './screen-snippet-bc-handler'; @@ -86,6 +90,9 @@ const callNotificationActionCallbacks = new Map< >(); const DEFAULT_THROTTLE = 1000; +const NOTIFICATION_DELAY = 500; + +const notificationQueue = createSequentialFunctionQueue(NOTIFICATION_DELAY); // Throttle func const throttledSetBadgeCount = throttle((count) => { @@ -712,22 +719,24 @@ export class SSFApi { notificationOpts: INotificationData, notificationCallback: NotificationActionCallback, ): void { - // Store callbacks based on notification id so, - // we can use this to trigger on notification action - if (typeof notificationOpts.id === 'number') { - notificationActionCallbacks.set( - notificationOpts.id, - notificationCallback, - ); - } - // ipc does not support sending Functions, Promises, Symbols, WeakMaps, - // or WeakSets will throw an exception - if (notificationOpts.callback) { - delete notificationOpts.callback; - } - ipcRenderer.send(apiName.symphonyApi, { - cmd: apiCmds.showNotification, - notificationOpts, + notificationQueue.enqueue(() => { + // Store callbacks based on notification id so, + // we can use this to trigger on notification action + if (typeof notificationOpts.id === 'number') { + notificationActionCallbacks.set( + notificationOpts.id, + notificationCallback, + ); + } + // ipc does not support sending Functions, Promises, Symbols, WeakMaps, + // or WeakSets will throw an exception + if (notificationOpts.callback) { + delete notificationOpts.callback; + } + ipcRenderer.send(apiName.symphonyApi, { + cmd: apiCmds.showNotification, + notificationOpts, + }); }); }