import QtQuick import QtQuick.Shapes import Quickshell import Quickshell.Widgets import Quickshell.Services.Mpris import Quickshell.Services.Notifications import "../Widgets" as Widgets Item { anchors { top: parent.top horizontalCenter: parent.horizontalCenter } width: childrenRect.width + 12 height: childrenRect.height + 12 Row { spacing: 6 x: 6 y: 6 Rectangle { width: 400 height: 300 color: "#111" radius: 10 Column { anchors.centerIn: parent spacing: 2 opacity: !notifServer.trackedNotifications.values.length Behavior on opacity {NumberAnimation {duration: 150}} Image { anchors.horizontalCenter: parent.horizontalCenter source: Quickshell.shellPath("assets/notif.svg") width: 24 height: 24 sourceSize {width: width; height: height} opacity: 0.5 } Text { anchors.horizontalCenter: parent.horizontalCenter color: "#888" text: "No notifications" } } ListView { anchors.fill: parent anchors.leftMargin: 4 anchors.rightMargin: anchors.leftMargin clip: true spacing: 4 add: Transition {NumberAnimation { property: "opacity" from: 0 to: 1 duration: 150 }} remove: Transition {NumberAnimation { property: "opacity" from: 1 to: 0 duration: 150 }} displaced: Transition {NumberAnimation { property: "y" duration: 300 }} header: Item {height: 4; width: 1} model: Array.from(notifServer.trackedNotifications.values) delegate: Widgets.Notification { color: "#181818" } } } Item { id: player property var modelData: Mpris.players.values[0] height: 300 width: 250 Column { anchors.centerIn: parent spacing: 2 opacity: !Mpris.players.values.length Behavior on opacity {NumberAnimation {duration: 150}} Image { anchors.horizontalCenter: parent.horizontalCenter source: Quickshell.shellPath("assets/player-symbolic.svg") width: 24 height: 24 sourceSize {width: width; height: height} opacity: 0.5 } Text { anchors.horizontalCenter: parent.horizontalCenter color: "#888" text: "Nothing playing" } } Column { anchors { left: parent.left right: parent.right verticalCenter: parent.verticalCenter margins: 6 } opacity: Mpris.players.values.length Behavior on opacity {NumberAnimation {duration: 150}} Shape { id: progressShape anchors.horizontalCenter: parent.horizontalCenter width: 160 height: width property var strokeWidth: 6 preferredRendererType: Shape.CurveRenderer ShapePath { capStyle: ShapePath.RoundCap strokeColor: "#444" fillColor: "transparent" strokeWidth: progressShape.strokeWidth PathAngleArc { moveToStart: true radiusX: (progressShape.width-progressShape.strokeWidth)/2 radiusY: (progressShape.height-progressShape.strokeWidth)/2 centerX: progressShape.width/2 centerY: progressShape.height/2 startAngle: 90 + 20 sweepAngle: 360 - 40 } } ShapePath { capStyle: ShapePath.RoundCap strokeColor: "white" fillColor: "transparent" strokeWidth: 6 PathAngleArc { moveToStart: true radiusX: (progressShape.width-progressShape.strokeWidth)/2 radiusY: (progressShape.height-progressShape.strokeWidth)/2 centerX: progressShape.width/2 centerY: progressShape.height/2 startAngle: 90 + 20 sweepAngle: (player.modelData?.position/player.modelData.length) * (360 - 40) } } ClippingRectangle { color: "transparent" radius: height/2 anchors.fill: parent anchors.margins: progressShape.strokeWidth*2 Image { anchors.fill: parent fillMode: Image.PreserveAspectCrop mipmap: true smooth: true source: player.modelData?.trackArtUrl ?? source } NumberAnimation on rotation { id: spin paused: !player.modelData?.isPlaying || !root.up || background.index !== 3 duration: 60000 loops: Animation.Infinite from: 0 to: 360 } layer.enabled: true layer.smooth: true } } Item {width: 1; height: 10} Text { anchors { left: parent.left right: parent.right } horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight color: "white" text: player.modelData?.trackTitle ?? "" font.pixelSize: 16 } Text { anchors { left: parent.left right: parent.right } horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight color: "white" text: player.modelData?.trackArtist ?? "" font.pixelSize: 12 } Item {width: 1; height: 8} Row { height: childrenRect.height anchors.horizontalCenter: parent.horizontalCenter component Button: Rectangle { id: button property var action property var clicked radius: 12 color: hover.hovered ? "#11ffffff" : "#00ffffff" property var hover: HoverHandler {} width: 40 height: width Image { anchors.fill: parent anchors.margins: 8 sourceSize {width: width; height: height} source: Quickshell.shellPath(`assets/lazer-${action}-symbolic.svg`) } TapHandler {onTapped: button.clicked()} } Button { action: "previous" clicked: player.modelData?.previous } Button { action: player.modelData?.isPlaying ? "pause" : "play" clicked: player.modelData?.togglePlaying } Button { action: "next" clicked: player.modelData?.next } } FrameAnimation { running: background.index === 3 onTriggered: player.modelData.positionChanged() } } } } }