From 6fd36c812fa4963af268a3a07996bc242c2b368c Mon Sep 17 00:00:00 2001 From: Damocles Date: Sat, 25 Apr 2026 14:07:26 +0200 Subject: [PATCH] barmodule: own hoverpanel internally, modules supply content as component --- shell/modules/BacklightModule.qml | 30 +++---- shell/modules/BarModule.qml | 42 +++++++++- shell/modules/BatteryModule.qml | 28 +++---- shell/modules/BluetoothModule.qml | 102 +++++++++++------------ shell/modules/ClockModule.qml | 28 +++---- shell/modules/CpuModule.qml | 38 ++++----- shell/modules/DiskModule.qml | 28 +++---- shell/modules/GpuModule.qml | 28 +++---- shell/modules/MemoryModule.qml | 64 +++++++-------- shell/modules/MprisModule.qml | 46 +++++------ shell/modules/NetworkModule.qml | 102 +++++++++++------------ shell/modules/NotificationsModule.qml | 112 +++++++++++++------------- shell/modules/PowerModule.qml | 36 ++++----- shell/modules/TemperatureModule.qml | 40 ++++----- shell/modules/VolumeModule.qml | 32 +++----- shell/modules/WeatherModule.qml | 28 +++---- test/qmllint-baseline.txt | 36 ++++----- 17 files changed, 367 insertions(+), 453 deletions(-) diff --git a/shell/modules/BacklightModule.qml b/shell/modules/BacklightModule.qml index 5a531d6..4f99b64 100644 --- a/shell/modules/BacklightModule.qml +++ b/shell/modules/BacklightModule.qml @@ -10,6 +10,17 @@ M.BarModule { opacity: S.Modules.backlight.enable && S.BacklightService.available ? 1 : 0 visible: opacity > 0 tooltip: "Brightness: " + percent + "%" + panelNamespace: "nova-backlight" + panelTitle: "Brightness" + panelContentWidth: 200 + panelComponent: Component { + C.BacklightApplet { + width: parent.width + percent: root.percent + accentColor: root.accentColor + onSetPercent: pct => S.BacklightService.setPercent(pct) + } + } property int percent: S.BacklightService.percent property bool _percentInit: false @@ -36,23 +47,4 @@ M.BarModule { minText: "100%" anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-backlight" - panelTitle: "Brightness" - contentWidth: 200 - onDismissed: root.dismissPanel() - - C.BacklightApplet { - width: parent.width - percent: root.percent - accentColor: root.accentColor - onSetPercent: pct => S.BacklightService.setPercent(pct) - } - } } diff --git a/shell/modules/BarModule.qml b/shell/modules/BarModule.qml index 8915880..0da9b8e 100644 --- a/shell/modules/BarModule.qml +++ b/shell/modules/BarModule.qml @@ -9,10 +9,9 @@ import "../services" as S // On tap: toggles _panelOpen and emits tapped(). Modules that want custom tap // behavior connect onTapped to their action (the toggle still happens). // -// Modules with a HoverPanel bind: -// M.HoverPanel { showPanel: root._showPanel; onDismissed: root.dismissPanel() } -// -// Modules without a panel need nothing - the toggle is a harmless no-op. +// Panel modules set panelComponent + panel config properties. BarModule owns the +// HoverPanel internally - modules never interact with it directly. +// For content resize grace, call keepPanelOpen(ms). Row { id: root property string tooltip: "" @@ -25,6 +24,13 @@ Row { property bool _osdActive: false readonly property bool _showPanel: _panelOpen || _osdActive + // Panel configuration - set by modules that have applets + property Component panelComponent: null + property string panelTitle: "" + property string panelNamespace: "nova-panel" + property real panelContentWidth: 220 + property Component titleActionsComponent: null + signal tapped function flashPanel() { @@ -38,6 +44,11 @@ Row { _osdTimer.stop(); } + function keepPanelOpen(ms) { + if (_panelLoader.item) + _panelLoader.item.keepOpen(ms); + } + Timer { id: _osdTimer interval: 1500 @@ -81,4 +92,27 @@ Row { duration: 150 } } + + // HoverPanel - only created when module provides panelComponent + LazyLoader { + id: _panelLoader + active: root.panelComponent !== null + + M.HoverPanel { + showPanel: root._showPanel + screen: QsWindow.window?.screen ?? null + anchorItem: root + accentColor: root.accentColor + panelNamespace: root.panelNamespace + panelTitle: root.panelTitle + contentWidth: root.panelContentWidth + titleActionsComponent: root.titleActionsComponent + onDismissed: root.dismissPanel() + + Loader { + width: root.panelContentWidth + sourceComponent: root.panelComponent + } + } + } } diff --git a/shell/modules/BatteryModule.qml b/shell/modules/BatteryModule.qml index 309d46d..57b66f7 100644 --- a/shell/modules/BatteryModule.qml +++ b/shell/modules/BatteryModule.qml @@ -10,6 +10,16 @@ M.BarModule { opacity: S.Modules.battery.enable && S.BatteryService.available ? 1 : 0 visible: opacity > 0 tooltip: "Battery: " + Math.round(S.BatteryService.percent) + "%" + (S.BatteryService.charging ? " (charging)" : "") + panelNamespace: "nova-battery" + panelTitle: "Battery" + panelContentWidth: 240 + panelComponent: Component { + C.BatteryApplet { + width: parent.width + active: root._showPanel + accentColor: root.accentColor + } + } property real _blinkOpacity: 1 @@ -37,22 +47,4 @@ M.BarModule { opacity: root._blinkOpacity anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-battery" - panelTitle: "Battery" - contentWidth: 240 - onDismissed: root.dismissPanel() - - C.BatteryApplet { - width: hoverPanel.contentWidth - active: root._showPanel - accentColor: root.accentColor - } - } } diff --git a/shell/modules/BluetoothModule.qml b/shell/modules/BluetoothModule.qml index e2710c5..347a614 100644 --- a/shell/modules/BluetoothModule.qml +++ b/shell/modules/BluetoothModule.qml @@ -16,6 +16,53 @@ M.BarModule { return "Bluetooth: off"; return "Bluetooth: on"; } + panelNamespace: "nova-bluetooth" + panelTitle: "Bluetooth" + panelContentWidth: 250 + titleActionsComponent: Component { + Item { + width: 20 + height: 20 + + Text { + anchors.centerIn: parent + text: "\uF011" + color: S.BluetoothService.enabled ? root.accentColor : S.Theme.base04 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.iconFontFamily + + Behavior on color { + ColorAnimation { + duration: 100 + } + } + } + + HoverHandler { + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: S.BluetoothService.setPower(!S.BluetoothService.enabled) + } + } + } + panelComponent: Component { + C.BluetoothApplet { + width: parent.width + accentColor: root.accentColor + } + } + + on_ShowPanelChanged: if (_showPanel) + S.BluetoothService.refresh() + + Connections { + target: S.BluetoothService + function onDevicesChanged() { + root.keepPanelOpen(500); + } + } M.BarIcon { icon: "\uF294" @@ -27,59 +74,4 @@ M.BarModule { label: S.BluetoothService.device + (S.BluetoothService.batteryPct >= 0 ? " " + S.BluetoothService.batteryPct + "%" : "") anchors.verticalCenter: parent.verticalCenter } - - Connections { - target: S.BluetoothService - function onDevicesChanged() { - hoverPanel.keepOpen(500); - } - } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-bluetooth" - panelTitle: "Bluetooth" - contentWidth: 250 - onDismissed: root.dismissPanel() - titleActionsComponent: Component { - Item { - width: 20 - height: 20 - - Text { - anchors.centerIn: parent - text: "\uF011" - color: S.BluetoothService.enabled ? hoverPanel.accentColor : S.Theme.base04 - font.pixelSize: S.Theme.fontSize - font.family: S.Theme.iconFontFamily - - Behavior on color { - ColorAnimation { - duration: 100 - } - } - } - - HoverHandler { - cursorShape: Qt.PointingHandCursor - } - - TapHandler { - onTapped: S.BluetoothService.setPower(!S.BluetoothService.enabled) - } - } - } - - onVisibleChanged: if (visible) - S.BluetoothService.refresh() - - C.BluetoothApplet { - width: hoverPanel.contentWidth - accentColor: root.accentColor - } - } } diff --git a/shell/modules/ClockModule.qml b/shell/modules/ClockModule.qml index baffffb..4bbd126 100644 --- a/shell/modules/ClockModule.qml +++ b/shell/modules/ClockModule.qml @@ -8,6 +8,16 @@ M.BarModule { id: root spacing: S.Theme.moduleSpacing tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy") + panelNamespace: "nova-clock" + panelTitle: Qt.formatTime(clock.date, "HH:mm:ss") + panelContentWidth: 220 + panelComponent: Component { + C.ClockApplet { + width: parent.width + accentColor: root.accentColor + currentDate: clock.date + } + } SystemClock { id: clock @@ -20,22 +30,4 @@ M.BarModule { minText: "Wed, 00. Sep 00:00" anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-clock" - panelTitle: Qt.formatTime(clock.date, "HH:mm:ss") - contentWidth: 220 - onDismissed: root.dismissPanel() - - C.ClockApplet { - width: hoverPanel.contentWidth - accentColor: root.accentColor - currentDate: clock.date - } - } } diff --git a/shell/modules/CpuModule.qml b/shell/modules/CpuModule.qml index 68ed553..9b89514 100644 --- a/shell/modules/CpuModule.qml +++ b/shell/modules/CpuModule.qml @@ -8,6 +8,20 @@ M.BarModule { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) tooltip: "CPU: " + S.SystemStats.cpuUsage + "% @ " + S.SystemStats.cpuFreqGhz.toFixed(2) + " GHz" + panelNamespace: "nova-cpu" + panelTitle: "CPU" + panelContentWidth: 260 + panelComponent: Component { + C.CpuApplet { + width: parent.width + cores: root._cores + coreMaxFreq: root._coreMaxFreq + coreTypes: root._coreTypes + processes: root._procs.processes + accentColor: root.accentColor + active: root._showPanel + } + } readonly property var _cores: S.SystemStats.cpuCores readonly property var _coreMaxFreq: S.SystemStats.cpuCoreMaxFreq @@ -28,7 +42,7 @@ M.BarModule { property M.ProcessList _procs: M.ProcessList { sortBy: "cpu" active: root._showPanel - onProcessesChanged: hoverPanel.keepOpen(300) + onProcessesChanged: root.keepPanelOpen(300) } M.BarIcon { @@ -40,26 +54,4 @@ M.BarModule { minText: "99%@9.99" anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-cpu" - panelTitle: "CPU" - contentWidth: 260 - onDismissed: root.dismissPanel() - - C.CpuApplet { - width: hoverPanel.contentWidth - cores: root._cores - coreMaxFreq: root._coreMaxFreq - coreTypes: root._coreTypes - processes: root._procs.processes - accentColor: root.accentColor - active: root._showPanel - } - } } diff --git a/shell/modules/DiskModule.qml b/shell/modules/DiskModule.qml index 0763b9b..d682e24 100644 --- a/shell/modules/DiskModule.qml +++ b/shell/modules/DiskModule.qml @@ -8,6 +8,16 @@ M.BarModule { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) tooltip: "Disk: " + _rootPct + "% used" + panelNamespace: "nova-disk" + panelTitle: "Disk" + panelContentWidth: 260 + panelComponent: Component { + C.DiskApplet { + width: parent.width + mounts: root._mounts + accentColor: root.accentColor + } + } property var _mounts: S.SystemStats.diskMounts property int _rootPct: S.SystemStats.diskRootPct @@ -30,22 +40,4 @@ M.BarModule { color: root._anyWarn ? S.Theme.base09 : root.accentColor anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-disk" - panelTitle: "Disk" - contentWidth: 260 - onDismissed: root.dismissPanel() - - C.DiskApplet { - width: hoverPanel.contentWidth - mounts: root._mounts - accentColor: root.accentColor - } - } } diff --git a/shell/modules/GpuModule.qml b/shell/modules/GpuModule.qml index 634cb10..69c5701 100644 --- a/shell/modules/GpuModule.qml +++ b/shell/modules/GpuModule.qml @@ -9,6 +9,16 @@ M.BarModule { spacing: Math.max(1, S.Theme.moduleSpacing - 2) visible: S.Modules.gpu.enable && S.SystemStats.gpuAvailable tooltip: "GPU: " + S.SystemStats.gpuUsage + "%" + panelNamespace: "nova-gpu" + panelTitle: "GPU" + panelContentWidth: 240 + panelComponent: Component { + C.GpuApplet { + width: parent.width + active: root._showPanel + accentColor: root.accentColor + } + } M.BarIcon { icon: "\uEB4C" @@ -19,22 +29,4 @@ M.BarModule { minText: "100%" anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-gpu" - panelTitle: "GPU" - contentWidth: 240 - onDismissed: root.dismissPanel() - - C.GpuApplet { - width: hoverPanel.contentWidth - active: root._showPanel - accentColor: root.accentColor - } - } } diff --git a/shell/modules/MemoryModule.qml b/shell/modules/MemoryModule.qml index 60b74bb..9a676d3 100644 --- a/shell/modules/MemoryModule.qml +++ b/shell/modules/MemoryModule.qml @@ -8,43 +8,12 @@ M.BarModule { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) tooltip: "Memory: " + usedGb.toFixed(1) + " / " + totalGb.toFixed(1) + " GB" - - property int percent: S.SystemStats.memPercent - property real usedGb: S.SystemStats.memUsedGb - property real totalGb: S.SystemStats.memTotalGb - property real availGb: S.SystemStats.memAvailGb - property real cachedGb: S.SystemStats.memCachedGb - property real buffersGb: S.SystemStats.memBuffersGb - - property M.ProcessList _procs: M.ProcessList { - sortBy: "mem" - active: root._showPanel - onProcessesChanged: hoverPanel.keepOpen(300) - } - - M.BarIcon { - icon: "\uEFC5" - anchors.verticalCenter: parent.verticalCenter - } - M.BarLabel { - label: root.percent + "%" - minText: "100%" - anchors.verticalCenter: parent.verticalCenter - } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-memory" - panelTitle: "Memory" - contentWidth: 240 - onDismissed: root.dismissPanel() - + panelNamespace: "nova-memory" + panelTitle: "Memory" + panelContentWidth: 240 + panelComponent: Component { C.MemoryApplet { - width: hoverPanel.contentWidth + width: parent.width percent: root.percent usedGb: root.usedGb totalGb: root.totalGb @@ -56,4 +25,27 @@ M.BarModule { active: root._showPanel } } + + property int percent: S.SystemStats.memPercent + property real usedGb: S.SystemStats.memUsedGb + property real totalGb: S.SystemStats.memTotalGb + property real availGb: S.SystemStats.memAvailGb + property real cachedGb: S.SystemStats.memCachedGb + property real buffersGb: S.SystemStats.memBuffersGb + + property M.ProcessList _procs: M.ProcessList { + sortBy: "mem" + active: root._showPanel + onProcessesChanged: root.keepPanelOpen(300) + } + + M.BarIcon { + icon: "\uEFC5" + anchors.verticalCenter: parent.verticalCenter + } + M.BarLabel { + label: root.percent + "%" + minText: "100%" + anchors.verticalCenter: parent.verticalCenter + } } diff --git a/shell/modules/MprisModule.qml b/shell/modules/MprisModule.qml index 4596da8..7c9d60b 100644 --- a/shell/modules/MprisModule.qml +++ b/shell/modules/MprisModule.qml @@ -12,6 +12,25 @@ M.BarModule { opacity: S.Modules.mpris.enable && player !== null ? 1 : 0 visible: opacity > 0 tooltip: player ? (player.trackTitle || player.identity || "Media") + (playing ? " (playing)" : " (paused)") : "Media" + panelNamespace: "nova-mpris" + panelTitle: "Now Playing" + panelContentWidth: 280 + panelComponent: Component { + C.MprisApplet { + width: parent.width + player: root.player + players: root._players + playing: root.playing + accentColor: root.accentColor + cachedArt: root._cachedArt + cavaBars: root._cavaBars + playerIdx: S.MprisService.playerIdx + onPlayerSwitched: idx => { + S.MprisService.switchPlayer(idx); + root.keepPanelOpen(400); + } + } + } readonly property var _players: S.MprisService.players readonly property MprisPlayer player: S.MprisService.player @@ -80,31 +99,4 @@ M.BarModule { width: Math.min(implicitWidth, 200) anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-mpris" - panelTitle: "Now Playing" - contentWidth: 280 - onDismissed: root.dismissPanel() - - C.MprisApplet { - width: hoverPanel.contentWidth - player: root.player - players: root._players - playing: root.playing - accentColor: root.accentColor - cachedArt: root._cachedArt - cavaBars: root._cavaBars - playerIdx: S.MprisService.playerIdx - onPlayerSwitched: idx => { - S.MprisService.switchPlayer(idx); - hoverPanel.keepOpen(400); - } - } - } } diff --git a/shell/modules/NetworkModule.qml b/shell/modules/NetworkModule.qml index fb08ffe..b434888 100644 --- a/shell/modules/NetworkModule.qml +++ b/shell/modules/NetworkModule.qml @@ -16,9 +16,56 @@ M.BarModule { return "Network: linked"; return "Network: disconnected"; } + panelNamespace: "nova-network" + panelTitle: "Wi-Fi" + panelContentWidth: 250 + titleActionsComponent: Component { + Item { + width: 20 + height: 20 + + Text { + anchors.centerIn: parent + text: "\uF011" + color: S.NetworkService.wifiEnabled ? root.accentColor : S.Theme.base04 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.iconFontFamily + + Behavior on color { + ColorAnimation { + duration: 100 + } + } + } + + HoverHandler { + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: S.NetworkService.setWifi(!S.NetworkService.wifiEnabled) + } + } + } + panelComponent: Component { + C.NetworkApplet { + width: parent.width + accentColor: root.accentColor + } + } readonly property string state: S.NetworkService.state + on_ShowPanelChanged: if (_showPanel) + S.NetworkService.refresh() + + Connections { + target: S.NetworkService + function onNetworksChanged() { + root.keepPanelOpen(500); + } + } + M.BarIcon { icon: { if (root.state === "wifi") @@ -38,59 +85,4 @@ M.BarModule { color: root.state === "disconnected" ? S.Theme.base08 : root.accentColor anchors.verticalCenter: parent.verticalCenter } - - Connections { - target: S.NetworkService - function onNetworksChanged() { - hoverPanel.keepOpen(500); - } - } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-network" - panelTitle: "Wi-Fi" - contentWidth: 250 - onDismissed: root.dismissPanel() - titleActionsComponent: Component { - Item { - width: 20 - height: 20 - - Text { - anchors.centerIn: parent - text: "\uF011" - color: S.NetworkService.wifiEnabled ? hoverPanel.accentColor : S.Theme.base04 - font.pixelSize: S.Theme.fontSize - font.family: S.Theme.iconFontFamily - - Behavior on color { - ColorAnimation { - duration: 100 - } - } - } - - HoverHandler { - cursorShape: Qt.PointingHandCursor - } - - TapHandler { - onTapped: S.NetworkService.setWifi(!S.NetworkService.wifiEnabled) - } - } - } - - onVisibleChanged: if (visible) - S.NetworkService.refresh() - - C.NetworkApplet { - width: hoverPanel.contentWidth - accentColor: root.accentColor - } - } } diff --git a/shell/modules/NotificationsModule.qml b/shell/modules/NotificationsModule.qml index 7bb9075..8b7502f 100644 --- a/shell/modules/NotificationsModule.qml +++ b/shell/modules/NotificationsModule.qml @@ -9,6 +9,60 @@ M.BarModule { id: root spacing: S.Theme.moduleSpacing tooltip: S.NotifService.count > 0 ? "Notifications: " + S.NotifService.count + (S.NotifService.dnd ? " (DND)" : "") : (S.NotifService.dnd ? "Do not disturb" : "No notifications") + panelNamespace: "nova-notifications" + panelTitle: "Notifications" + panelContentWidth: 350 + titleActionsComponent: Component { + Row { + spacing: 8 + + // DND toggle + Text { + text: S.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C" + color: S.NotifService.dnd ? S.Theme.base09 : S.Theme.base04 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.iconFontFamily + anchors.verticalCenter: parent.verticalCenter + + HoverHandler { + cursorShape: Qt.PointingHandCursor + } + TapHandler { + onTapped: S.NotifService.toggleDnd() + } + } + + // Clear all + Text { + text: "\uF1F8" + color: _clearHover.hovered ? S.Theme.base08 : S.Theme.base04 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.iconFontFamily + anchors.verticalCenter: parent.verticalCenter + visible: S.NotifService.count > 0 + + HoverHandler { + id: _clearHover + cursorShape: Qt.PointingHandCursor + } + TapHandler { + onTapped: if (root._notifApplet) + root._notifApplet.cascadeDismiss() + } + } + } + } + panelComponent: Component { + C.NotifApplet { + width: parent.width + contentWidth: root.panelContentWidth + accentColor: root.accentColor + Component.onCompleted: root._notifApplet = this + Component.onDestruction: root._notifApplet = null + } + } + + property var _notifApplet: null readonly property bool hasUrgent: S.NotifService.list.some(n => n.urgency === NotificationUrgency.Critical && n.state !== "dismissed") @@ -67,62 +121,4 @@ M.BarModule { acceptedButtons: Qt.RightButton onTapped: S.NotifService.toggleDnd() } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-notifications" - panelTitle: "Notifications" - contentWidth: 350 - onDismissed: root.dismissPanel() - titleActionsComponent: Component { - Row { - spacing: 8 - - // DND toggle - Text { - text: S.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C" - color: S.NotifService.dnd ? S.Theme.base09 : S.Theme.base04 - font.pixelSize: S.Theme.fontSize - font.family: S.Theme.iconFontFamily - anchors.verticalCenter: parent.verticalCenter - - HoverHandler { - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: S.NotifService.toggleDnd() - } - } - - // Clear all - Text { - text: "\uF1F8" - color: _clearHover.hovered ? S.Theme.base08 : S.Theme.base04 - font.pixelSize: S.Theme.fontSize - font.family: S.Theme.iconFontFamily - anchors.verticalCenter: parent.verticalCenter - visible: S.NotifService.count > 0 - - HoverHandler { - id: _clearHover - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: _notifApplet.cascadeDismiss() - } - } - } - } - - C.NotifApplet { - id: _notifApplet - width: hoverPanel.contentWidth - contentWidth: hoverPanel.contentWidth - accentColor: root.accentColor - } - } } diff --git a/shell/modules/PowerModule.qml b/shell/modules/PowerModule.qml index 31a5407..b763b37 100644 --- a/shell/modules/PowerModule.qml +++ b/shell/modules/PowerModule.qml @@ -8,6 +8,20 @@ import "../applets" as C M.BarModule { id: root tooltip: "Power menu" + panelNamespace: "nova-power" + panelTitle: "Power" + panelContentWidth: 180 + panelComponent: Component { + C.PowerApplet { + width: parent.width + accentColor: root.accentColor + onRunCommand: cmd => { + runner.command = cmd; + runner.running = true; + } + onDismiss: root.dismissPanel() + } + } Process { id: runner @@ -17,26 +31,4 @@ M.BarModule { icon: "\uF011" anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-power" - panelTitle: "Power" - contentWidth: 180 - onDismissed: root.dismissPanel() - - C.PowerApplet { - width: hoverPanel.contentWidth - accentColor: root.accentColor - onRunCommand: cmd => { - runner.command = cmd; - runner.running = true; - } - onDismiss: root.dismissPanel() - } - } } diff --git a/shell/modules/TemperatureModule.qml b/shell/modules/TemperatureModule.qml index f355910..338aab6 100644 --- a/shell/modules/TemperatureModule.qml +++ b/shell/modules/TemperatureModule.qml @@ -8,6 +8,22 @@ M.BarModule { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) tooltip: "Temperature: " + _temp + "\u00B0C" + panelNamespace: "nova-temperature" + panelTitle: "Temperature" + panelContentWidth: 220 + panelComponent: Component { + C.TemperatureApplet { + width: parent.width + temp: root._temp + warm: root._warm + hot: root._hot + history: S.SystemStats.tempHistory + devices: S.SystemStats.tempDevices + accentColor: root.accentColor + deviceFilter: root._deviceFilter + active: root._showPanel + } + } readonly property int _warm: S.Modules.temperature.warm || 80 readonly property int _hot: S.Modules.temperature.hot || 90 @@ -40,28 +56,4 @@ M.BarModule { color: root._stateColor anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-temperature" - panelTitle: "Temperature" - contentWidth: 220 - onDismissed: root.dismissPanel() - - C.TemperatureApplet { - width: hoverPanel.contentWidth - temp: root._temp - warm: root._warm - hot: root._hot - history: S.SystemStats.tempHistory - devices: S.SystemStats.tempDevices - accentColor: root.accentColor - deviceFilter: root._deviceFilter - active: root._showPanel - } - } } diff --git a/shell/modules/VolumeModule.qml b/shell/modules/VolumeModule.qml index 8e71f45..678eca4 100644 --- a/shell/modules/VolumeModule.qml +++ b/shell/modules/VolumeModule.qml @@ -9,6 +9,18 @@ M.BarModule { id: root spacing: S.Theme.moduleSpacing tooltip: "Volume: " + Math.round(volume * 100) + "%" + (muted ? " (muted)" : "") + panelNamespace: "nova-volume" + panelTitle: "Sound" + panelContentWidth: 220 + panelComponent: Component { + C.VolumeApplet { + width: parent.width + sink: root.sink + sinkList: root._sinkList + streamList: root._streamList + accentColor: root.accentColor + } + } PwObjectTracker { objects: [Pipewire.defaultAudioSink, ...root._streamList] @@ -78,24 +90,4 @@ M.BarModule { root.sink.audio.volume = Math.max(0, root.sink.audio.volume + (event.angleDelta.y > 0 ? 0.05 : -0.05)); } } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-volume" - panelTitle: "Sound" - contentWidth: 220 - onDismissed: root.dismissPanel() - - C.VolumeApplet { - width: hoverPanel.contentWidth - sink: root.sink - sinkList: root._sinkList - streamList: root._streamList - accentColor: root.accentColor - } - } } diff --git a/shell/modules/WeatherModule.qml b/shell/modules/WeatherModule.qml index ba06651..2325d21 100644 --- a/shell/modules/WeatherModule.qml +++ b/shell/modules/WeatherModule.qml @@ -8,27 +8,19 @@ M.BarModule { id: root spacing: S.Theme.moduleSpacing visible: S.Modules.weather.enable && S.WeatherService.available - tooltip: S.WeatherService.summary || "Weather" + tooltip: "Weather" + panelNamespace: "nova-weather" + panelTitle: "Weather" + panelContentWidth: 280 + panelComponent: Component { + C.WeatherApplet { + width: parent.width + accentColor: root.accentColor + } + } M.BarIcon { icon: S.WeatherService.icon anchors.verticalCenter: parent.verticalCenter } - - M.HoverPanel { - id: hoverPanel - showPanel: root._showPanel - screen: QsWindow.window?.screen ?? null - anchorItem: root - accentColor: root.accentColor - panelNamespace: "nova-weather" - panelTitle: "Weather" - contentWidth: 280 - onDismissed: root.dismissPanel() - - C.WeatherApplet { - width: hoverPanel.contentWidth - accentColor: root.accentColor - } - } } diff --git a/test/qmllint-baseline.txt b/test/qmllint-baseline.txt index cd655d5..5f0a711 100644 --- a/test/qmllint-baseline.txt +++ b/test/qmllint-baseline.txt @@ -20,30 +20,28 @@ shell/lock/Lock.qml: Unqualified access [unqualified] shell/lock/LockAuth.qml: Unqualified access [unqualified] shell/lock/LockSurface.qml: Unqualified access [unqualified] shell/modules/BackgroundOverlay.qml: Type PanelWindow is not creatable. [uncreatable-type] -shell/modules/BacklightModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/BacklightModule.qml: Unqualified access [unqualified] shell/modules/Bar.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/BarGroup.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/BarGroup.qml: Unqualified access [unqualified] shell/modules/BarIcon.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] -shell/modules/BarIcon.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/BarLabel.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] -shell/modules/BarLabel.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/BarSection.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] -shell/modules/BarSection.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/BatteryModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/BluetoothModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/BarModule.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] +shell/modules/BarModule.qml: Member "keepOpen" not found on type "QObject" [missing-property] +shell/modules/BarModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/BarModule.qml: Unqualified access [unqualified] +shell/modules/BatteryModule.qml: Unqualified access [unqualified] shell/modules/BluetoothModule.qml: Unqualified access [unqualified] -shell/modules/ClockModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/CpuModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/DiskModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/GpuModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/ClockModule.qml: Unqualified access [unqualified] +shell/modules/CpuModule.qml: Unqualified access [unqualified] +shell/modules/DiskModule.qml: Unqualified access [unqualified] +shell/modules/GpuModule.qml: Unqualified access [unqualified] shell/modules/HoverPanel.qml: Could not find property "top". [missing-property] shell/modules/HoverPanel.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/HoverPanel.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/HoverPanel.qml: unknown grouped property scope margins. [unqualified] -shell/modules/MemoryModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/MprisModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/NetworkModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/MemoryModule.qml: Unqualified access [unqualified] +shell/modules/MprisModule.qml: Unqualified access [unqualified] shell/modules/NetworkModule.qml: Unqualified access [unqualified] shell/modules/NotifCard.qml: Unqualified access [unqualified] shell/modules/NotifPopup.qml: Could not find property "right". [missing-property] @@ -52,16 +50,14 @@ shell/modules/NotifPopup.qml: Type PanelWindow is not creatable. [uncreatable-ty shell/modules/NotifPopup.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/NotifPopup.qml: Unqualified access [unqualified] shell/modules/NotifPopup.qml: unknown grouped property scope margins. [unqualified] -shell/modules/NotificationsModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/NotificationsModule.qml: Unqualified access [unqualified] shell/modules/OverviewBackdrop.qml: Type PanelWindow is not creatable. [uncreatable-type] -shell/modules/PowerMenu.qml: Unqualified access [unqualified] -shell/modules/PowerModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/applets/PowerApplet.qml: Unqualified access [unqualified] shell/modules/PowerModule.qml: Unqualified access [unqualified] shell/modules/ScreenCapture.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/ScreenCorners.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/ScreenCorners.qml: Unqualified access [unqualified] -shell/modules/TemperatureModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/TemperatureModule.qml: Unqualified access [unqualified] shell/modules/ThemedIcon.qml: Unqualified access [unqualified] shell/modules/Tooltip.qml: Could not find property "left". [missing-property] shell/modules/Tooltip.qml: Could not find property "top". [missing-property] @@ -72,8 +68,8 @@ shell/modules/TrayMenu.qml: Unqualified access [unqualified] shell/modules/TrayModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/TrayModule.qml: Type "qs::dbus::dbusmenu::DBusMenuHandle" of property "menu" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/TrayModule.qml: Unqualified access [unqualified] -shell/modules/VolumeModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/WeatherModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/VolumeModule.qml: Unqualified access [unqualified] +shell/modules/WeatherModule.qml: Unqualified access [unqualified] shell/modules/WindowTitleModule.qml: Unqualified access [unqualified] shell/modules/WorkspacesModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/WorkspacesModule.qml: Unqualified access [unqualified]