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": {
"lastModified": 1759303785,
"narHash": "sha256-EUXrK7pUIzOQWR1dquZh26A6W8lsY2oiHEEZzQnsarM=",
"ref": "refs/heads/master",
"rev": "9662234759eb57f2a1057f2a1c667da1bf128c1c",
"revCount": 686,
"type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
"lastModified": 1759610621,
"narHash": "sha256-P3UPFd95mS/3aNgy40nCXAmyfR2bEEBd+tX6xfkYFb0=",
"rev": "c5c438f1cd1a76660a8658ef929a3d19e968e2ce",
"type": "tarball",
"url": "https://git.outfoxxed.me/api/v1/repos/quickshell/quickshell/archive/c5c438f1cd1a76660a8658ef929a3d19e968e2ce.tar.gz"
},
"original": {
"type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
"type": "tarball",
"url": "https://git.outfoxxed.me/quickshell/quickshell/archive/master.tar.gz"
}
},
"root": {

View file

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

View file

@ -31,7 +31,7 @@ ColumnLayout {
value2: Math.min(1, SystemUsage.gpuTemp / 90)
label2: root.displayTemp(SystemUsage.gpuTemp)
sublabel2: qsTr("Temp")
warning2: value2 > 0.75
warning2: value2 > 0.8
}
Resource {
@ -48,7 +48,7 @@ ColumnLayout {
value2: Math.min(1, SystemUsage.cpuTemp / 90)
label2: root.displayTemp(SystemUsage.cpuTemp)
sublabel2: qsTr("Temp")
warning2: value2 > 0.75
warning2: value2 > 0.8
}
Resource {
@ -107,7 +107,7 @@ ColumnLayout {
Column {
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
CustomText {
@ -131,9 +131,9 @@ ColumnLayout {
anchors.horizontalCenter: parent.right
anchors.top: parent.verticalCenter
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
CustomText {

View file

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

View file

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

View file

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