import Quickshell import Quickshell.Services.Mpris import QtQuick PanelWindow { id: controller required property var walColors required property string fontFamily property color bgColor: (walColors.special && walColors.special.background) ? walColors.special.background : "#1d160d" property color fgColor: (walColors.special && walColors.special.foreground) ? walColors.special.foreground : "#d8d8d3" property color accentColor: (walColors.colors && walColors.colors.color1) ? walColors.colors.color1 : "#946F50" property color accent2Color: (walColors.colors && walColors.colors.color2) ? walColors.colors.color2 : "#BA9351" property color accent3Color: (walColors.colors && walColors.colors.color3) ? walColors.colors.color3 : "#BA9351" property color accent4Color: (walColors.colors && walColors.colors.color4) ? walColors.colors.color4 : "#BA9351" property color accent5Color: (walColors.colors && walColors.colors.color5) ? walColors.colors.color5 : "#BA9351" anchors { bottom: true // right: true } color: "transparent" exclusionMode: ExclusionMode.Ignore implicitHeight: 34 implicitWidth: mainGroup.width + 8 property var player: { let players = Mpris.players.values if (!players || players.length === 0) return null for (let i = 0; i < players.length; i++) { if (players[i].playbackState === MprisPlaybackState.Playing) return players[i] } return players[0] } property bool hovered: hoverArea.containsMouse Item { anchors.fill: parent anchors.margins: 2 MouseArea { id: hoverArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.NoButton } Rectangle { id: mainGroup anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter height: 30 width: infoRow.width + 8 clip: true color: controller.bgColor border.color: controller.accentColor border.width: 2 radius: 100 Behavior on width { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } // Track info (default view) Row { id: infoRow anchors.right: parent.right anchors.rightMargin: 4 anchors.verticalCenter: parent.verticalCenter spacing: 5 visible: !controller.hovered BarPill { id: trackInfoPill fontFamily: controller.fontFamily topLeftRadius: 100 bottomLeftRadius: 100 label: { if (!controller.player) return "No Player" let artist = controller.player.trackArtist || "" let title = controller.player.trackTitle || "" if (artist && title) return artist + " \u2022 " + title if (title) return title return controller.player.identity || "Unknown" } pillColor: controller.accent2Color textColor: controller.bgColor } BarPill { fontFamily: controller.fontFamily label: { if (!controller.player) return "\uf04c" if (controller.player.playbackState === MprisPlaybackState.Playing) return "\uf04b" if (controller.player.playbackState === MprisPlaybackState.Paused) return "\uf04c" return "\uf04d" } pillColor: controller.accentColor textColor: controller.bgColor topLeftRadius: 4 bottomLeftRadius: 4 topRightRadius: 100 bottomRightRadius: 100 } } // Controls (hover view) Row { id: controlsRow anchors.right: parent.right anchors.rightMargin: 4 anchors.verticalCenter: parent.verticalCenter spacing: 5 visible: controller.hovered property bool hasShuffle: controller.player && controller.player.shuffleSupported property bool hasLoop: controller.player && controller.player.loopSupported property int visibleCount: 3 + (hasShuffle ? 1 : 0) + (hasLoop ? 1 : 0) property real totalSpacing: (visibleCount - 1) * spacing property real pillWidth: visibleCount > 0 ? (infoRow.width - totalSpacing) / visibleCount : 40 BarPill { fontFamily: controller.fontFamily label: "\uf048" pillColor: controller.accent5Color textColor: controller.bgColor width: controlsRow.pillWidth topLeftRadius: 100 bottomLeftRadius: 100 MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: if (controller.player && controller.player.canGoPrevious) controller.player.previous() } } BarPill { fontFamily: controller.fontFamily label: { if (!controller.player) return "\uf04b" return controller.player.playbackState === MprisPlaybackState.Playing ? "\uf04c" : "\uf04b" } pillColor: controller.accent3Color textColor: controller.bgColor width: controlsRow.pillWidth MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: if (controller.player && controller.player.canTogglePlaying) controller.player.togglePlaying() } } BarPill { id: nextPill fontFamily: controller.fontFamily label: "\uf051" pillColor: controller.accent4Color textColor: controller.bgColor width: controlsRow.pillWidth topRightRadius: (!controlsRow.hasShuffle && !controlsRow.hasLoop) ? 100 : 4 bottomRightRadius: (!controlsRow.hasShuffle && !controlsRow.hasLoop) ? 100 : 4 MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: if (controller.player && controller.player.canGoNext) controller.player.next() } } BarPill { id: shufflePill fontFamily: controller.fontFamily label: "\uf074" pillColor: controller.player && controller.player.shuffle ? controller.accent2Color : controller.accentColor textColor: controller.bgColor width: controlsRow.pillWidth visible: controlsRow.hasShuffle topRightRadius: !controlsRow.hasLoop ? 100 : 4 bottomRightRadius: !controlsRow.hasLoop ? 100 : 4 MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: if (controller.player) controller.player.shuffle = !controller.player.shuffle } } BarPill { fontFamily: controller.fontFamily label: { if (!controller.player) return "\uf01e" if (controller.player.loopState === MprisLoopState.Track) return "\uf021" return "\uf01e" } pillColor: controller.player && controller.player.loopState !== MprisLoopState.None ? controller.accent2Color : controller.accentColor textColor: controller.bgColor width: controlsRow.pillWidth visible: controlsRow.hasLoop topRightRadius: 100 bottomRightRadius: 100 MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { if (!controller.player) return if (controller.player.loopState === MprisLoopState.None) controller.player.loopState = MprisLoopState.Playlist else if (controller.player.loopState === MprisLoopState.Playlist) controller.player.loopState = MprisLoopState.Track else controller.player.loopState = MprisLoopState.None } } } } } } }