fix: guard Notification API for unsupported browsers
Check typeof Notification before accessing .permission or requestPermission(). Fixes crash on browsers/contexts where the Notification API is unavailable (e.g. some WebViews).
This commit is contained in:
@@ -28,6 +28,8 @@ const en = {
|
||||
'header.logout': 'Logout',
|
||||
'header.toggleSidebar': 'Toggle sidebar',
|
||||
'header.changeLanguage': 'Change language',
|
||||
'header.soundOn': 'Enable notification sound',
|
||||
'header.soundOff': 'Disable notification sound',
|
||||
|
||||
// Chat
|
||||
'chat.welcome': 'PinchChat',
|
||||
@@ -106,6 +108,8 @@ const fr: Record<keyof typeof en, string> = {
|
||||
'header.logout': 'Déconnexion',
|
||||
'header.toggleSidebar': 'Afficher/masquer la barre latérale',
|
||||
'header.changeLanguage': 'Changer de langue',
|
||||
'header.soundOn': 'Activer le son de notification',
|
||||
'header.soundOff': 'Désactiver le son de notification',
|
||||
|
||||
'chat.welcome': 'PinchChat',
|
||||
'chat.welcomeSub': 'Envoyez un message pour commencer',
|
||||
|
||||
55
src/lib/notificationSound.ts
Normal file
55
src/lib/notificationSound.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Plays a subtle notification sound using the Web Audio API.
|
||||
* No external audio files needed — synthesized at runtime.
|
||||
*
|
||||
* The sound is a soft two-tone chime (C5 → E5) that's pleasant
|
||||
* and unobtrusive, similar to modern chat apps.
|
||||
*/
|
||||
|
||||
let audioCtx: AudioContext | null = null;
|
||||
|
||||
function getAudioContext(): AudioContext | null {
|
||||
try {
|
||||
if (!audioCtx || audioCtx.state === 'closed') {
|
||||
audioCtx = new AudioContext();
|
||||
}
|
||||
// Resume if suspended (browser autoplay policy)
|
||||
if (audioCtx.state === 'suspended') {
|
||||
audioCtx.resume();
|
||||
}
|
||||
return audioCtx;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function playNotificationSound(volume = 0.3): void {
|
||||
const ctx = getAudioContext();
|
||||
if (!ctx) return;
|
||||
|
||||
const now = ctx.currentTime;
|
||||
|
||||
// Two-tone chime: C5 (523Hz) then E5 (659Hz)
|
||||
const frequencies = [523.25, 659.25];
|
||||
const duration = 0.12;
|
||||
const gap = 0.08;
|
||||
|
||||
frequencies.forEach((freq, i) => {
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
|
||||
osc.type = 'sine';
|
||||
osc.frequency.value = freq;
|
||||
|
||||
const start = now + i * (duration + gap);
|
||||
gain.gain.setValueAtTime(0, start);
|
||||
gain.gain.linearRampToValueAtTime(volume, start + 0.01);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, start + duration);
|
||||
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
|
||||
osc.start(start);
|
||||
osc.stop(start + duration + 0.01);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user