quickshell: round album art, full-width notifications with app icon + image preview

- album art uses ClippingRectangle so the image follows the radius
- NotifContent gains an app icon + name header
- notifications move to a full-width card spanning both panes, each item
  showing the notification image preview when present

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
rope 2026-06-17 14:56:49 +01:00
parent c901b9b56d
commit f0193eedd3

View file

@ -475,6 +475,29 @@ in
signal actionInvoked() signal actionInvoked()
spacing: 2 spacing: 2
// App header: icon + name of the sending app, when known.
Row {
width: parent.width
spacing: 4
visible: _nc.notif && (_nc.notif.appName !== "" || _appIcon.source != "")
Image {
id: _appIcon
width: 14; height: 14
sourceSize.width: 14; sourceSize.height: 14
anchors.verticalCenter: parent.verticalCenter
source: _nc.notif && _nc.notif.appIcon ? Quickshell.iconPath(_nc.notif.appIcon, true) : ""
visible: source != ""
}
SText {
anchors.verticalCenter: parent.verticalCenter
text: _nc.notif ? _nc.notif.appName : ""
color: Theme.base04
font.pixelSize: 10
elide: Text.ElideRight
width: parent.width - (_appIcon.visible ? 18 : 0)
}
}
SText { SText {
width: parent.width width: parent.width
text: _nc.notif ? (_nc.notif.summary || _nc.notif.appName) : "" text: _nc.notif ? (_nc.notif.summary || _nc.notif.appName) : ""
@ -2145,7 +2168,7 @@ in
// ceil: Text metrics give fractional sizes; fractional rect // ceil: Text metrics give fractional sizes; fractional rect
// edges render as soft 2px lines // edges render as soft 2px lines
fullWidth: Math.ceil(calRow.width) + 24 fullWidth: Math.ceil(calRow.width) + 24
fullHeight: Math.ceil(calRow.height) + 24 fullHeight: Math.ceil(calRow.height + 8 + notifCard.height) + 24
// Month being viewed; reset to today when the popup opens // Month being viewed; reset to today when the popup opens
// (via the setup function passed to bar.toggleDropdown). // (via the setup function passed to bar.toggleDropdown).
@ -2430,12 +2453,11 @@ in
width: parent.width width: parent.width
spacing: 12 spacing: 12
Rectangle { ClippingRectangle {
width: 128; height: 128 width: 128; height: 128
radius: Theme.radiusSmall radius: Theme.radiusSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: Theme.base02 color: Theme.base02
clip: true
SIcon { SIcon {
anchors.centerIn: parent anchors.centerIn: parent
visible: albumArt.status !== Image.Ready visible: albumArt.status !== Image.Ready
@ -2548,85 +2570,106 @@ in
} }
} }
// Notifications card }
Card { }
// Notifications: spans both columns, below the panes
Card {
id: notifCard
anchors.top: calRow.bottom
anchors.topMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
width: calRow.width
opacity: calRow.opacity
cardSpacing: 6
Item {
width: parent.width
height: 20
SText {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: "Notifications"
font.weight: Font.Medium
}
SText {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: bar.notifServer.trackedNotifications.values.length > 0 ? "Clear all" : ""
color: Theme.base04
font.pixelSize: 11
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
let notifs = bar.notifServer.trackedNotifications.values;
for (let i = notifs.length - 1; i >= 0; i--) {
notifs[i].dismiss();
}
}
}
}
}
SText {
visible: bar.notifServer.trackedNotifications.values.length === 0
text: "No notifications"
color: Theme.base03
font.pixelSize: 11
anchors.horizontalCenter: parent.horizontalCenter
}
Repeater {
model: bar.notifServer.trackedNotifications
Rectangle {
id: notifItem
required property var modelData
width: parent.width width: parent.width
cardSpacing: 6 height: Math.max(notifPreview.visible ? 48 : 0, ncBody.height) + 16
radius: Theme.radiusSmall
color: Theme.base02
Item { // Image preview (album art, screenshot thumb)
width: parent.width ClippingRectangle {
height: 20 id: notifPreview
visible: notifItem.modelData.image != ""
SText { anchors.left: parent.left
anchors.left: parent.left anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter anchors.margins: 8
text: "Notifications" width: 48; height: 48
font.weight: Font.Medium radius: Theme.radiusTiny
} color: Theme.base01
Image {
SText { anchors.fill: parent
anchors.right: parent.right fillMode: Image.PreserveAspectCrop
anchors.verticalCenter: parent.verticalCenter source: notifItem.modelData.image
text: bar.notifServer.trackedNotifications.values.length > 0 ? "Clear all" : ""
color: Theme.base04
font.pixelSize: 11
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
let notifs = bar.notifServer.trackedNotifications.values;
for (let i = notifs.length - 1; i >= 0; i--) {
notifs[i].dismiss();
}
}
}
} }
} }
SText { NotifContent {
visible: bar.notifServer.trackedNotifications.values.length === 0 id: ncBody
text: "No notifications" notif: notifItem.modelData
color: Theme.base03 anchors.left: notifPreview.visible ? notifPreview.right : parent.left
font.pixelSize: 11 anchors.right: dismissBtn.left
anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top
anchors.margins: 8
} }
Repeater { SIcon {
model: bar.notifServer.trackedNotifications id: dismissBtn
anchors.right: parent.right
Rectangle { anchors.top: parent.top
id: notifItem anchors.margins: 8
required property var modelData text: "close"
width: parent.width color: dismissMa.containsMouse ? Theme.base05 : Theme.base03
height: ncBody.height + 16 font.pixelSize: 15
radius: Theme.radiusSmall MouseArea {
color: Theme.base02 id: dismissMa
anchors.fill: parent
NotifContent { hoverEnabled: true
id: ncBody cursorShape: Qt.PointingHandCursor
notif: notifItem.modelData onClicked: notifItem.modelData.dismiss()
anchors.left: parent.left
anchors.right: dismissBtn.left
anchors.top: parent.top
anchors.margins: 8
}
SIcon {
id: dismissBtn
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 8
text: "close"
color: dismissMa.containsMouse ? Theme.base05 : Theme.base03
font.pixelSize: 15
MouseArea {
id: dismissMa
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: notifItem.modelData.dismiss()
}
}
} }
} }
} }