Skip to content

Commit

Permalink
SDA-4675 - Add sequential function queue for showing notification (#2207
Browse files Browse the repository at this point in the history
)

* SDA-4675 - Add sequential function queue for showing notification

* SDA-4675 - Add delay for notification position animation
  • Loading branch information
KiranNiranjan authored Sep 30, 2024
1 parent ba8358c commit 9558aa1
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 39 deletions.
48 changes: 48 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
};
35 changes: 19 additions & 16 deletions src/renderer/notification-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,26 +429,29 @@ export default class NotificationHandler {
newX: number,
) {
const [startX, startY] = notificationWindow.getPosition();
const stepY = (newY - startY) / this.settings.animationSteps;
const stepX = (newX - startX) / this.settings.animationSteps;
const duration = this.settings.animationSteps;
const startTime = Date.now();

let curStep = 1;
const animationInterval = setInterval(() => {
// Abort condition
if (curStep === this.settings.animationSteps) {
const animateStep = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);

const currentX = startX + (newX - startX) * progress;
const currentY = startY + (newY - startY) * progress;

// Set new position
this.setWindowPosition(notificationWindow, currentX, currentY);

if (progress < 1) {
setTimeout(animateStep, 16);
} else {
// Ensure final position is set
this.setWindowPosition(notificationWindow, newX, newY);
clearInterval(animationInterval);
return;
}
};

// Move one step in both x and y directions
this.setWindowPosition(
notificationWindow,
startX + curStep * stepX,
startY + curStep * stepY,
);
curStep++;
}, this.settings.animationStepMs);
// Start the animation
setTimeout(animateStep, 16);
}

/**
Expand Down
6 changes: 0 additions & 6 deletions src/renderer/notification.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { app, BrowserWindow, ipcMain } from 'electron';
import * as debounce from 'lodash.debounce';

import { analytics } from '../app/bi/analytics-handler';
import {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 (
Expand Down
43 changes: 26 additions & 17 deletions src/renderer/ssf-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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,
});
});
}

Expand Down

0 comments on commit 9558aa1

Please sign in to comment.