Compare commits

...

5 commits

Author SHA1 Message Date
6e1fb585e3
tweak(dashboard): adjust performance warning indicator 2025-10-08 22:23:14 -04:00
b9fcb7227b
fix(dashboard): clip notification contents to boundary 2025-10-08 22:23:14 -04:00
a7023aaf45
fix(notifs): fix notification expand animation 2025-10-08 22:23:13 -04:00
a9dab6189d
feat(notifs): handle transient notifications properly
Transient notifications are not persistently shown in the dashboard, and
thus permanently expire after their timer runs out.
2025-10-08 22:23:02 -04:00
3bb5e10d4d
refactor: change quickshell flake URL 2025-10-08 13:05:33 -04:00
6 changed files with 54 additions and 45 deletions

16
flake.lock generated
View file

@ -23,17 +23,15 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1759303785, "lastModified": 1759610621,
"narHash": "sha256-EUXrK7pUIzOQWR1dquZh26A6W8lsY2oiHEEZzQnsarM=", "narHash": "sha256-P3UPFd95mS/3aNgy40nCXAmyfR2bEEBd+tX6xfkYFb0=",
"ref": "refs/heads/master", "rev": "c5c438f1cd1a76660a8658ef929a3d19e968e2ce",
"rev": "9662234759eb57f2a1057f2a1c667da1bf128c1c", "type": "tarball",
"revCount": 686, "url": "https://git.outfoxxed.me/api/v1/repos/quickshell/quickshell/archive/c5c438f1cd1a76660a8658ef929a3d19e968e2ce.tar.gz"
"type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
}, },
"original": { "original": {
"type": "git", "type": "tarball",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell" "url": "https://git.outfoxxed.me/quickshell/quickshell/archive/master.tar.gz"
} }
}, },
"root": { "root": {

View file

@ -5,13 +5,11 @@
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
systems.url = "github:nix-systems/default"; systems.url = "github:nix-systems/default";
quickshell = { quickshell.url = "https://git.outfoxxed.me/quickshell/quickshell/archive/master.tar.gz";
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell"; quickshell.inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = { self, nixpkgs, systems, quickshell, ... } @ inputs: outputs = { self, nixpkgs, systems, quickshell, ... }:
let let
inherit (nixpkgs) lib; inherit (nixpkgs) lib;
eachSystem = lib.genAttrs (import systems); eachSystem = lib.genAttrs (import systems);

View file

@ -31,7 +31,7 @@ ColumnLayout {
value2: Math.min(1, SystemUsage.gpuTemp / 90) value2: Math.min(1, SystemUsage.gpuTemp / 90)
label2: root.displayTemp(SystemUsage.gpuTemp) label2: root.displayTemp(SystemUsage.gpuTemp)
sublabel2: qsTr("Temp") sublabel2: qsTr("Temp")
warning2: value2 > 0.75 warning2: value2 > 0.8
} }
Resource { Resource {
@ -48,7 +48,7 @@ ColumnLayout {
value2: Math.min(1, SystemUsage.cpuTemp / 90) value2: Math.min(1, SystemUsage.cpuTemp / 90)
label2: root.displayTemp(SystemUsage.cpuTemp) label2: root.displayTemp(SystemUsage.cpuTemp)
sublabel2: qsTr("Temp") sublabel2: qsTr("Temp")
warning2: value2 > 0.75 warning2: value2 > 0.8
} }
Resource { Resource {
@ -107,7 +107,7 @@ ColumnLayout {
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent
readonly property color color: res.warning1 ? Config.colors.error : readonly property color color: res.warning1 ? Color.mute(Config.colors.error, 1.3, 1.2) :
res.value1 === 0 ? Config.colors.inactive : Config.colors.primary res.value1 === 0 ? Config.colors.inactive : Config.colors.primary
CustomText { CustomText {
@ -131,9 +131,9 @@ ColumnLayout {
anchors.horizontalCenter: parent.right anchors.horizontalCenter: parent.right
anchors.top: parent.verticalCenter anchors.top: parent.verticalCenter
anchors.horizontalCenterOffset: -res.thickness / 2 anchors.horizontalCenterOffset: -res.thickness / 2
anchors.topMargin: res.thickness / 2 + 7 anchors.topMargin: res.thickness / 2 + 5
readonly property color color: res.warning2 ? Config.colors.error : readonly property color color: res.warning2 ? Color.mute(Config.colors.error, 1.3, 1.2) :
res.value2 === 0 ? Config.colors.inactive : Config.colors.primary res.value2 === 0 ? Config.colors.inactive : Config.colors.primary
CustomText { CustomText {

View file

@ -6,6 +6,7 @@ import qs.services
import qs.util import qs.util
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.modules.notifications as N import qs.modules.notifications as N
@ -17,9 +18,7 @@ ColumnLayout {
spacing: 7 spacing: 7
readonly property int notifCount: readonly property list<Notifs.Notif> list: Notifs.list.filter(n => !n.notification.transient)
(Notifs.list && Notifs.list.length !== undefined) ? Notifs.list.length :
((Notifs.list && Notifs.list.count !== undefined) ? Notifs.list.count : 0)
function notifAt(i) { function notifAt(i) {
if (!Notifs.list) if (!Notifs.list)
@ -47,14 +46,14 @@ ColumnLayout {
text: { text: {
if (Notifs.dnd) if (Notifs.dnd)
return "notifications_off"; return "notifications_off";
if (notifCount > 0) if (root.list.length > 0)
return "notifications_active"; return "notifications_active";
return "notifications"; return "notifications";
} }
fill: { fill: {
if (Notifs.dnd) if (Notifs.dnd)
return 0; return 0;
if (notifCount > 0) if (root.list.length > 0)
return 1; return 1;
return 0; return 0;
} }
@ -75,7 +74,7 @@ ColumnLayout {
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true Layout.fillWidth: true
text: notifCount > 0 ? qsTr("%1 notifications").arg(notifCount) : qsTr("No notifications") text: root.list.length > 0 ? qsTr("%1 notifications").arg(root.list.length) : qsTr("No notifications")
font.weight: 600 font.weight: 600
font.pointSize: Config.font.size.normal font.pointSize: Config.font.size.normal
animate: true animate: true
@ -117,7 +116,7 @@ ColumnLayout {
} }
model: ScriptModel { model: ScriptModel {
values: [...Notifs.list].reverse() values: [...root.list].reverse()
} }
delegate: Item { delegate: Item {
@ -167,12 +166,18 @@ ColumnLayout {
} }
} }
N.Notification { ClippingRectangle {
id: notif anchors.fill: parent
width: parent.width color: "transparent"
notif: wrapper.modelData radius: notif.radius
color: wrapper.modelData.urgency === NotificationUrgency.Critical ? Config.colors.errorBg : Config.colors.containerAlt
inPopup: false N.Notification {
id: notif
width: wrapper.width
notif: wrapper.modelData
color: wrapper.modelData.urgency === NotificationUrgency.Critical ? Config.colors.errorBg : Config.colors.containerAlt
inPopup: false
}
} }
} }
@ -209,8 +214,8 @@ ColumnLayout {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: bottomMargin anchors.bottomMargin: bottomMargin
property real bottomMargin: notifCount > 0 ? 12 : -4 property real bottomMargin: root.list.length > 0 ? 12 : -4
opacity: notifCount > 0 ? 1 : 0 opacity: root.list.length > 0 ? 1 : 0
visible: opacity > 0 visible: opacity > 0
implicitWidth: clearBtn.implicitWidth + 32 implicitWidth: clearBtn.implicitWidth + 32
implicitHeight: clearBtn.implicitHeight + 20 implicitHeight: clearBtn.implicitHeight + 20
@ -230,7 +235,7 @@ ColumnLayout {
anchors.fill: parent anchors.fill: parent
function onClicked(): void { function onClicked(): void {
for (let i = root.notifCount - 1; i >= 0; i--) { for (let i = root.list.length - 1; i >= 0; i--) {
const n = root.notifAt(i); const n = root.notifAt(i);
n?.notification?.dismiss(); n?.notification?.dismiss();
} }

View file

@ -76,7 +76,7 @@ CustomRect {
if (Math.abs(root.x) < Config.notifs.width * Config.notifs.clearThreshold) if (Math.abs(root.x) < Config.notifs.width * Config.notifs.clearThreshold)
root.x = 0; root.x = 0;
else if (root.inPopup) else if (root.inPopup)
root.notif.popup = null; root.notif.clear();
else else
root.notif.notification.dismiss(); root.notif.notification.dismiss();
} }
@ -228,7 +228,7 @@ CustomRect {
anchors.top: parent.top anchors.top: parent.top
anchors.left: image.right anchors.left: image.right
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.topMargin: 2 anchors.topMargin: root.expanded ? 5 : 2
animate: true animate: true
text: summaryPreviewMetrics.elidedText text: summaryPreviewMetrics.elidedText
@ -277,7 +277,7 @@ CustomRect {
anchors.left: image.right anchors.left: image.right
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.topMargin: 5 anchors.topMargin: root.expanded ? 5 : 2
anchors.rightMargin: 10 anchors.rightMargin: 10
animate: true animate: true
@ -370,6 +370,7 @@ CustomRect {
font.pointSize: Config.font.size.small font.pointSize: Config.font.size.small
opacity: root.expanded ? 1 : 0 opacity: root.expanded ? 1 : 0
visible: opacity > 0
Behavior on opacity { Behavior on opacity {
Anim {} Anim {}
@ -467,8 +468,8 @@ CustomRect {
anchors.left: summary.left anchors.left: summary.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: summary.bottom anchors.top: summary.bottom
anchors.rightMargin: 7
anchors.topMargin: 3 anchors.topMargin: 3
anchors.rightMargin: 7
animate: true animate: true
textFormat: Text.MarkdownText textFormat: Text.MarkdownText

View file

@ -45,7 +45,7 @@ Singleton {
description: "Clear all notifications" description: "Clear all notifications"
onPressed: { onPressed: {
for (const notif of root.list) for (const notif of root.list)
notif.popup = null; notif.clear();
} }
} }
@ -93,13 +93,20 @@ Singleton {
// One-line version (for non-expanded notifications) // One-line version (for non-expanded notifications)
readonly property string bodyOneLine: notification.body.replace("\n", " ") readonly property string bodyOneLine: notification.body.replace("\n", " ")
readonly property int expireTimeout: notification.expireTimeout > 0 ?
notification.expireTimeout : Config.notifs.defaultExpireTimeout
readonly property Timer timer: Timer { readonly property Timer timer: Timer {
running: true running: true
interval: notif.notification.expireTimeout > 0 ? notif.notification.expireTimeout : Config.notifs.defaultExpireTimeout interval: notif.expireTimeout
onTriggered: { onTriggered: notif.clear()
if (Config.notifs.expire) }
notif.popup = null;
} function clear(): void {
if (notification.transient)
notification.expire();
else
popup = null;
} }
readonly property Connections conn: Connections { readonly property Connections conn: Connections {