Notifications: Group multiple push notifications (#1209)

This commit is contained in:
Alexander Zinchuk 2021-06-27 19:09:18 +03:00
parent 21dc993463
commit c218e38abc
2 changed files with 53 additions and 10 deletions

View File

@ -45,7 +45,6 @@ self.addEventListener('fetch', (e: FetchEvent) => {
})());
});
self.addEventListener('push', handlePush);
self.addEventListener('notificationclick', handleNotificationClick);
self.addEventListener('message', handleClientMessage);

View File

@ -1,4 +1,5 @@
import { APP_NAME, DEBUG } from '../config';
import { debounce } from '../util/schedulers';
declare const self: ServiceWorkerGlobalScope;
@ -32,6 +33,7 @@ type NotificationData = {
const clickBuffer: Record<string, NotificationData> = {};
const shownNotifications = new Set();
let pendingNotifications: Record<number, NotificationData[]> = {};
function getPushData(e: PushEvent | Notification): PushData | undefined {
try {
@ -91,6 +93,55 @@ function showNotification({
});
}
async function showNotifications(groupLimit: number = 1) {
const count = Object.keys(pendingNotifications).reduce<number>((result, groupId) => {
result += pendingNotifications[Number(groupId)].length;
return result;
}, 0);
// if we have more than groupLimit notification groups we send only one notification
if (Object.keys(pendingNotifications).length > groupLimit) {
await showNotification({
title: APP_NAME,
body: `You have ${count} new Telegram notifications`,
});
} else {
// Else we send a notification per group
await Promise.all(Object.keys(pendingNotifications)
// eslint-disable-next-line no-async-without-await/no-async-without-await
.map(async (groupId) => {
const group = pendingNotifications[Number(groupId)];
if (group.length > groupLimit) {
return showNotification({
title: APP_NAME,
body: `You have ${count} notifications from ${group[0].title}`,
chatId: Number(groupId),
});
}
return Promise.all(group.map(showNotification));
}));
}
// Clear all pending notifications
pendingNotifications = {};
}
const flushNotifications = debounce(showNotifications, 1000, false);
async function handleNotification(notification: NotificationData, groupLimit?: number) {
// Dont show already triggered notification
if (shownNotifications.has(notification.messageId)) {
shownNotifications.delete(notification.messageId);
return;
}
const groupId = notification.chatId || 0;
if (!pendingNotifications[groupId]) {
pendingNotifications[groupId] = [];
}
pendingNotifications[groupId].push(notification);
await flushNotifications(groupLimit);
}
export function handlePush(e: PushEvent) {
if (DEBUG) {
// eslint-disable-next-line no-console
@ -106,14 +157,7 @@ export function handlePush(e: PushEvent) {
if (!data || data.mute === Boolean.True) return;
const notification = getNotificationData(data);
// Dont show already triggered notification
if (shownNotifications.has(notification.messageId)) {
shownNotifications.delete(notification.messageId);
return;
}
e.waitUntil(showNotification(notification));
e.waitUntil(handleNotification(notification));
}
async function focusChatMessage(client: WindowClient, data: { chatId?: number; messageId?: number }) {
@ -181,7 +225,7 @@ export function handleClientMessage(e: ExtendableMessageEvent) {
if (e.data.type === 'newMessageNotification') {
// store messageId for already shown notification
const notification: NotificationData = e.data.payload;
e.waitUntil(showNotification(notification));
e.waitUntil(handleNotification(notification, 3));
shownNotifications.add(notification.messageId);
}
}