Give Sound the whole story, and keep the buttons inside the card

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 11:39:16 -04:00
parent 9bc68ba358
commit b58371bb35
38 changed files with 3884 additions and 213 deletions
+35
View File
@@ -15,6 +15,7 @@ pragma Singleton
// ─────────────────────────────────────────────────────────────────────────────
import Quickshell
import Quickshell.Io
import Quickshell.Services.Notifications
import QtQuick
import qs.config
@@ -232,6 +233,7 @@ Singleton {
// because FocusModes.allows is false whenever no mode is active.
if (!root.doNotDisturb || FocusModes.allows(root.notificationAppId(notification))) {
root.popups = [notification].concat(root.popups);
root.playBell(notification);
} else if (notification.transient) {
// Never shown, and (being transient) never filed in history
// either — nothing will otherwise dismiss() it, so schedule
@@ -240,6 +242,39 @@ Singleton {
}
}
// ── The chime ───────────────────────────────────────────────────────────
//
// A notification you can hear. GTK applications get this from libcanberra
// for free; Panama's own popups had no sound at all, so a notification that
// arrived while you were looking elsewhere simply did not happen. Same
// theme, same desktop preference: one switch covers the whole session
// rather than leaving Panama as the one thing that stays quiet -- or the
// one thing that will not shut up.
//
// Throttled to one bell a second. A burst -- a chat catching up after a
// suspend, ten build jobs finishing together -- would otherwise stack a
// dozen overlapping bells, which is a noise rather than a notification.
property real lastBellAt: 0
function playBell(notification: var): void {
if (!SoundFeedback.eventSounds)
return;
// Low urgency is the "you did not need to know this" tier -- battery
// reaching full, a sync completing. It stays silent by design.
if (notification.urgency === NotificationUrgency.Low)
return;
const now = Date.now();
if (bell.running || now - root.lastBellAt < 1000)
return;
root.lastBellAt = now;
bell.command = SoundFeedback.bellCommand;
bell.running = true;
}
Process { id: bell }
// Runs a DND-hidden transient notification through the same lifetime it
// would have gotten as a visible popup (Toast.qml's countdown), just
// without ever showing it, so it still gets released instead of staying