Files
nixos/Droidnix/generated/.config/quickshell/media/shell.qml
T
2026-04-22 12:23:49 +02:00

387 lines
13 KiB
QML

// --- This file has been auto-generated. For permanent changes alter the appropriate block in the README.org. ---
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
ShellRoot {
QtObject {
id: colors
readonly property color baseAlpha: Qt.rgba(30/255, 30/255, 46/255, 0.95)
readonly property color base: "#1e1e2e"
readonly property color surface0: "#313244"
readonly property color surface1: "#45475a"
readonly property color surface2: "#585b70"
readonly property color text: "#cdd6f4"
readonly property color subtext0: "#a6adc8"
readonly property color subtext1: "#bac2de"
readonly property color blue: "#89b4fa"
readonly property color green: "#a6e3a1"
readonly property color teal: "#94e2d5"
readonly property color red: "#f38ba8"
readonly property color mauve: "#cba6f7"
readonly property color peach: "#fab387"
readonly property color lavender: "#b4befe"
}
QtObject {
id: media
property string artist: ""
property string title: ""
property string album: ""
property string artUrl: ""
property string status: ""
property string device: ""
property string player: ""
property real progress: 0.0
property real duration: 0.0
property real position: 0.0
property int shuffleMode: 0
readonly property bool isSpotify: player.indexOf("spotify") !== -1
}
Timer {
interval: 1000
running: true
repeat: true
onTriggered: {
playerProc.running = true
artistProc.running = true
titleProc.running = true
albumProc.running = true
artProc.running = true
statusProc.running = true
positionProc.running = true
lengthProc.running = true
if (media.isSpotify)
shuffleProc.running = true
}
}
Process {
id: playerProc
command: ["playerctl", "-l"]
stdout: StdioCollector {
onStreamFinished: {
var lines = text.trim().split("\n")
for (var i = 0; i < lines.length; i++) {
if (lines[i].indexOf("spotify") !== -1) {
media.player = lines[i].trim()
return
}
}
media.player = lines[0] ? lines[0].trim() : ""
}
}
}
Process {
id: artistProc
command: ["playerctl", "metadata", "artist"]
stdout: StdioCollector { onStreamFinished: media.artist = text.trim() }
}
Process {
id: titleProc
command: ["playerctl", "metadata", "title"]
stdout: StdioCollector { onStreamFinished: media.title = text.trim() }
}
Process {
id: albumProc
command: ["playerctl", "metadata", "album"]
stdout: StdioCollector { onStreamFinished: media.album = text.trim() }
}
Process {
id: artProc
command: ["playerctl", "metadata", "mpris:artUrl"]
stdout: StdioCollector { onStreamFinished: media.artUrl = text.trim() }
}
Process {
id: statusProc
command: ["playerctl", "status"]
stdout: StdioCollector { onStreamFinished: media.status = text.trim() }
}
Process {
id: positionProc
command: ["playerctl", "position"]
stdout: StdioCollector {
onStreamFinished: {
media.position = parseFloat(text.trim()) || 0
if (media.duration > 0)
media.progress = media.position / media.duration
}
}
}
Process {
id: lengthProc
command: ["playerctl", "metadata", "mpris:length"]
stdout: StdioCollector {
onStreamFinished: {
media.duration = (parseFloat(text.trim()) || 0) / 1000000
}
}
}
Process {
id: shuffleProc
command: ["playerctl", "--player=" + media.player, "shuffle"]
stdout: StdioCollector {
onStreamFinished: {
media.shuffleMode = (text.trim() === "On") ? 1 : 0
}
}
}
Process { id: shuffleOnProc; command: ["playerctl", "--player=" + media.player, "shuffle", "on"] }
Process { id: shuffleOffProc; command: ["playerctl", "--player=" + media.player, "shuffle", "off"] }
function cycleShuffleMode() {
var next = (media.shuffleMode + 1) % 2
media.shuffleMode = next
if (next === 0)
shuffleOffProc.running = true
else
shuffleOnProc.running = true
}
// Focus spotify — uses exact lowercase class as reported by hyprctl
Process {
id: focusSpotifyProc
command: ["hyprctl", "dispatch", "focuswindow", "class:^(spotify)$"]
}
function focusPlayer() {
if (media.isSpotify) {
focusSpotifyProc.running = true
}
}
Process { id: prevProc; command: ["playerctl", "previous"] }
Process { id: playProc; command: ["playerctl", "play-pause"] }
Process { id: nextProc; command: ["playerctl", "next"] }
FloatingWindow {
id: root
title: "quickshell-media"
visible: true
implicitWidth: 300
implicitHeight: 420
color: "transparent"
Shortcut {
sequence: "Escape"
onActivated: Qt.quit()
}
// Gradient border — hidden when app has focus
Rectangle {
anchors.fill: parent
anchors.margins: -2
radius: 18
z: -1
opacity: Qt.application.active ? 0 : 1
Behavior on opacity {
NumberAnimation { duration: 150 }
}
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: colors.blue }
GradientStop { position: 1.0; color: colors.green }
}
}
Rectangle {
anchors.fill: parent
radius: 16
color: colors.base
ColumnLayout {
anchors {
fill: parent
margins: 16
}
spacing: 12
// Album art — click to focus player
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 200
radius: 12
color: colors.surface0
clip: true
Image {
anchors.fill: parent
source: media.artUrl
fillMode: Image.PreserveAspectCrop
visible: media.artUrl !== ""
}
Text {
anchors.centerIn: parent
text: "󰝚"
font.pixelSize: 48
color: colors.surface2
visible: media.artUrl === ""
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: focusPlayer()
}
}
// Artist
Text {
Layout.fillWidth: true
text: media.artist || "Unknown artist"
color: colors.subtext1
font.pixelSize: 12
elide: Text.ElideRight
}
// Title
Text {
Layout.fillWidth: true
text: media.title || "Nothing playing"
color: colors.text
font.pixelSize: 14
font.bold: true
elide: Text.ElideRight
}
// Album
Text {
Layout.fillWidth: true
text: media.album
color: colors.subtext0
font.pixelSize: 11
elide: Text.ElideRight
visible: media.album !== ""
}
// Device (Spotify)
Text {
Layout.fillWidth: true
text: "󰓻 " + media.device
color: colors.green
font.pixelSize: 11
visible: media.device !== ""
}
// Progress bar
Rectangle {
Layout.fillWidth: true
height: 4
radius: 2
color: colors.surface1
Rectangle {
width: parent.width * media.progress
height: parent.height
radius: parent.radius
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: colors.blue }
GradientStop { position: 1.0; color: colors.green }
}
}
}
// Time
RowLayout {
Layout.fillWidth: true
Text {
text: {
var m = Math.floor(media.position / 60)
var s = Math.floor(media.position % 60)
return m + ":" + (s < 10 ? "0" + s : s)
}
color: colors.subtext0
font.pixelSize: 11
}
Item { Layout.fillWidth: true }
Text {
text: {
var m = Math.floor(media.duration / 60)
var s = Math.floor(media.duration % 60)
return m + ":" + (s < 10 ? "0" + s : s)
}
color: colors.subtext0
font.pixelSize: 11
}
}
// Playback controls + shuffle
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
spacing: 20
// Shuffle button (Spotify only)
Item {
visible: media.isSpotify
width: 28
height: 28
Text {
anchors.centerIn: parent
text: "󰒟"
font.pixelSize: 18
color: media.shuffleMode === 0 ? colors.surface2 : colors.blue
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: cycleShuffleMode()
}
}
Text {
text: "󰒮"
font.pixelSize: 22
color: prevHover.containsMouse ? colors.blue : colors.text
MouseArea {
id: prevHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: prevProc.running = true
}
}
Text {
text: media.status === "Playing" ? "󰏤" : "󰐊"
font.pixelSize: 28
color: playHover.containsMouse ? colors.green : colors.text
MouseArea {
id: playHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: playProc.running = true
}
}
Text {
text: "󰒭"
font.pixelSize: 22
color: nextHover.containsMouse ? colors.blue : colors.text
MouseArea {
id: nextHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: nextProc.running = true
}
}
}
}
}
}
}