168 lines
4.3 KiB
QML
168 lines
4.3 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Services.Mpris
|
|
import Quickshell.Hyprland
|
|
import "../.."
|
|
|
|
Singleton {
|
|
id: root;
|
|
property MprisPlayer trackedPlayer: null;
|
|
property MprisPlayer activePlayer: trackedPlayer ?? Mpris.players.values[0] ?? null;
|
|
signal trackChanged(reverse: bool);
|
|
|
|
property bool __reverse: false;
|
|
|
|
property var activeTrack;
|
|
Component.onCompleted: {
|
|
for (const player of Mpris.players.values) {
|
|
if (player.playbackState == MprisPlaybackState.Playing) {
|
|
if (root.trackedPlayer == null) {
|
|
root.trackedPlayer = player;
|
|
}
|
|
}
|
|
|
|
player.playbackStateChanged.connect(() => {
|
|
if (root.trackedPlayer !== player) root.trackedPlayer = player;
|
|
});
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: activePlayer
|
|
|
|
function onTrackChanged() {
|
|
root.updateTrack();
|
|
}
|
|
}
|
|
|
|
// Change the tracked player when one changes playback state or is created in a playing state.
|
|
Connections {
|
|
target: Mpris.players;
|
|
|
|
function onObjectInsertedPost(player: MprisPlayer) {
|
|
if (player.playbackState === MprisPlaybackState.Playing) {
|
|
if (root.trackedPlayer !== player) root.trackedPlayer = player;
|
|
}
|
|
|
|
player.playbackStateChanged.connect(() => {
|
|
if (root.trackedPlayer !== player) root.trackedPlayer = player;
|
|
});
|
|
}
|
|
|
|
function onObjectRemovedPre() {
|
|
console.log(`trackedPlayer: ${root.trackedPlayer}`)
|
|
if (root.trackedPlayer == null) {
|
|
for (const player of Mpris.players.values) {
|
|
if (player.playbackState === MprisPlaybackState.Playing) {
|
|
root.trackedPlayer = player;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onActivePlayerChanged: this.updateTrack();
|
|
|
|
function updateTrack() {
|
|
const metadata = this.activePlayer?.metadata ?? {};
|
|
|
|
this.activeTrack = {
|
|
artUrl: metadata["mpris:artUrl"] ?? "",
|
|
title: metadata["xesam:title"] ?? "",
|
|
artist: metadata["xesam:artist"] ?? "",
|
|
};
|
|
|
|
this.trackChanged(__reverse);
|
|
this.__reverse = false;
|
|
}
|
|
|
|
property bool isPlaying: this.activePlayer && this.activePlayer.playbackState == MprisPlaybackState.Playing;
|
|
property bool canPlay: this.activePlayer?.canPlay ?? false;
|
|
function play() {
|
|
if (this.canPlay) this.activePlayer.playbackState = MprisPlaybackState.Playing;
|
|
}
|
|
|
|
property bool canPause: this.activePlayer?.canPause ?? false;
|
|
function pause() {
|
|
if (this.canPause) this.activePlayer.playbackState = MprisPlaybackState.Paused;
|
|
}
|
|
|
|
property bool canGoPrevious: this.activePlayer?.canGoPrevious ?? false;
|
|
function previous() {
|
|
if (this.canGoPrevious) {
|
|
this.__reverse = true;
|
|
this.activePlayer.previous();
|
|
}
|
|
}
|
|
|
|
property bool canGoNext: this.activePlayer?.canGoNext ?? false;
|
|
function next() {
|
|
if (this.canGoNext) {
|
|
this.__reverse = false;
|
|
this.activePlayer.next();
|
|
}
|
|
}
|
|
|
|
property bool canChangeVolume: this.activePlayer && this.activePlayer.volumeSupported && this.activePlayer.canControl;
|
|
|
|
property bool loopSupported: this.activePlayer && this.activePlayer.loopSupported && this.activePlayer.canControl;
|
|
property var loopState: this.activePlayer?.loopState ?? MprisLoopState.None;
|
|
function setLoopState(loopState: var) {
|
|
if (this.loopSupported) {
|
|
this.activePlayer.loopState = loopState;
|
|
}
|
|
}
|
|
|
|
property bool shuffleSupported: this.activePlayer && this.activePlayer.shuffleSupported && this.activePlayer.canControl;
|
|
property bool hasShuffle: this.activePlayer?.shuffle ?? false;
|
|
function setShuffle(shuffle: bool) {
|
|
if (this.shuffleSupported) {
|
|
this.activePlayer.shuffle = shuffle;
|
|
}
|
|
}
|
|
|
|
function setActivePlayer(player: MprisPlayer) {
|
|
const targetPlayer = player ?? MprisPlayer.players[0];
|
|
console.log(`setactive: ${targetPlayer} from ${activePlayer}`)
|
|
|
|
if (targetPlayer && this.activePlayer) {
|
|
this.__reverse = Mpris.players.indexOf(targetPlayer) < Mpris.players.indexOf(this.activePlayer);
|
|
} else {
|
|
// always animate forward if going to null
|
|
this.__reverse = false;
|
|
}
|
|
|
|
this.trackedPlayer = targetPlayer;
|
|
}
|
|
|
|
Shortcut {
|
|
name: "music-pauseall";
|
|
onPressed: {
|
|
for (let i = 0; i < Mpris.players.length; i++) {
|
|
const player = Mpris.players[i];
|
|
if (player.canPause) player.playbackState = MprisPlaybackState.Paused;
|
|
}
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
name: "music-playpause";
|
|
onPressed: {
|
|
if (root.isPlaying) root.pause();
|
|
else root.play();
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
name: "music-previous";
|
|
onPressed: root.previous();
|
|
}
|
|
|
|
Shortcut {
|
|
name: "music-next";
|
|
onPressed: root.next();
|
|
}
|
|
}
|