quickshell: unify media player selection in a Media singleton
The pill and popout each picked an active MPRIS player independently, so with multiple players open they disagreed and flipped. Add a Media singleton that selects one active player with stickiness and bind both components to it.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import Quickshell
|
||||
import Quickshell.Services.Mpris
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import "../shared" as Shared
|
||||
@@ -7,13 +6,7 @@ import "../shared" as Shared
|
||||
BarPill {
|
||||
id: root
|
||||
|
||||
readonly property var player: {
|
||||
let players = Mpris.players.values;
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
if (players[i].isPlaying) return players[i];
|
||||
}
|
||||
return players.length > 0 ? players[0] : null;
|
||||
}
|
||||
readonly property var player: Shared.Media.activePlayer
|
||||
|
||||
visible: player !== null
|
||||
groupName: "media"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Quickshell
|
||||
import Quickshell.Services.Mpris
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import "../../shared" as Shared
|
||||
@@ -13,13 +12,7 @@ Item {
|
||||
PopoutBackground { anchors.fill: parent }
|
||||
MouseArea { anchors.fill: parent }
|
||||
|
||||
readonly property var player: {
|
||||
let players = Mpris.players.values;
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
if (players[i].isPlaying) return players[i];
|
||||
}
|
||||
return players.length > 0 ? players[0] : null;
|
||||
}
|
||||
readonly property var player: Shared.Media.activePlayer
|
||||
|
||||
readonly property bool isPlaying: player?.isPlaying ?? false
|
||||
readonly property string trackTitle: player?.trackTitle ?? ""
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Services.Mpris
|
||||
import QtQuick
|
||||
|
||||
// Single source of truth for "which MPRIS player is active", so the bar pill and
|
||||
// the popout never disagree when several players are open.
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var activePlayer: null
|
||||
|
||||
readonly property bool hasPlayer: activePlayer !== null
|
||||
readonly property bool isPlaying: activePlayer?.isPlaying ?? false
|
||||
|
||||
// Choose the active player with stickiness: keep the current one while it
|
||||
// still exists and is playing; otherwise prefer a playing player (scanning
|
||||
// newest-first), else keep a valid current, else fall back to the first.
|
||||
function reevaluate() {
|
||||
let players = Mpris.players.values;
|
||||
if (players.length === 0) { root.activePlayer = null; return; }
|
||||
|
||||
let cur = root.activePlayer;
|
||||
let curValid = cur && players.indexOf(cur) >= 0;
|
||||
if (curValid && cur.isPlaying) return;
|
||||
|
||||
for (let i = players.length - 1; i >= 0; i--) {
|
||||
if (players[i].isPlaying) { root.activePlayer = players[i]; return; }
|
||||
}
|
||||
|
||||
if (curValid) return;
|
||||
root.activePlayer = players[0];
|
||||
}
|
||||
|
||||
// Re-evaluate when the set of players changes…
|
||||
Connections {
|
||||
target: Mpris.players
|
||||
function onValuesChanged() { root.reevaluate(); }
|
||||
}
|
||||
|
||||
// …and when any individual player's playback state changes.
|
||||
Instantiator {
|
||||
model: Mpris.players
|
||||
delegate: Connections {
|
||||
required property var modelData
|
||||
target: modelData
|
||||
function onPlaybackStateChanged() { root.reevaluate(); }
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: reevaluate()
|
||||
}
|
||||
Reference in New Issue
Block a user