Notification System
RTC Agent includes a lightweight notification system that intelligently triggers sound alerts, Toast popups, and icon animations based on user focus and window state.
Architecture Overview
Section titled “Architecture Overview”NotificationController
Section titled “NotificationController”NotificationController is the core of the notification system. It listens for message events and triggers notifications based on focus detection logic.
Focus Detection
Section titled “Focus Detection”Rules:
| Scenario | Notify? |
|---|---|
| User is in session A, session B receives message | ✅ Notify |
| User is in session A, session A receives message | ❌ Don’t notify |
| User is not viewing any session | ✅ Notify |
| User disabled notifications | ❌ Don’t notify |
State and Actions
Section titled “State and Actions”interface NotificationState { unreadCount: number; // Unread notification count lastNotificationAt: number | null; // Last notification timestamp}
interface NotificationActions { markAsRead(): void; // Mark all notifications as read clearAll(): void; // Clear all notification state}Context Consumption
Section titled “Context Consumption”Get notification state via NotificationContext:
import { consume } from '@lit/context';import { NotificationContext, type NotificationContextValue } from '../contexts/notification.js';
@consume({ context: NotificationContext, subscribe: true })@state()private _notificationCtx: NotificationContextValue;
// Get unread countconst unread = this._notificationCtx.state.unreadCount;
// Mark as readthis._notificationCtx.actions.markAsRead();Sound Notifications
Section titled “Sound Notifications”Sound Files
Section titled “Sound Files”| Sound | File | Trigger | Loading Strategy |
|---|---|---|---|
| Message alert | message.mp3 | New message received | Load immediately |
| Task complete | complete.mp3 | Task execution completed | Deferred loading |
| Error alert | error.mp3 | Error occurred | Deferred loading |
Preloading Mechanism
Section titled “Preloading Mechanism”// NotificationController._preloadSounds()// Critical sound (message) loaded immediatelyconst soundUrls = { message: messageSoundUrl };
// Non-critical sounds loaded with delay (using requestIdleCallback)const deferredSounds = { complete: completeSoundUrl, error: errorSoundUrl,};Sound Configuration
Section titled “Sound Configuration”Control sound toggle through the settings panel:
// SettingsState.notifications.soundEnabledinterface NotificationSettings { soundEnabled: boolean; // Whether sound is enabled toastEnabled: boolean; // Whether Toast is enabled}Browser Autoplay Policy
Section titled “Browser Autoplay Policy”Browsers require user interaction before playing audio. If sound is blocked, the system degrades gracefully:
sound.play().catch((error) => { if (error.name === 'NotAllowedError') { // Browser blocked autoplay, user interaction needed console.warn('[NotificationController] Audio playback blocked by browser'); }});💡 Sound loading failure does not affect Toast and animation functionality.
Toast Notifications
Section titled “Toast Notifications”ToastAction Buttons
Section titled “ToastAction Buttons”Toast notifications support action buttons, allowing users to quickly navigate to the message source:
Toast Configuration:
// NotificationController._showToast()this.toastController?.actions.show( `${title}: ${content}`, // Notification content 'info', // Type { label: msg('View'), // Button text onClick: () => this._navigateToSession(sessionId), // Click callback });Navigation Flow
Section titled “Navigation Flow”After clicking the Toast “View” button:
- Switch to the target session (
sessionController.actions.switchSession()) - Mark notification as read (
actions.markAsRead()) - Dispatch
rtc-notification-clickevent (carryingsessionId)
Minimized Bubble Animation
Section titled “Minimized Bubble Animation”When the window is in minimized mode, new messages trigger the bubble icon animation:
Animation Implementation
Section titled “Animation Implementation”Control animation via CSS data-notification attribute:
// NotificationController._animateMinimizeIcon()this.host.setAttribute('data-notification', 'active');// Animation persists until user expands window or clicks bubble
// Clear animationthis.host.removeAttribute('data-notification');Visual Style
Section titled “Visual Style”| Property | Value |
|---|---|
| Shape | Rounded square (border-radius: 23.2%) |
| Color | Orange → Yellow pulse |
| Animation | Continuous pulse until user interaction |
Restoring from Minimized
Section titled “Restoring from Minimized”When restoring from minimized, notification state is automatically cleared:
// RtcAgent._handleModeTransition()if (this._appliedMode === 'minimized' && mode !== 'minimized') { this._notification.actions.markAsRead();}Events
Section titled “Events”rtc-notification-click
Section titled “rtc-notification-click”Triggered when user clicks the Toast “View” button:
interface NotificationClickDetail { sessionId: string; // Target session ID}
agent.addEventListener('rtc-notification-click', (e: CustomEvent<NotificationClickDetail>) => { console.log('User navigated to session:', e.detail.sessionId);});Keyboard Accessibility
Section titled “Keyboard Accessibility”The notification system supports full keyboard interaction:
| Key | Behavior |
|---|---|
Tab | Switch focus between Toast buttons |
Enter / Space | Activate Toast action button |
Esc | Close current Toast |
Toast components use role="alert" and aria-live="polite" to ensure screen readers announce correctly.
Throttling Mechanism
Section titled “Throttling Mechanism”To prevent UI lag from rapid consecutive messages, the notification system implements throttling:
private static readonly NOTIFY_THROTTLE_MS = 300;
private async _handleNewMessage(event: UIUpdateEvent) { const now = Date.now(); if (now - this._lastNotifyTime < NotificationController.NOTIFY_THROTTLE_MS) { return; // Throttled: skip } this._lastNotifyTime = now; // ... trigger notification}Parameters:
| Parameter | Value | Description |
|---|---|---|
NOTIFY_THROTTLE_MS | 300ms | Minimum interval between two notifications |
Configuration Example
Section titled “Configuration Example”Full Configuration
Section titled “Full Configuration”const agent = document.querySelector('rtc-agent');
agent.addEventListener('rtc-agent-ready', () => { // Configure notifications via SettingsController // Note: Settings are typically adjusted by users in the settings panel // This shows programmatic configuration
// Listen for notification events agent.addEventListener('rtc-notification-click', (e) => { console.log('Notification clicked:', e.detail.sessionId); });});Disabling Notifications
Section titled “Disabling Notifications”/* Hide Toast via CSS */rtc-agent { --rtc-toast-display: none;}Or toggle in the settings panel:
- Turn off “Enable sound” → Disable sound effects
- Turn off “Enable Toast” → Disable Toast popups
Next Steps
Section titled “Next Steps”- Settings System — Learn about the global settings system
- Component API — Learn about the full component API