From 200a844062931070aac3904ac1401196f1dbb41b Mon Sep 17 00:00:00 2001 From: Damocles Date: Sun, 26 Apr 2026 13:37:34 +0200 Subject: [PATCH] mpris applet reads service directly, fix accent color gradient with pinned dock --- shell/applets/MprisApplet.qml | 55 +++++++++++++++-------------------- shell/dock/AppletDock.qml | 6 ---- shell/lock/LockWidgets.qml | 6 ---- shell/modules/BarGroup.qml | 3 +- shell/modules/MprisModule.qml | 22 ++++---------- test/qmllint-baseline.txt | 2 +- 6 files changed, 31 insertions(+), 63 deletions(-) diff --git a/shell/applets/MprisApplet.qml b/shell/applets/MprisApplet.qml index e06c531..9cc349c 100644 --- a/shell/applets/MprisApplet.qml +++ b/shell/applets/MprisApplet.qml @@ -1,19 +1,11 @@ import QtQuick -import Quickshell.Services.Mpris import "../services" as S Column { id: root - required property var player - required property var players - required property bool playing required property color accentColor - property string cachedArt: "" property var cavaBars: Array(16).fill(0) - property int playerIdx: 0 - - signal playerSwitched(int idx) // Album art - always 1:1, crossfades on session switch Item { @@ -74,22 +66,23 @@ Column { } Connections { - target: root + target: S.MprisService function onCachedArtChanged() { - if (!root.cachedArt) { + const art = S.MprisService.cachedArt; + if (!art) { _artFadeIn.stop(); _prevFadeOut.stop(); _artImg._hasArt = false; _artImg.opacity = 0; _artImgPrev.opacity = 0; _artImg.source = ""; - } else if (root.cachedArt !== _artImg.source) { + } else if (art !== _artImg.source) { _prevFadeOut.stop(); _artFadeIn.stop(); _artImgPrev.source = _artImg.source; _artImgPrev.opacity = _artImg.opacity; _artImg.opacity = 0; - _artImg.source = root.cachedArt; + _artImg.source = art; } } } @@ -102,7 +95,7 @@ Column { anchors.bottom: parent.bottom height: parent.height * 0.6 spacing: 2 - visible: root.playing + visible: S.MprisService.playing opacity: 0.5 Repeater { @@ -168,7 +161,7 @@ Column { Text { width: parent.width - text: root.player?.trackTitle || "No track" + text: S.MprisService.player?.trackTitle || "No track" color: S.Theme.base05 font.pixelSize: S.Theme.fontSize + 1 font.family: S.Theme.fontFamily @@ -179,7 +172,7 @@ Column { Text { width: parent.width text: { - const p = root.player; + const p = S.MprisService.player; if (!p) return ""; const artist = Array.isArray(p.trackArtists) ? p.trackArtists.join(", ") : (p.trackArtists || ""); @@ -199,8 +192,8 @@ Column { width: root.width height: 20 - readonly property real pos: root.player?.position ?? 0 - readonly property real dur: root.player?.length ?? 0 + readonly property real pos: S.MprisService.player?.position ?? 0 + readonly property real dur: S.MprisService.player?.length ?? 0 readonly property real frac: dur > 0 ? pos / dur : 0 function _fmtTime(ms) { @@ -259,7 +252,7 @@ Column { Text { text: "\uF048" - color: root.player?.canGoPrevious ? S.Theme.base05 : S.Theme.base03 + color: S.MprisService.player?.canGoPrevious ? S.Theme.base05 : S.Theme.base03 font.pixelSize: S.Theme.fontSize + 4 font.family: S.Theme.iconFontFamily anchors.verticalCenter: parent.verticalCenter @@ -267,13 +260,13 @@ Column { cursorShape: Qt.PointingHandCursor } TapHandler { - enabled: root.player?.canGoPrevious ?? false - onTapped: root.player.previous() + enabled: S.MprisService.player?.canGoPrevious ?? false + onTapped: S.MprisService.player.previous() } } Text { - text: root.playing ? "\uF04C" : "\uF04B" + text: S.MprisService.playing ? "\uF04C" : "\uF04B" color: root.accentColor font.pixelSize: S.Theme.fontSize + 8 font.family: S.Theme.iconFontFamily @@ -282,13 +275,13 @@ Column { cursorShape: Qt.PointingHandCursor } TapHandler { - onTapped: root.player?.togglePlaying() + onTapped: S.MprisService.player?.togglePlaying() } } Text { text: "\uF051" - color: root.player?.canGoNext ? S.Theme.base05 : S.Theme.base03 + color: S.MprisService.player?.canGoNext ? S.Theme.base05 : S.Theme.base03 font.pixelSize: S.Theme.fontSize + 4 font.family: S.Theme.iconFontFamily anchors.verticalCenter: parent.verticalCenter @@ -296,8 +289,8 @@ Column { cursorShape: Qt.PointingHandCursor } TapHandler { - enabled: root.player?.canGoNext ?? false - onTapped: root.player.next() + enabled: S.MprisService.player?.canGoNext ?? false + onTapped: S.MprisService.player.next() } } } @@ -306,8 +299,8 @@ Column { // Player switcher Item { width: root.width - height: root.players.length > 1 ? _playerFlow.implicitHeight + 6 : 0 - visible: root.players.length > 1 + height: S.MprisService.players.length > 1 ? _playerFlow.implicitHeight + 6 : 0 + visible: S.MprisService.players.length > 1 Flow { id: _playerFlow @@ -317,13 +310,13 @@ Column { spacing: 6 Repeater { - model: root.players + model: S.MprisService.players delegate: Rectangle { required property var modelData required property int index - readonly property bool _active: index === root.playerIdx + readonly property bool _active: index === S.MprisService.playerIdx width: _pLabel.implicitWidth + 12 height: 18 @@ -348,9 +341,7 @@ Column { } TapHandler { - onTapped: { - root.playerSwitched(index); - } + onTapped: S.MprisService.switchPlayer(index) } } } diff --git a/shell/dock/AppletDock.qml b/shell/dock/AppletDock.qml index c38bbbb..d8184a1 100644 --- a/shell/dock/AppletDock.qml +++ b/shell/dock/AppletDock.qml @@ -372,13 +372,7 @@ PanelWindow { C.MprisApplet { width: parent.width - player: S.MprisService.player - players: S.MprisService.players - playing: S.MprisService.playing accentColor: root._accent - cachedArt: S.MprisService.cachedArt - playerIdx: S.MprisService.playerIdx - onPlayerSwitched: idx => S.MprisService.switchPlayer(idx) } } diff --git a/shell/lock/LockWidgets.qml b/shell/lock/LockWidgets.qml index 40e157b..1836d71 100644 --- a/shell/lock/LockWidgets.qml +++ b/shell/lock/LockWidgets.qml @@ -78,13 +78,7 @@ Item { anchors.right: parent.right anchors.top: parent.top anchors.topMargin: 8 - player: S.MprisService.player - players: S.MprisService.players - playing: S.MprisService.playing - playerIdx: S.MprisService.playerIdx accentColor: S.Theme.base0D - cachedArt: S.MprisService.player?.trackArtUrl ?? "" - onPlayerSwitched: idx => S.MprisService.switchPlayer(idx) } } diff --git a/shell/modules/BarGroup.qml b/shell/modules/BarGroup.qml index 5cbbe6e..fffa807 100644 --- a/shell/modules/BarGroup.qml +++ b/shell/modules/BarGroup.qml @@ -15,7 +15,8 @@ Item { if (!scr) return 0.5; const gx = mapToGlobal(width / 2, 0).x - scr.x; - return Math.max(0, Math.min(1, gx / scr.width)); + const effectiveWidth = scr.width - (S.DockState.reservedWidth ?? 0); + return Math.max(0, Math.min(1, gx / (effectiveWidth > 0 ? effectiveWidth : scr.width))); } property color borderColor: Qt.rgba(S.Theme.base0C.r + (S.Theme.base09.r - S.Theme.base0C.r) * _posFrac, S.Theme.base0C.g + (S.Theme.base09.g - S.Theme.base0C.g) * _posFrac, S.Theme.base0C.b + (S.Theme.base09.b - S.Theme.base0C.b) * _posFrac, 1) property bool leftEdge: false diff --git a/shell/modules/MprisModule.qml b/shell/modules/MprisModule.qml index 0ad0673..92c42a2 100644 --- a/shell/modules/MprisModule.qml +++ b/shell/modules/MprisModule.qml @@ -9,32 +9,20 @@ import "../applets" as C M.BarModule { id: root spacing: S.Theme.moduleSpacing - opacity: S.Modules.mpris.enable && player !== null ? 1 : 0 + opacity: S.Modules.mpris.enable && S.MprisService.player !== null ? 1 : 0 visible: opacity > 0 - tooltip: player ? (player.trackTitle || player.identity || "Media") + (playing ? " (playing)" : " (paused)") : "Media" + tooltip: S.MprisService.player ? (S.MprisService.player.trackTitle || S.MprisService.player.identity || "Media") + (S.MprisService.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: S.MprisService.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 - readonly property bool playing: S.MprisService.playing // Cava visualizer - 16 bars, raw output mode property var _cavaBars: Array(16).fill(0) property bool _cavaActive: false @@ -56,7 +44,7 @@ M.BarModule { Process { id: cavaProc - running: root.playing && root._cavaActive + running: S.MprisService.playing && root._cavaActive command: ["sh", "-c", "cfg=$(mktemp /tmp/nova-cava-XXXXXX.conf);" + "cat > \"$cfg\" << 'CAVAEOF'\n" + "[general]\nbars=16\nframerate=30\n[output]\nmethod=raw\nraw_target=/dev/stdout\ndata_format=ascii\nascii_max_range=100\n" + "CAVAEOF\n" + "trap 'rm -f \"$cfg\"' EXIT;" + "exec cava -p \"$cfg\""] stdout: SplitParser { splitMarker: "\n" @@ -71,11 +59,11 @@ M.BarModule { required property var bar M.BarIcon { - icon: root.playing ? "\uF04B" : (root.player?.playbackState === MprisPlaybackState.Paused ? "\uDB80\uDFE4" : "\uDB81\uDCDB") + icon: S.MprisService.playing ? "\uF04B" : (S.MprisService.player?.playbackState === MprisPlaybackState.Paused ? "\uDB80\uDFE4" : "\uDB81\uDCDB") anchors.verticalCenter: parent.verticalCenter } M.BarLabel { - label: root.player?.trackTitle || root.player?.identity || "" + label: S.MprisService.player?.trackTitle || S.MprisService.player?.identity || "" elide: Text.ElideRight width: Math.min(implicitWidth, 200) anchors.verticalCenter: parent.verticalCenter diff --git a/test/qmllint-baseline.txt b/test/qmllint-baseline.txt index 708aa1d..fc7df71 100644 --- a/test/qmllint-baseline.txt +++ b/test/qmllint-baseline.txt @@ -8,7 +8,7 @@ shell/applets/CpuApplet.qml: Unqualified access [unqualified] shell/applets/DiskApplet.qml: Unqualified access [unqualified] shell/applets/MemoryApplet.qml: Unqualified access [unqualified] shell/applets/MprisApplet.qml: Member "frac" not found on type "QQuickItem" [missing-property] -shell/applets/MprisApplet.qml: Member "spacing" not found on type "Repeater" [missing-property] +shell/applets/MprisApplet.qml: Member "join" not found on type "QString" [missing-property] shell/applets/MprisApplet.qml: Unqualified access [unqualified] shell/applets/NetworkApplet.qml: Unqualified access [unqualified] shell/applets/NotifApplet.qml: Member "_notif" not found on type "QQuickItem" [missing-property]