Compare commits
2 changed files with 79 additions and 53 deletions
|
|
@ -306,50 +306,58 @@ Column {
|
||||||
// Player switcher
|
// Player switcher
|
||||||
Item {
|
Item {
|
||||||
width: root.width
|
width: root.width
|
||||||
height: root.players.length > 1 ? _playerFlow.implicitHeight + 6 : 0
|
height: root.players.length > 1 ? 28 : 0
|
||||||
visible: root.players.length > 1
|
visible: root.players.length > 1
|
||||||
|
|
||||||
Flow {
|
Flickable {
|
||||||
id: _playerFlow
|
id: _switcher
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.centerIn: parent
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
width: Math.min(_playerRow.implicitWidth, parent.width - 16)
|
||||||
width: parent.width - 16
|
height: 22
|
||||||
spacing: 6
|
contentWidth: _playerRow.implicitWidth
|
||||||
|
clip: true
|
||||||
|
|
||||||
Repeater {
|
Row {
|
||||||
model: root.players
|
id: _playerRow
|
||||||
|
height: 22
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
delegate: Rectangle {
|
Repeater {
|
||||||
required property var modelData
|
model: root.players
|
||||||
required property int index
|
|
||||||
|
|
||||||
readonly property bool _active: index === root.playerIdx
|
delegate: Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
width: _pLabel.implicitWidth + 12
|
readonly property bool _active: index === root.playerIdx
|
||||||
height: 18
|
|
||||||
radius: 9
|
|
||||||
color: _active ? S.Theme.base02 : (pHover.hovered ? S.Theme.base02 : "transparent")
|
|
||||||
border.color: _active ? root.accentColor : S.Theme.base03
|
|
||||||
border.width: _active ? 1 : 0
|
|
||||||
|
|
||||||
Text {
|
width: _pLabel.implicitWidth + 12
|
||||||
id: _pLabel
|
height: 18
|
||||||
anchors.centerIn: parent
|
radius: 9
|
||||||
text: modelData.identity ?? "Player"
|
color: _active ? S.Theme.base02 : (pHover.hovered ? S.Theme.base02 : "transparent")
|
||||||
color: _active ? root.accentColor : S.Theme.base04
|
border.color: _active ? root.accentColor : S.Theme.base03
|
||||||
font.pixelSize: S.Theme.fontSize - 2
|
border.width: _active ? 1 : 0
|
||||||
font.family: S.Theme.fontFamily
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
font.bold: _active
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
Text {
|
||||||
id: pHover
|
id: _pLabel
|
||||||
cursorShape: Qt.PointingHandCursor
|
anchors.centerIn: parent
|
||||||
}
|
text: modelData.identity ?? "Player"
|
||||||
|
color: _active ? root.accentColor : S.Theme.base04
|
||||||
|
font.pixelSize: S.Theme.fontSize - 2
|
||||||
|
font.family: S.Theme.fontFamily
|
||||||
|
font.bold: _active
|
||||||
|
}
|
||||||
|
|
||||||
TapHandler {
|
HoverHandler {
|
||||||
onTapped: {
|
id: pHover
|
||||||
root.playerSwitched(index);
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
root.playerSwitched(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQml.Models
|
|
||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
|
@ -14,6 +13,7 @@ QtObject {
|
||||||
|
|
||||||
property string _selectedIdentity: ""
|
property string _selectedIdentity: ""
|
||||||
property var _lastPlayedTime: ({})
|
property var _lastPlayedTime: ({})
|
||||||
|
property var _watchers: []
|
||||||
|
|
||||||
onPlayerChanged: {
|
onPlayerChanged: {
|
||||||
if (player)
|
if (player)
|
||||||
|
|
@ -33,18 +33,33 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch all raw players for state changes via Instantiator -
|
// Watch raw Mpris.players for add/remove - this does NOT fire on state changes
|
||||||
// delegates persist across state changes since the model only
|
property Connections _mprisConn: Connections {
|
||||||
// changes on player add/remove, not property changes
|
target: Mpris
|
||||||
property Instantiator _stateWatchers: Instantiator {
|
function onPlayersChanged() {
|
||||||
model: Mpris.players
|
root._reconnectWatchers();
|
||||||
delegate: QtObject {
|
}
|
||||||
required property MprisPlayer modelData
|
}
|
||||||
property Connections _conn: Connections {
|
|
||||||
target: modelData
|
function _reconnectWatchers() {
|
||||||
function onPlaybackStateChanged() {
|
for (const w of _watchers)
|
||||||
root._onPlaybackStateChanged(modelData);
|
w.destroy();
|
||||||
}
|
|
||||||
|
const raw = Mpris.players.values ?? [];
|
||||||
|
const newWatchers = [];
|
||||||
|
for (const p of raw) {
|
||||||
|
const conn = _watcherComp.createObject(root, {
|
||||||
|
target: p
|
||||||
|
});
|
||||||
|
newWatchers.push(conn);
|
||||||
|
}
|
||||||
|
_watchers = newWatchers;
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component _watcherComp: Component {
|
||||||
|
Connections {
|
||||||
|
function onPlaybackStateChanged() {
|
||||||
|
root._onPlaybackStateChanged(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,6 +84,7 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (p.playbackState === MprisPlaybackState.Paused && p === player) {
|
} else if (p.playbackState === MprisPlaybackState.Paused && p === player) {
|
||||||
|
// Current player paused - switch to a playing one if available
|
||||||
_switchToPlaying();
|
_switchToPlaying();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,4 +139,6 @@ QtObject {
|
||||||
if (players[idx])
|
if (players[idx])
|
||||||
_selectedIdentity = players[idx].identity ?? "";
|
_selectedIdentity = players[idx].identity ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: _reconnectWatchers()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue