From 0439d017b91ef22c9fabf44afbb8cded5864b4cc Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 9 Jul 2026 12:00:15 -0400 Subject: [PATCH] fix(notifications): handle sound-name hint --- .../DankDash/Overview/CalendarEventDetail.qml | 53 ++++++++++++++++++- quickshell/Services/CalendarDankBackend.qml | 1 + quickshell/Services/NotificationService.qml | 10 ++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/quickshell/Modules/DankDash/Overview/CalendarEventDetail.qml b/quickshell/Modules/DankDash/Overview/CalendarEventDetail.qml index 6c85ac779..f7f327003 100644 --- a/quickshell/Modules/DankDash/Overview/CalendarEventDetail.qml +++ b/quickshell/Modules/DankDash/Overview/CalendarEventDetail.qml @@ -18,6 +18,17 @@ Item { readonly property bool _descriptionIsHtml: /<[a-z][^>]*>/i.test((eventData && eventData.description) || "") + // _locationUrl returns the location when it is nothing but a URL so the + // row can open it; links inside a street address surface as meetingUrl. + function _locationUrl() { + const loc = ((eventData && eventData.location) || "").trim(); + if (/^https?:\/\/\S+$/i.test(loc)) + return loc; + if (/^www\.\S+$/i.test(loc)) + return "https://" + loc; + return ""; + } + function _styleAnchors(html) { return html.replace(/]*)>/gi, (m, attrs) => { const cleaned = attrs.replace(/style="[^"]*"/gi, ""); @@ -214,7 +225,7 @@ Item { DankIcon { name: "place" size: 14 - color: Theme.surfaceVariantText + color: root._locationUrl() !== "" ? Theme.primary : Theme.surfaceVariantText anchors.top: parent.top anchors.topMargin: 2 } @@ -223,10 +234,48 @@ Item { width: parent.width - 14 - Theme.spacingXS text: root.eventData ? root.eventData.location : "" font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText + color: root._locationUrl() !== "" ? Theme.primary : Theme.surfaceVariantText wrapMode: Text.Wrap maximumLineCount: 2 elide: Text.ElideRight + + MouseArea { + anchors.fill: parent + enabled: root._locationUrl() !== "" + cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor + onClicked: Qt.openUrlExternally(root._locationUrl()) + } + } + } + + Row { + width: parent.width + spacing: Theme.spacingXS + visible: root.eventData && root.eventData.meetingUrl + + DankIcon { + name: "videocam" + size: 14 + color: Theme.primary + anchors.top: parent.top + anchors.topMargin: 2 + } + + StyledText { + width: parent.width - 14 - Theme.spacingXS + text: I18n.tr("Join video call") + font.pixelSize: Theme.fontSizeSmall + color: Theme.primary + elide: Text.ElideRight + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + if (root.eventData && root.eventData.meetingUrl) + Qt.openUrlExternally(root.eventData.meetingUrl); + } + } } } diff --git a/quickshell/Services/CalendarDankBackend.qml b/quickshell/Services/CalendarDankBackend.qml index bbea820cc..e70e3d089 100644 --- a/quickshell/Services/CalendarDankBackend.qml +++ b/quickshell/Services/CalendarDankBackend.qml @@ -380,6 +380,7 @@ Item { "description": e.description || "", "location": e.location || "", "url": e.url || "", + "meetingUrl": e.meetingUrl || "", "start": allDay ? _dayBoundary(e.start) : new Date(e.start), "end": allDay ? _dayBoundary(e.end) : new Date(e.end), "allDay": allDay, diff --git a/quickshell/Services/NotificationService.qml b/quickshell/Services/NotificationService.qml index 7ef3d4134..8c0135dd5 100644 --- a/quickshell/Services/NotificationService.qml +++ b/quickshell/Services/NotificationService.qml @@ -700,9 +700,13 @@ Singleton { // Honor the freedesktop "suppress-sound" hint: the sender // plays its own audio for this notification and asks the - // server not to double up. - const suppressSound = !!(notif.hints && notif.hints["suppress-sound"]); - if (SettingsData.soundsEnabled && SettingsData.soundNewNotification && !suppressSound) { + // server not to double up. "sound-name" is the opposite — an + // explicit request for audio — so it plays even when the + // global new-notification sound is off. + const soundHints = notif.hints || {}; + const suppressSound = !!soundHints["suppress-sound"]; + const requestsSound = !!soundHints["sound-name"]; + if (SettingsData.soundsEnabled && (SettingsData.soundNewNotification || requestsSound) && !suppressSound) { if (policy.urgency === NotificationUrgency.Critical) { AudioService.playCriticalNotificationSound(); } else {