Send notifications for events that are not announced when window is out of focus.

This commit is contained in:
Storm Dragon
2026-07-28 17:22:24 -04:00
parent 6a94f893b6
commit 9125e76d43
9 changed files with 161 additions and 19 deletions
+2 -2
View File
@@ -224,7 +224,7 @@ function ServerConnection() {
* 'id' is non-null, 'privileged' indicates whether the message was
* sent by an operator.
*
* @type {(this: ServerConnection, id: string, dest: string, username: string, time: Date, privileged: boolean, kind: string, error: string, message: unknown) => void}
* @type {(this: ServerConnection, id: string, dest: string, username: string, time: Date, privileged: boolean, kind: string, error: string, message: unknown, notify: boolean) => void}
*/
this.onusermessage = null;
/**
@@ -517,7 +517,7 @@ ServerConnection.prototype.connect = function(url) {
else if(sc.onusermessage)
sc.onusermessage.call(
sc, m.source, m.dest, m.username, parseTime(m.time),
m.privileged, m.kind, m.error, m.value,
m.privileged, m.kind, m.error, m.value, !!m.notify,
);
break;
case 'ping':
+74 -1
View File
@@ -278,6 +278,56 @@ function notificationSoundsEnabled() {
return !!getSettings().notificationSounds;
}
function browserNotificationsSupported() {
return 'Notification' in window;
}
async function requestBrowserNotificationPermission() {
if(!browserNotificationsSupported()) {
displayWarning('This browser does not support browser notifications.');
return;
}
try {
let permission = await window.Notification.requestPermission();
if(permission === 'granted')
displayMessage('Browser notifications enabled.');
else
displayWarning(
'Browser notifications are blocked. Allow them in your browser site settings.',
);
} catch(e) {
console.error('Could not request browser notification permission:', e);
displayWarning('Could not request browser notification permission.');
}
}
/**
* @param {string} message
*/
function showBrowserNotification(message) {
if(!browserNotificationsSupported() ||
window.Notification.permission !== 'granted')
return;
let focused = typeof document.hasFocus !== 'function' || document.hasFocus();
if(!document.hidden && focused)
return;
let hallName = hallStatus.displayName || capitalise(hall) || 'Hall';
try {
let notification = new window.Notification(`Skald: ${hallName}`, {
body: message,
});
notification.onclick = function() {
window.focus();
notification.close();
};
} catch(e) {
console.error('Could not show browser notification:', e);
}
}
function getNotificationAudioContext() {
if(!notificationSoundsEnabled())
return null;
@@ -1798,6 +1848,26 @@ function userMenu(elt) {
window.open(recordingsUrl(), '_blank', 'noopener');
}});
}
if(browserNotificationsSupported()) {
if(window.Notification.permission === 'default') {
items.push({
label: 'Enable browser notifications',
onClick: requestBrowserNotificationPermission,
});
} else if(window.Notification.permission === 'granted') {
items.push({label: 'Browser notifications enabled', onClick: () => {
displayMessage(
'Timed unlock messages will notify you when this window is not active.',
);
}});
} else {
items.push({label: 'Browser notifications blocked', onClick: () => {
displayWarning(
'Allow browser notifications in your browser site settings.',
);
}});
}
}
if(findUpMedia('audio'))
items.push({label: 'Turn microphone off', onClick: () => {
closeUpMedia('audio');
@@ -2396,8 +2466,9 @@ function gotFileTransferEvent(state, data) {
* @param {string} kind
* @param {string} error
* @param {any} message
* @param {boolean} notify
*/
function gotUserMessage(id, dest, username, time, privileged, kind, error, message) {
function gotUserMessage(id, dest, username, time, privileged, kind, error, message, notify) {
switch(kind) {
case 'kicked':
case 'error':
@@ -2418,6 +2489,8 @@ function gotUserMessage(id, dest, username, time, privileged, kind, error, messa
let text = '' + message;
localMessage(text);
displayMessage(text, false);
if(notify)
showBrowserNotification(text);
break;
}
case 'recording': {