From 55a90754153d0e1780467ea536cb663f9937ae21 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Wed, 13 May 2026 02:07:52 -0400 Subject: [PATCH] Address reviewer follow-ups: powerProfile detect, slider live-value, glyphs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - powerProfile now hides on machines without power-profiles-daemon by checking against the published profile set rather than a never-undefined enum, and uses mdi-scale-balance for Balanced (not battery-charging). - networkPanel renames the QML-keyword-shadowing 'signal' property to 'signalStrength'; ethernet glyph corrected to mdi-ethernet (not the access-point icon). - workspacesPro indicator color guards against null bar during construction. - Common.Slider keeps an internal liveValue so external value bindings survive a drag; sliders fed from PipeWire/brightnessctl now follow external changes after the user interacts. - audioPanel drops the redundant default-sink PwObjectTracker since the candidate-sinks tracker already covers it. - networkPanel guards scan/connect commands against re-entry while the previous Process is running. - notificationCenter only instantiates its NotificationServer when the module is opted in via settings.replaceMako (default off) so it does not collide with mako out of the box. - PopupCard fully opaque while open (previously 0.98) — removes a visible ghost outline on first render. - Drop dead code: calendar trailing MouseArea, weatherFlyout's unused parseForecast/forecast property, idleInhibitor's holdSeconds, media's scrollAnim.position; gate media's scroll animation off in vertical bar mode. --- default/quickshell/bar/common/PopupCard.qml | 2 +- default/quickshell/bar/common/Slider.qml | 16 ++++-- default/quickshell/bar/shell.qml | 3 +- default/quickshell/bar/widgets/audioPanel.qml | 1 - default/quickshell/bar/widgets/calendar.qml | 5 -- .../quickshell/bar/widgets/idleInhibitor.qml | 1 - default/quickshell/bar/widgets/media.qml | 4 +- .../quickshell/bar/widgets/networkPanel.qml | 20 ++++--- .../bar/widgets/notificationCenter.qml | 57 +++++++++++-------- .../quickshell/bar/widgets/powerProfile.qml | 6 +- .../quickshell/bar/widgets/weatherFlyout.qml | 16 ------ .../quickshell/bar/widgets/workspacesPro.qml | 2 +- 12 files changed, 63 insertions(+), 70 deletions(-) diff --git a/default/quickshell/bar/common/PopupCard.qml b/default/quickshell/bar/common/PopupCard.qml index e79ba207..80363341 100644 --- a/default/quickshell/bar/common/PopupCard.qml +++ b/default/quickshell/bar/common/PopupCard.qml @@ -77,7 +77,7 @@ PopupWindow { border.color: root.bar ? root.bar.foreground : "#cacccc" border.width: 1 radius: 0 - opacity: root.open ? 0.98 : 0 + opacity: root.open ? 1.0 : 0 Behavior on opacity { NumberAnimation { duration: 140; easing.type: Easing.OutCubic } diff --git a/default/quickshell/bar/common/Slider.qml b/default/quickshell/bar/common/Slider.qml index 12e6db69..2b3d644c 100644 --- a/default/quickshell/bar/common/Slider.qml +++ b/default/quickshell/bar/common/Slider.qml @@ -14,6 +14,9 @@ Item { property color knobColor: bar ? bar.foreground : "#cacccc" property bool dragging: false property real trackHeight: 4 + property real liveValue: value + + onValueChanged: if (!dragging) liveValue = value signal moved(real value) signal released(real value) @@ -22,7 +25,7 @@ Item { implicitHeight: 22 readonly property real range: Math.max(0.0001, maximum - minimum) - readonly property real progress: Math.max(0, Math.min(1, (value - minimum) / range)) + readonly property real progress: Math.max(0, Math.min(1, (liveValue - minimum) / range)) Rectangle { id: track @@ -87,24 +90,25 @@ Item { onPressed: function(mouse) { root.dragging = true var next = valueFromX(mouse.x) - root.value = next + root.liveValue = next root.moved(next) } onPositionChanged: function(mouse) { if (!root.dragging) return var next = valueFromX(mouse.x) - root.value = next + root.liveValue = next root.moved(next) } onReleased: function(mouse) { root.dragging = false - root.released(root.value) + root.released(root.liveValue) + root.liveValue = root.value } onWheel: function(wheel) { var delta = wheel.angleDelta.y > 0 ? root.step : -root.step - var next = Math.max(root.minimum, Math.min(root.maximum, root.value + delta)) + var next = Math.max(root.minimum, Math.min(root.maximum, root.liveValue + delta)) if (root.integer) next = Math.round(next) - root.value = next + root.liveValue = next root.moved(next) root.released(next) } diff --git a/default/quickshell/bar/shell.qml b/default/quickshell/bar/shell.qml index ec1df123..75e6ed64 100644 --- a/default/quickshell/bar/shell.qml +++ b/default/quickshell/bar/shell.qml @@ -273,7 +273,8 @@ ShellRoot { "workspacesPro": true, "powerMenu": true, "idleInhibitor": true, - "microphone": true + "microphone": true, + "notificationCenter": true }) function firstPartyWidgetSource(name) { diff --git a/default/quickshell/bar/widgets/audioPanel.qml b/default/quickshell/bar/widgets/audioPanel.qml index 63bfc32c..f297eb94 100644 --- a/default/quickshell/bar/widgets/audioPanel.qml +++ b/default/quickshell/bar/widgets/audioPanel.qml @@ -81,7 +81,6 @@ Item { PwObjectTracker { objects: root.candidateSinks } PwObjectTracker { objects: root.candidateStreams } - PwObjectTracker { objects: root.sink ? [root.sink] : [] } Common.WidgetButton { id: button diff --git a/default/quickshell/bar/widgets/calendar.qml b/default/quickshell/bar/widgets/calendar.qml index fb3655bf..c4a55370 100644 --- a/default/quickshell/bar/widgets/calendar.qml +++ b/default/quickshell/bar/widgets/calendar.qml @@ -184,9 +184,4 @@ Item { } } - MouseArea { - anchors.fill: parent - visible: false - enabled: false - } } diff --git a/default/quickshell/bar/widgets/idleInhibitor.qml b/default/quickshell/bar/widgets/idleInhibitor.qml index fc905c0d..56c25a87 100644 --- a/default/quickshell/bar/widgets/idleInhibitor.qml +++ b/default/quickshell/bar/widgets/idleInhibitor.qml @@ -11,7 +11,6 @@ Item { property var settings: ({}) property bool active: false - property int holdSeconds: 0 readonly property string icon: active ? "󰛊" : "󰾪" diff --git a/default/quickshell/bar/widgets/media.qml b/default/quickshell/bar/widgets/media.qml index 88ac0adb..ce1c2d2f 100644 --- a/default/quickshell/bar/widgets/media.qml +++ b/default/quickshell/bar/widgets/media.qml @@ -74,12 +74,10 @@ Item { anchors.verticalCenter: parent.verticalCenter property bool needsScroll: implicitWidth > scrollClip.width - x: needsScroll ? scrollAnim.position : 0 NumberAnimation on x { id: scrollAnim - property real position: 0 - running: labelText.needsScroll && !root.popupOpen + running: labelText.needsScroll && !root.popupOpen && !root.bar.vertical loops: Animation.Infinite duration: Math.max(6000, labelText.implicitWidth * 25) from: scrollClip.width diff --git a/default/quickshell/bar/widgets/networkPanel.qml b/default/quickshell/bar/widgets/networkPanel.qml index 689ad216..743927e0 100644 --- a/default/quickshell/bar/widgets/networkPanel.qml +++ b/default/quickshell/bar/widgets/networkPanel.qml @@ -18,15 +18,15 @@ Item { readonly property string kind: bar ? bar.networkKind : "disconnected" readonly property string label: bar ? bar.networkLabel : "" - readonly property int signal: bar ? bar.networkSignal : -1 + readonly property int signalStrength: bar ? bar.networkSignal : -1 readonly property string icon: { if (kind === "wifi") { var icons = ["󰤯", "󰤟", "󰤢", "󰤥", "󰤨"] - var index = Math.max(0, Math.min(4, Math.ceil(signal / 20) - 1)) + var index = Math.max(0, Math.min(4, Math.ceil(signalStrength / 20) - 1)) return icons[index] } - if (kind === "ethernet") return "󰀂" + if (kind === "ethernet") return "󰈀" return "󰤮" } @@ -48,21 +48,21 @@ Item { list.push({ inUse: parts[0] === "*", ssid: parts[1], - signal: parseInt(parts[2], 10) || 0, + signalStrength: parseInt(parts[2], 10) || 0, security: parts[3] || "" }) } list.sort(function(a, b) { if (a.inUse !== b.inUse) return a.inUse ? -1 : 1 - return b.signal - a.signal + return b.signalStrength - a.signalStrength }) networks = list scanning = false } - function wifiIconFor(signal) { + function wifiIconFor(signalStrength) { var icons = ["󰤯", "󰤟", "󰤢", "󰤥", "󰤨"] - var index = Math.max(0, Math.min(4, Math.ceil(signal / 20) - 1)) + var index = Math.max(0, Math.min(4, Math.ceil(signalStrength / 20) - 1)) return icons[index] } @@ -141,7 +141,7 @@ Item { Text { visible: root.kind !== "disconnected" - text: root.kind === "wifi" ? "Wi-Fi · " + root.signal + "%" : "Ethernet" + text: root.kind === "wifi" ? "Wi-Fi · " + root.signalStrength + "%" : "Ethernet" color: Qt.darker(root.bar.foreground, 1.4) font.family: root.bar.fontFamily font.pixelSize: 10 @@ -155,6 +155,7 @@ Item { verticalPadding: 4 active: root.scanning onClicked: { + if (scanProc.running) return scanProc.command = ["bash", "-lc", "command -v nmcli >/dev/null && nmcli device wifi rescan 2>/dev/null; nmcli -t -f IN-USE,SSID,SIGNAL,SECURITY device wifi list --rescan no 2>/dev/null"] root.refresh() } @@ -178,7 +179,7 @@ Item { required property var modelData width: parent.width - iconText: root.wifiIconFor(modelData.signal) + iconText: root.wifiIconFor(modelData.signalStrength) text: (modelData.ssid || "Hidden") + (modelData.security ? " · " : "") + (modelData.security || "") foreground: root.bar.foreground horizontalPadding: 10 @@ -187,6 +188,7 @@ Item { onClicked: { if (modelData.inUse) return + if (actionProc.running) return actionProc.command = ["bash", "-lc", "command -v nmcli >/dev/null && nmcli device wifi connect " + root.bar.shellQuote(modelData.ssid)] actionProc.running = true root.popupOpen = false diff --git a/default/quickshell/bar/widgets/notificationCenter.qml b/default/quickshell/bar/widgets/notificationCenter.qml index 927ccaec..669894d4 100644 --- a/default/quickshell/bar/widgets/notificationCenter.qml +++ b/default/quickshell/bar/widgets/notificationCenter.qml @@ -23,31 +23,42 @@ Item { return "󰂚" } - NotificationServer { - id: server - keepOnReload: false - bodySupported: true - actionsSupported: true - imageSupported: true + property bool replaceMako: settings && settings.replaceMako === true - onNotification: function(notification) { - if (root.dnd) { - notification.expire() - return + Loader { + active: root.replaceMako + sourceComponent: serverComponent + } + + Component { + id: serverComponent + + NotificationServer { + id: server + keepOnReload: false + bodySupported: true + actionsSupported: true + imageSupported: true + + onNotification: function(notification) { + if (root.dnd) { + notification.expire() + return + } + notification.tracked = true + var snapshot = { + id: notification.id, + app: notification.appName, + summary: notification.summary, + body: notification.body, + time: new Date(), + ref: notification + } + var next = root.stored.slice() + next.unshift(snapshot) + if (next.length > 30) next.pop() + root.stored = next } - notification.tracked = true - var snapshot = { - id: notification.id, - app: notification.appName, - summary: notification.summary, - body: notification.body, - time: new Date(), - ref: notification - } - var next = root.stored.slice() - next.unshift(snapshot) - if (next.length > 30) next.pop() - root.stored = next } } diff --git a/default/quickshell/bar/widgets/powerProfile.qml b/default/quickshell/bar/widgets/powerProfile.qml index 3686ce47..0a37ed46 100644 --- a/default/quickshell/bar/widgets/powerProfile.qml +++ b/default/quickshell/bar/widgets/powerProfile.qml @@ -16,7 +16,7 @@ Item { readonly property var profileGlyphs: ({ [PowerProfile.PowerSaver]: "󰌪", - [PowerProfile.Balanced]: "󰂄", + [PowerProfile.Balanced]: "󰗑", [PowerProfile.Performance]: "󰓅" }) @@ -26,7 +26,7 @@ Item { [PowerProfile.Performance]: "Performance" }) - readonly property bool available: PowerProfiles.profile !== undefined + readonly property bool available: PowerProfiles.hasPerformanceProfile || PowerProfiles.profile === PowerProfile.PowerSaver || PowerProfiles.profile === PowerProfile.Balanced readonly property int current: PowerProfiles.profile visible: available @@ -70,7 +70,7 @@ Item { Repeater { model: [ { profile: PowerProfile.PowerSaver, label: "Power Saver", glyph: "󰌪" }, - { profile: PowerProfile.Balanced, label: "Balanced", glyph: "󰂄" }, + { profile: PowerProfile.Balanced, label: "Balanced", glyph: "󰗑" }, { profile: PowerProfile.Performance, label: "Performance", glyph: "󰓅" } ] diff --git a/default/quickshell/bar/widgets/weatherFlyout.qml b/default/quickshell/bar/widgets/weatherFlyout.qml index 37046a42..9407145f 100644 --- a/default/quickshell/bar/widgets/weatherFlyout.qml +++ b/default/quickshell/bar/widgets/weatherFlyout.qml @@ -13,7 +13,6 @@ Item { property bool popupOpen: false function closePopout() { popupOpen = false } - property var forecast: ({}) property string fullReport: "" readonly property string label: bar ? bar.weatherText : "" @@ -27,21 +26,6 @@ Item { if (!forecastProc.running) forecastProc.running = true } - function parseForecast(text) { - var lines = String(text || "").split("\n") - var data = { location: "", current: "", hourly: [], daily: [] } - var section = "" - - for (var i = 0; i < lines.length; i++) { - var line = lines[i] - if (i === 0 && line.indexOf("Weather report:") === 0) { - data.location = line.replace("Weather report:", "").trim() - } else if (line.match(/^[├└]\s/)) { - section = "daily" - } - } - return data - } Process { id: forecastProc diff --git a/default/quickshell/bar/widgets/workspacesPro.qml b/default/quickshell/bar/widgets/workspacesPro.qml index 521032b8..aa373954 100644 --- a/default/quickshell/bar/widgets/workspacesPro.qml +++ b/default/quickshell/bar/widgets/workspacesPro.qml @@ -36,7 +36,7 @@ Item { width: vertical ? root.slotSize - 8 : root.slotSize - 6 height: vertical ? root.slotSize - 6 : root.slotSize - 8 radius: 4 - color: root.bar.foreground + color: root.bar ? root.bar.foreground : "#cacccc" opacity: root.focusedIndex >= 0 ? 0.25 : 0 x: vertical ? (root.width - width) / 2 : 3 + root.focusedIndex * (root.slotSize + root.spacing) + (root.slotSize - width) / 2 y: vertical ? 3 + root.focusedIndex * (root.slotSize + root.spacing) + (root.slotSize - height) / 2 : (root.height - height) / 2