From 17b606e1be4bda6a73790d1b577422f2edec9c99 Mon Sep 17 00:00:00 2001 From: Laurent Dubertrand Date: Wed, 11 Mar 2026 22:43:32 +0100 Subject: [PATCH] notifications --- client/src/app/chat-page.component.scss | 2 ++ client/src/app/chat-session.service.ts | 40 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/client/src/app/chat-page.component.scss b/client/src/app/chat-page.component.scss index 46372bf..a2cc3d2 100644 --- a/client/src/app/chat-page.component.scss +++ b/client/src/app/chat-page.component.scss @@ -251,6 +251,8 @@ .peer-dropdown-trigger { width: 100%; + padding-top: 0.56rem; + padding-bottom: 0.56rem; } .peer-dropdown-menu { diff --git a/client/src/app/chat-session.service.ts b/client/src/app/chat-session.service.ts index 4cef67b..2a16f2f 100644 --- a/client/src/app/chat-session.service.ts +++ b/client/src/app/chat-session.service.ts @@ -1855,6 +1855,7 @@ export class ChatSessionService { this.incomingVoiceCallPeerId.set(peerId); this.upsertCallMode(this.incomingCallModes, peerId, mode); this.startRingtone(); + this.showIncomingCallNotification(peerId); this.addSystemMessage(peerId, mode === 'video' ? 'Incoming video call.' : 'Incoming audio call.'); } @@ -2729,6 +2730,45 @@ export class ChatSessionService { this.ringtoneAudio.currentTime = 0; } + private showIncomingCallNotification(peerId: string): void { + if (typeof Notification === 'undefined') { + return; + } + + const peerName = this.peers().find((peer) => peer.id === peerId)?.displayName ?? 'A user'; + const body = `${peerName} is calling you with PrivateChat.`; + + const createNotification = () => { + const notification = new Notification('PrivateChat', { + body, + tag: `incoming-call-${peerId}`, + requireInteraction: true, + }); + + notification.onclick = () => { + notification.close(); + window.focus(); + }; + }; + + if (Notification.permission === 'granted') { + createNotification(); + return; + } + + if (Notification.permission !== 'default') { + return; + } + + void Notification.requestPermission().then((permission) => { + if (permission === 'granted') { + createNotification(); + } + }).catch(() => { + // Ignore rejected notification permission requests. + }); + } + private preloadRingtone(): Promise { if (this.ringtonePreloadPromise) { return this.ringtonePreloadPromise;