031 — Notification settings in tray
Parent PRD
PRD.md §FR7 (configuration)
What to build
Expose per-source notification toggles in the tray menu, using the NotificationSource interface from 029. Designed to slot into the future settings window (026) without rework.
Tray structure
Settings
├── Displays (existing)
├── Window
│ └── Always on Top (existing)
└── Notifications
└── Timer expired ✓/✗ (toggleable, sourced from TimerExpiredSource::label())
- Toggle reads/writes
NotificationSettings::sources["timer_expired"]
- Persists immediately to
settings.yaml
- Adding a new
NotificationSource implementation automatically appears here — no hardcoded list
Implementation note
The tray submenu builder should iterate registered NotificationSource implementations (or a static list for now) rather than hardcoding menu items. This makes the submenu extensible when new sources are added.
Completion promise
User can enable/disable timer expiry notifications from the tray without editing settings.yaml. The mechanism is generic enough that new notification sources appear automatically.
Acceptance criteria
Blocked by
029 (NotificationSource trait + NotificationSettings in domain)
031 — Notification settings in tray
Parent PRD
PRD.md §FR7 (configuration)
What to build
Expose per-source notification toggles in the tray menu, using the
NotificationSourceinterface from 029. Designed to slot into the future settings window (026) without rework.Tray structure
NotificationSettings::sources["timer_expired"]settings.yamlNotificationSourceimplementation automatically appears here — no hardcoded listImplementation note
The tray submenu builder should iterate registered
NotificationSourceimplementations (or a static list for now) rather than hardcoding menu items. This makes the submenu extensible when new sources are added.Completion promise
User can enable/disable timer expiry notifications from the tray without editing
settings.yaml. The mechanism is generic enough that new notification sources appear automatically.Acceptance criteria
notifications.sources["timer_expired"]valuesettings.yamland takes effect immediately (no restart needed)NotificationSourcerequires no changes to tray menu buildertask checkgreenBlocked by
029 (NotificationSource trait + NotificationSettings in domain)