diff --git a/README.md b/README.md index 33eff9f..924edcf 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,6 @@ programs.nova-shell.modules = { power.enable = false; # if you enjoy living dangerously without a logout button lock.enable = false; # if you prefer your session unlocked and your secrets free lock.screenshot = false; # disable blurred desktop screenshot background - lock.notifications = false; # hide notification icons on the lock screen lock.mpris = false; # hide media controls on the lock screen lock.volume = false; # hide volume slider on the lock screen diff --git a/nix/hm-module.nix b/nix/hm-module.nix index d5f5691..8b1879b 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -106,11 +106,6 @@ in default = true; description = "Show blurred desktop screenshot as lock screen background."; }; - notifications = lib.mkOption { - type = lib.types.bool; - default = true; - description = "Show notification app icons on the lock screen."; - }; mpris = lib.mkOption { type = lib.types.bool; default = true; diff --git a/shell/lock/LockSurface.qml b/shell/lock/LockSurface.qml index 0e774b6..b5c8a0f 100644 --- a/shell/lock/LockSurface.qml +++ b/shell/lock/LockSurface.qml @@ -141,74 +141,6 @@ WlSessionLockSurface { } } - // Notification pills - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 6 - visible: (S.Modules.lock.notifications ?? true) && _notifGroups.length > 0 - - readonly property var _notifGroups: { - const notifs = S.NotifService.list.filter(n => n.state !== "dismissed"); - const groups = {}; - for (const n of notifs) { - const key = n.appIcon || n.appName || "unknown"; - if (!groups[key]) - groups[key] = { - icon: n.appIcon, - name: n.appName, - count: 0 - }; - groups[key].count++; - } - return Object.values(groups); - } - - Repeater { - model: parent._notifGroups - - delegate: Rectangle { - required property var modelData - width: _pillRow.implicitWidth + 12 - height: 24 - radius: 12 - color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) - border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) - border.width: 1 - - Row { - id: _pillRow - anchors.centerIn: parent - spacing: 4 - - Image { - anchors.verticalCenter: parent.verticalCenter - width: 14 - height: 14 - source: { - const icon = modelData.icon; - if (!icon) - return ""; - if (icon.startsWith("/")) - return icon; - return Quickshell.iconPath(icon) ?? ""; - } - sourceSize: Qt.size(14, 14) - visible: source !== "" - } - - Text { - anchors.verticalCenter: parent.verticalCenter - text: modelData.count > 1 ? modelData.count.toString() : "" - color: S.Theme.base04 - font.pixelSize: S.Theme.fontSize - 2 - font.family: S.Theme.fontFamily - visible: modelData.count > 1 - } - } - } - } - } - // Spacer Item { width: 1 diff --git a/shell/modules/NotifCenter.qml b/shell/modules/NotifCenter.qml index 27180a8..e49231e 100644 --- a/shell/modules/NotifCenter.qml +++ b/shell/modules/NotifCenter.qml @@ -33,8 +33,8 @@ M.HoverPanel { // DND toggle Text { - text: S.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C" - color: S.NotifService.dnd ? S.Theme.base09 : S.Theme.base04 + text: M.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C" + color: M.NotifService.dnd ? S.Theme.base09 : S.Theme.base04 font.pixelSize: S.Theme.fontSize font.family: S.Theme.iconFontFamily anchors.verticalCenter: parent.verticalCenter @@ -42,7 +42,7 @@ M.HoverPanel { MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: S.NotifService.toggleDnd() + onClicked: M.NotifService.toggleDnd() } } @@ -53,7 +53,7 @@ M.HoverPanel { font.pixelSize: S.Theme.fontSize font.family: S.Theme.iconFontFamily anchors.verticalCenter: parent.verticalCenter - visible: S.NotifService.count > 0 + visible: M.NotifService.count > 0 MouseArea { id: clearArea @@ -88,7 +88,7 @@ M.HoverPanel { // Group notifications by appName, sorted by max urgency desc then most recent time desc readonly property var _groups: { const map = {}; - for (const n of S.NotifService.list) { + for (const n of M.NotifService.list) { const key = n.appName || ""; if (!map[key]) map[key] = { @@ -167,14 +167,14 @@ M.HoverPanel { } function _cascadeDismiss() { - if (S.NotifService.list.length === 0) + if (M.NotifService.list.length === 0) return; - const ids = S.NotifService.list.map(n => n.id); + const ids = M.NotifService.list.map(n => n.id); _startCascade(_getVisibleNotifDelegates(), ids); } function _cascadeGroupDismiss(appName) { - const ids = S.NotifService.list.filter(n => n.appName === appName).map(n => n.id); + const ids = M.NotifService.list.filter(n => n.appName === appName).map(n => n.id); if (ids.length === 0) return; _startCascade(_getVisibleNotifDelegates(appName), ids); @@ -184,7 +184,7 @@ M.HoverPanel { const ids = _pendingDismissIds; _pendingDismissIds = []; for (const id of ids) - S.NotifService.dismiss(id); + M.NotifService.dismiss(id); } property Component _cascadeTimer: Component { @@ -467,7 +467,7 @@ M.HoverPanel { ScriptAction { script: { if (notifDelegate._notif && !notifDelegate._skipDismiss) - S.NotifService.dismiss(notifDelegate._notif.id); + M.NotifService.dismiss(notifDelegate._notif.id); } } } @@ -476,7 +476,7 @@ M.HoverPanel { // Empty state Text { - visible: S.NotifService.count === 0 + visible: M.NotifService.count === 0 width: menuWindow.contentWidth height: 48 horizontalAlignment: Text.AlignHCenter diff --git a/shell/services/NotifItem.qml b/shell/modules/NotifItem.qml similarity index 92% rename from shell/services/NotifItem.qml rename to shell/modules/NotifItem.qml index 488f48a..ac7f4cf 100644 --- a/shell/services/NotifItem.qml +++ b/shell/modules/NotifItem.qml @@ -1,6 +1,7 @@ import QtQuick import Quickshell.Services.Notifications -import "." as S +import "." as M +import "../services" as S QtObject { id: root @@ -31,7 +32,7 @@ QtObject { // Relative time string — recomputed whenever NotifService._now ticks (single global 5s timer) readonly property string timeStr: { - const diff = S.NotifService._now - time; + const diff = M.NotifService._now - time; const m = Math.floor(diff / 60000); if (m < 1) return "now"; @@ -47,7 +48,7 @@ QtObject { target: root.notification function onClosed() { if (root.state !== "dismissed") - S.NotifService.dismiss(root.id); + M.NotifService.dismiss(root.id); } } diff --git a/shell/modules/NotifPopup.qml b/shell/modules/NotifPopup.qml index 25ba8fd..d9a5ffb 100644 --- a/shell/modules/NotifPopup.qml +++ b/shell/modules/NotifPopup.qml @@ -10,7 +10,7 @@ PanelWindow { required property var screen - visible: S.NotifService.popups.length > 0 && !S.NiriIpc.overviewOpen + visible: M.NotifService.popups.length > 0 && !S.NiriIpc.overviewOpen color: "transparent" WlrLayershell.layer: WlrLayer.Overlay @@ -34,7 +34,7 @@ PanelWindow { property var _knownIds: ({}) Repeater { - model: S.NotifService.popups.slice(0, S.Modules.notifications.maxPopups || 4) + model: M.NotifService.popups.slice(0, S.Modules.notifications.maxPopups || 4) delegate: Item { id: popupItem @@ -74,7 +74,7 @@ PanelWindow { } Connections { - target: S.NotifService + target: M.NotifService function onPopupExpiring(notifId) { if (notifId === popupItem.modelData.id) popupItem.animateDismiss(false); @@ -152,7 +152,7 @@ PanelWindow { easing.type: Easing.OutCubic } ScriptAction { - script: popupItem._fullDismiss ? S.NotifService.dismiss(popupItem.modelData.id) : S.NotifService.dismissPopup(popupItem.modelData.id) + script: popupItem._fullDismiss ? M.NotifService.dismiss(popupItem.modelData.id) : M.NotifService.dismissPopup(popupItem.modelData.id) } } diff --git a/shell/services/NotifService.qml b/shell/modules/NotifService.qml similarity index 99% rename from shell/services/NotifService.qml rename to shell/modules/NotifService.qml index e3dde41..fe012d9 100644 --- a/shell/services/NotifService.qml +++ b/shell/modules/NotifService.qml @@ -3,7 +3,8 @@ pragma Singleton import QtQuick import Quickshell import Quickshell.Services.Notifications -import "." as S +import "." as M +import "../services" as S QtObject { id: root diff --git a/shell/modules/NotificationsModule.qml b/shell/modules/NotificationsModule.qml index 4783f44..4aa19bf 100644 --- a/shell/modules/NotificationsModule.qml +++ b/shell/modules/NotificationsModule.qml @@ -8,28 +8,28 @@ M.BarSection { id: root spacing: S.Theme.moduleSpacing tooltip: { - const parts = [S.NotifService.count + " notification" + (S.NotifService.count !== 1 ? "s" : "")]; - if (S.NotifService.dnd) + const parts = [M.NotifService.count + " notification" + (M.NotifService.count !== 1 ? "s" : "")]; + if (M.NotifService.dnd) parts.push("Do not disturb"); return parts.join("\n"); } required property var bar - readonly property bool hasUrgent: S.NotifService.list.some(n => n.urgency === NotificationUrgency.Critical && n.state !== "dismissed") + readonly property bool hasUrgent: M.NotifService.list.some(n => n.urgency === NotificationUrgency.Critical && n.state !== "dismissed") M.BarIcon { icon: { - if (S.NotifService.dnd) - return S.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93"; - return S.NotifService.count > 0 ? "\uDB84\uDD6B" : "\uDB80\uDC9C"; + if (M.NotifService.dnd) + return M.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93"; + return M.NotifService.count > 0 ? "\uDB84\uDD6B" : "\uDB80\uDC9C"; } - color: S.NotifService.dnd ? S.Theme.base04 : root.accentColor + color: M.NotifService.dnd ? S.Theme.base04 : root.accentColor anchors.verticalCenter: parent.verticalCenter } M.BarLabel { id: countLabel - label: S.NotifService.count > 0 ? String(S.NotifService.count) + (root.hasUrgent ? "!" : "") : "" + label: M.NotifService.count > 0 ? String(M.NotifService.count) + (root.hasUrgent ? "!" : "") : "" color: root.hasUrgent ? S.Theme.base08 : root.accentColor anchors.verticalCenter: parent.verticalCenter @@ -61,9 +61,9 @@ M.BarSection { } Connections { - target: S.NotifService + target: M.NotifService function onCountChanged() { - if (S.NotifService.count > 0) + if (M.NotifService.count > 0) popAnim.start(); } } @@ -77,7 +77,7 @@ M.BarSection { } TapHandler { acceptedButtons: Qt.RightButton - onTapped: S.NotifService.toggleDnd() + onTapped: M.NotifService.toggleDnd() } LazyLoader { diff --git a/shell/modules/qmldir b/shell/modules/qmldir index 2ebf8a6..49e65fd 100644 --- a/shell/modules/qmldir +++ b/shell/modules/qmldir @@ -31,6 +31,8 @@ PowerProfileModule 1.0 PowerProfileModule.qml IdleInhibitorModule 1.0 IdleInhibitorModule.qml NotificationsModule 1.0 NotificationsModule.qml ProcessList 1.0 ProcessList.qml +singleton NotifService 1.0 NotifService.qml +NotifItem 1.0 NotifItem.qml NotifPopup 1.0 NotifPopup.qml NotifCenter 1.0 NotifCenter.qml NotifCard 1.0 NotifCard.qml diff --git a/shell/services/Modules.qml b/shell/services/Modules.qml index 20ceede..eab237b 100644 --- a/shell/services/Modules.qml +++ b/shell/services/Modules.qml @@ -95,7 +95,6 @@ QtObject { property var lock: ({ enable: true, screenshot: true, - notifications: true, mpris: true, volume: true }) diff --git a/shell/services/qmldir b/shell/services/qmldir index 62f2550..e411660 100644 --- a/shell/services/qmldir +++ b/shell/services/qmldir @@ -4,5 +4,3 @@ singleton SystemStats 1.0 SystemStats.qml singleton Modules 1.0 Modules.qml singleton NiriIpc 1.0 NiriIpc.qml singleton PowerProfileService 1.0 PowerProfileService.qml -singleton NotifService 1.0 NotifService.qml -NotifItem 1.0 NotifItem.qml