Files
dotfiles/quickshell/bar/widgets/player/PlayerPopupV2.qml
doloro 2e94f6dac3 meow
2025-09-22 20:55:16 +00:00

255 lines
12 KiB
QML
Executable File

import QtQml
import QtQuick
import Quickshell
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell.Widgets
import Quickshell.Services.Mpris
PopupWindow {
property PlayerControllerV2 player: PlayerControllerV2;
readonly property string elementBackgroundColor : "#323232"
readonly property string elementButtonBaseColor : "#515151"
readonly property string elementButtonHoverColor : "#737373"
id: audioPopup
anchor {
item: root
}
anchor.rect.x: root.width / 2 - width / 2
anchor.rect.y: root.height * 1.2
height: columnContainer.height + 5
width: 425
Rectangle {
anchors.fill: parent
color: "#919191"
ColumnLayout {
id: columnContainer
anchors.centerIn: parent
Repeater {
model: player.mpris.players
Item {
id: root
width: 375
height: 110
required property MprisPlayer modelData
property string trackPosition: PlayerControllerV2.trackPositionFormatter(root.modelData.position)
property string trackLength: "0:00"
Rectangle {
id: background
anchors.fill: parent
color: audioPopup.elementBackgroundColor
radius: 7
}
MouseArea {
anchors.fill: parent
onClicked: event => {
audioPopup.player.setActivePlayer(root.modelData);
audioPopup.player.update();
}
}
ColumnLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Layout.alignment: Qt.AlignHCenter
width:root.width - 15
RowLayout {
implicitWidth: root.width - 15
ClippingWrapperRectangle {
implicitWidth: 75
implicitHeight: 75
radius: 7
Image {
anchors.fill: parent
mipmap: true
source: root.modelData.trackArtUrl
}
}
ColumnLayout {
spacing: 2
ScrollView {
implicitWidth: 180
height: parent.height
Text {
text: root.modelData.trackTitle
color: "white"
font.pointSize: 11
antialiasing: true
}
}
Text {
text: root.modelData.trackArtist
color: "white"
font.pointSize: 8
antialiasing: true
}
}
Rectangle { // Spacer
color: "transparent"
Layout.fillWidth: true
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// Layout.
spacing: 0
// buttons
Item {
implicitWidth: 30
implicitHeight: 25
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Item {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Rectangle {
id: gobackButton
width: 30
height: 25
topLeftRadius: 7
bottomLeftRadius: 7
color: audioPopup.elementButtonBaseColor
}
IconImage {
Layout.alignment: Qt.AlignCenter
implicitSize: 25
source: "root:/assets/media_player/skip_previous.svg"
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
gobackButton.color = audioPopup.elementButtonHoverColor
}
onExited: event => {
gobackButton.color = audioPopup.elementButtonBaseColor
}
onClicked: event => {
root.modelData.previous();
}
}
}
Item {
width: 30
height: 25
Item {
Layout.alignment: Qt.AlignCenter
width: 30
height: 25
Rectangle {
id: pauseButton
width: 30
height: 25
// topLeftRadius: 7
// bottomLeftRadius: 7
color: audioPopup.elementButtonBaseColor
}
IconImage {
Layout.alignment: Qt.AlignCenter
anchors.centerIn: parent
implicitSize: 25
source: root.modelData.isPlaying ? "root:/assets/media_player/pausebutton.svg" : "root:/assets/media_player/playbutton.svg"
}
}
MouseArea {
// id: pauseButton
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
pauseButton.color = audioPopup.elementButtonHoverColor
}
onExited: event => {
pauseButton.color = audioPopup.elementButtonBaseColor
}
onClicked: event => {
root.modelData.togglePlaying();
}
}
}
Item {
width: 30
height: 25
Item {
Layout.alignment: Qt.AlignCenter
Rectangle {
id: gonextButton
width: 30
height: 25
topRightRadius: 7
bottomRightRadius: 7
color: audioPopup.elementButtonBaseColor
}
IconImage {
Layout.alignment: Qt.AlignCenter
implicitSize: 25
source: "root:/assets/media_player/skip_next.svg"
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
gonextButton.color = audioPopup.elementButtonHoverColor
}
onExited: event => {
gonextButton.color = audioPopup.elementButtonBaseColor
}
onClicked: event => {
root.modelData.next();
}
}
}
}
}
RowLayout {
Slider {
id: slider
Layout.fillWidth: true
from: 0
value: root.modelData.position
to: root.modelData.length
property double lastPosition;
property bool debounceValue: false;
onMoved: event => {
debounceValue = true; // there is insane lag if we put the move logic here, so its better to trigger a time with the logic instead
}
Timer {
running: slider.debounceValue
interval: 250
repeat: true
onTriggered: {
root.modelData.position = slider.value
slider.debounceValue = false;
}
}
}
Text {
id: positionText
text: trackPosition + "/" + trackLength // returns float of seconds of length
color: "white"
font.pointSize: 10
}
}
}
Timer {
id: updateTimer
property bool tempOneshot: false;
running: root.modelData.isPlaying || (root.modelData.position != slider.lastPosition)
interval: 750
repeat: true
onTriggered: {
trackPosition = PlayerControllerV2.trackPositionFormatter(root.modelData.position)
trackLength = PlayerControllerV2.trackPositionFormatter(root.modelData.length)
updateTimer.tempOneshot = false;
slider.lastPosition = slider.value
slider.value = root.modelData.position
// root.audioPopup.player.update();
}
}
}
}
}
}
}