pragma Singleton import QtQuick import QtQml.Models import Quickshell.Services.Mpris QtObject { id: root readonly property var players: (Mpris.players.values ?? []).filter(p => p.trackTitle || p.playbackState === MprisPlaybackState.Playing || p.playbackState === MprisPlaybackState.Paused) property int playerIdx: 0 readonly property MprisPlayer player: players[playerIdx] ?? players[0] ?? null readonly property bool playing: player?.playbackState === MprisPlaybackState.Playing property string _selectedIdentity: "" property var _lastPlayedTime: ({}) onPlayerChanged: { if (player) _selectedIdentity = player.identity ?? ""; } onPlayersChanged: { if (_selectedIdentity) { const idx = players.findIndex(p => (p.identity ?? "") === _selectedIdentity); if (idx >= 0) { playerIdx = idx; } else { _switchToBest(); } } else { _switchToBest(); } } // Watch all raw players for state changes via Instantiator - // delegates persist across state changes since the model only // changes on player add/remove, not property changes property Instantiator _stateWatchers: Instantiator { model: Mpris.players delegate: QtObject { required property MprisPlayer modelData property Connections _conn: Connections { target: modelData function onPlaybackStateChanged() { root._onPlaybackStateChanged(modelData); } } } } function _onPlaybackStateChanged(p) { if (!p) return; const identity = p.identity ?? ""; if (p.playbackState === MprisPlaybackState.Playing) { const times = Object.assign({}, _lastPlayedTime); times[identity] = Date.now(); _lastPlayedTime = times; // Always switch to the newly playing player if (player !== p) { const idx = players.indexOf(p); if (idx >= 0) { playerIdx = idx; _selectedIdentity = identity; } } } else if (p.playbackState === MprisPlaybackState.Paused && p === player) { _switchToPlaying(); } } function _switchToPlaying() { let best = -1; let bestTime = 0; for (let i = 0; i < players.length; i++) { if (players[i].playbackState === MprisPlaybackState.Playing) { const t = _lastPlayedTime[players[i].identity ?? ""] || 0; if (best < 0 || t > bestTime) { best = i; bestTime = t; } } } if (best >= 0) { playerIdx = best; _selectedIdentity = players[best].identity ?? ""; } } function _switchToBest() { let best = -1; let bestTime = 0; let bestPlaying = -1; let bestPlayingTime = 0; for (let i = 0; i < players.length; i++) { const identity = players[i].identity ?? ""; const t = _lastPlayedTime[identity] || 0; if (players[i].playbackState === MprisPlaybackState.Playing) { if (bestPlaying < 0 || t > bestPlayingTime) { bestPlaying = i; bestPlayingTime = t; } } if (best < 0 || t > bestTime) { best = i; bestTime = t; } } const chosen = bestPlaying >= 0 ? bestPlaying : (best >= 0 ? best : 0); playerIdx = chosen; if (players[chosen]) _selectedIdentity = players[chosen].identity ?? ""; } function switchPlayer(idx) { playerIdx = idx; if (players[idx]) _selectedIdentity = players[idx].identity ?? ""; } }