// Compact media controls in the date menu: artwork, useful metadata, and the // three controls people expect. It disappears completely without a track. import QtQuick import Quickshell.Services.Mpris import qs.config import qs.widgets Rectangle { id: root readonly property bool compact: width < 360 readonly property MprisPlayer player: { const players = Mpris.players ? Mpris.players.values : []; return players.find(p => p.isPlaying) ?? players.find(p => p.trackTitle) ?? null; } visible: root.player !== null implicitHeight: visible ? (compact ? 64 : 76) : 0 radius: Theme.cardRadius border.width: 0 color: Theme.alpha(Theme.fg, 0.06) clip: true Rectangle { id: artwork anchors.left: parent.left anchors.leftMargin: root.compact ? 8 : 10 anchors.verticalCenter: parent.verticalCenter width: root.compact ? 46 : 56 height: width radius: root.compact ? 9 : 10 border.width: 0 color: Theme.alpha(Theme.accentAlt, 0.16) clip: true Image { anchors.fill: parent source: root.player?.trackArtUrl ?? "" asynchronous: true cache: true fillMode: Image.PreserveAspectCrop visible: status === Image.Ready } ThemedIcon { anchors.centerIn: parent size: 24 icon: "audio-x-generic-symbolic" iconFallback: "multimedia-player-symbolic" tint: Theme.accentAlt visible: !root.player?.trackArtUrl } } Column { anchors.left: artwork.right anchors.leftMargin: root.compact ? 9 : 12 anchors.right: controls.left anchors.rightMargin: root.compact ? 6 : 10 anchors.verticalCenter: parent.verticalCenter spacing: 3 Text { width: parent.width text: root.player?.trackTitle || "Unknown track" color: Theme.fg elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSize font.weight: Font.DemiBold } Text { width: parent.width text: root.player?.trackArtist || root.player?.identity || "Media" color: Theme.fgDim elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } } Row { id: controls anchors.right: parent.right anchors.rightMargin: root.compact ? 7 : 10 anchors.verticalCenter: parent.verticalCenter spacing: 2 MediaButton { icon: "media-skip-backward-symbolic" enabled: root.player?.canGoPrevious ?? false onClicked: root.player?.previous() } MediaButton { icon: root.player?.isPlaying ? "media-playback-pause-symbolic" : "media-playback-start-symbolic" enabled: root.player?.canTogglePlaying ?? false emphasized: true onClicked: root.player?.togglePlaying() } MediaButton { icon: "media-skip-forward-symbolic" enabled: root.player?.canGoNext ?? false onClicked: root.player?.next() } } component MediaButton: Rectangle { id: button required property string icon property bool emphasized: false signal clicked width: root.compact ? (emphasized ? 30 : 27) : (emphasized ? 34 : 30) height: width radius: width / 2 border.width: 0 opacity: enabled ? 1 : 0.35 color: { if (mouse.pressed) return Theme.alpha(emphasized ? Theme.accent : Theme.fg, 0.34); if (mouse.containsMouse) return Theme.alpha(emphasized ? Theme.accent : Theme.fg, 0.22); return emphasized ? Theme.alpha(Theme.accent, 0.14) : "transparent"; } Behavior on color { ColorAnimation { duration: Theme.durFast } } ThemedIcon { anchors.centerIn: parent size: 15 icon: button.icon tint: button.emphasized ? Theme.accent : Theme.fg } MouseArea { id: mouse anchors.fill: parent enabled: button.enabled hoverEnabled: true cursorShape: button.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor onClicked: button.clicked() } } }