quickshell media player enchantments

This commit is contained in:
2025-07-28 02:41:01 +01:00
parent 22df7e7181
commit 097fee8d1c
10 changed files with 192 additions and 91 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#EA3323"><path d="m710-362-58-58q14-23 21-48t7-52h80q0 44-13 83.5T710-362ZM592-482 360-714v-46q0-50 35-85t85-35q50 0 85 35t35 85v240q0 11-2.5 20t-5.5 18ZM440-120v-124q-104-14-172-92.5T200-520h80q0 83 58.5 141.5T480-320q34 0 64.5-10.5T600-360l57 57q-29 23-63.5 38.5T520-244v124h-80Zm352 64L56-792l56-56 736 736-56 56Z"/></svg>

After

Width:  |  Height:  |  Size: 424 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#EA3323"><path d="M792-56 671-177q-25 16-53 27.5T560-131v-82q14-5 27.5-10t25.5-12L480-368v208L280-360H120v-240h128L56-792l56-56 736 736-56 56Zm-8-232-58-58q17-31 25.5-65t8.5-70q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 53-14.5 102T784-288ZM650-422l-90-90v-130q47 22 73.5 66t26.5 96q0 15-2.5 29.5T650-422ZM480-592 376-696l104-104v208Z"/></svg>

After

Width:  |  Height:  |  Size: 450 B

View File

@@ -8,6 +8,7 @@ import Quickshell.Widgets
import "widgets" as Widgets import "widgets" as Widgets
import "widgets/player" as Player import "widgets/player" as Player
import "widgets/common" as Common import "widgets/common" as Common
import "widgets/clock" as Clock
// Tako kindly threatened you to sort the naming schema and to put all the svg's in an asset folder, so please do that // Tako kindly threatened you to sort the naming schema and to put all the svg's in an asset folder, so please do that
@@ -22,15 +23,20 @@ import "widgets/common" as Common
right: true right: true
} }
implicitHeight: 30 implicitHeight: 32
RowLayout { RowLayout {
height: 28
anchors { anchors {
fill: parent top: parent.top
left: parent.left
right: parent.right
// bottomMargin: 2
leftMargin: 10 leftMargin: 10
rightMargin: 10 rightMargin: 10
} }
RowLayout { // Left RowLayout { // Left
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
Clock.Date {}
} }
RowLayout { // Center RowLayout { // Center
// TODO: add icons of the active window per workspace in the workspace tab // TODO: add icons of the active window per workspace in the workspace tab
@@ -50,13 +56,7 @@ import "widgets/common" as Common
} }
} }
Common.VerticalSeprator {} Common.VerticalSeprator {}
WrapperItem { Clock.Clock {}
Text { // Date & Time
text: Widgets.Time.time
color: '#FFFFFF'
font.pointSize: 10.75
}
}
Widgets.SystemTray { Widgets.SystemTray {
id: systemTray id: systemTray
} }
@@ -68,7 +68,7 @@ import "widgets/common" as Common
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
height: 2 height: 1
color: "#8d8d8d" color: "#8d8d8d"
} }
} }

View File

@@ -18,30 +18,26 @@ Item {
RowLayout { RowLayout {
id: row id: row
Item {
IconImage { implicitWidth: 28
// anchors.centerIn: parent implicitHeight: 28
implicitSize: 27 Rectangle {
source: "root:/assets/bar/Speaker.svg" width: parent.width
} height: parent.height
radius: 7
color: "black"
Text { }
id: text IconImage {
text: root.speakerNode.audio.muted ? "0%" : root.speakerNode.audio.volume * 100 + "%" anchors.centerIn: parent
font.pointSize: 10.75 implicitSize: 25
color: root.speakerNode.audio.muted ? "red" : "#FFFFFF" source: root.speakerNode.audio.muted ? "root:/assets/bar/MutedSpeaker.svg" : "root:/assets/bar/Speaker.svg"
// source: "root:/assets/bar/Speaker.svg"
} }
IconImage {
implicitSize: 26
source: "root:/assets/bar/Mic.svg"
} }
IconImage {
Text { implicitSize: 25
text: parseInt(root.microphoneNode.audio.muted ? "0" : root.microphoneNode.audio.volume * 100) + "%" source: root.microphoneNode.audio.muted ? "root:/assets/bar/MutedMic.svg" : "root:/assets/bar/Mic.svg"
font.pointSize: 10.75 // source: "root:/assets/bar/Mic.svg"
color: root.microphoneNode.audio.muted ? "red" : "#FFFFFF"
} }
} }
} }

View File

@@ -1,18 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
readonly property string time: {
Qt.formatDateTime(clock.date, "ddd d MMM [hh:mm]")
}
SystemClock {
id: clock
precision: SystemClock.Minutes
}
}

View File

@@ -0,0 +1,18 @@
import Quickshell
import Quickshell.Io
import QtQuick
import "../common" as Common
Item {
id: root
width: text.width
height: text.height
Common.Container {}
Text {
id: text
text: ClockData.time
font.pointSize: 10.25
color: "white"
}
}

View File

@@ -0,0 +1,22 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
readonly property string time: {
// Qt.formatDateTime(clock.date, "ddd d MMM [hh:mm]")
Qt.formatDateTime(clock.date, "hh:mm")
}
readonly property string date: {
Qt.formatDateTime(clock.date, "d MMM")
// Qt.formatDateTime(clock.date, "hh:mm")
}
SystemClock {
id: clock
precision: SystemClock.Minutes
}
}

View File

@@ -0,0 +1,19 @@
import Quickshell
import Quickshell.Io
import QtQuick
import "../common" as Common
Item {
id: root
width: text.width + 15
height: text.height
Common.Container {}
Text {
anchors.centerIn: parent
id: text
text: ClockData.date
font.pointSize: 10.25
color: "white"
}
}

View File

@@ -0,0 +1,13 @@
import Quickshell
import QtQuick
Rectangle {
z: -1
color: "black"
anchors {
verticalCenter: parent.verticalCenter
}
height: 25
width: parent.width
radius: 7
}

View File

@@ -3,11 +3,16 @@ import QtQuick
import Quickshell import Quickshell
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls import QtQuick.Controls
import Quickshell.Widgets
import Quickshell.Services.Mpris import Quickshell.Services.Mpris
PopupWindow { PopupWindow {
property PlayerControllerV2 player: PlayerControllerV2; property PlayerControllerV2 player: PlayerControllerV2;
readonly property string elementBackgroundColor : "#323232"
readonly property string elementButtonBaseColor : "#515151"
readonly property string elementButtonHoverColor : "#737373"
id: audioPopup id: audioPopup
anchor { anchor {
item: root item: root
@@ -16,6 +21,7 @@ PopupWindow {
anchor.rect.y: root.height * 1.2 anchor.rect.y: root.height * 1.2
height: columnContainer.height + 5 height: columnContainer.height + 5
width: 425 width: 425
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#919191" color: "#919191"
@@ -26,15 +32,15 @@ PopupWindow {
model: player.mpris.players model: player.mpris.players
Item { Item {
id: root id: root
width: 400 width: 375
height: 80 height: 110
required property MprisPlayer modelData required property MprisPlayer modelData
property string trackPosition: PlayerControllerV2.trackPositionFormatter(root.modelData.position) property string trackPosition: PlayerControllerV2.trackPositionFormatter(root.modelData.position)
property string trackLength: "0:00" property string trackLength: "0:00"
Rectangle { Rectangle {
id: background id: background
anchors.fill: parent anchors.fill: parent
color: "black" color: audioPopup.elementBackgroundColor
radius: 7 radius: 7
} }
MouseArea { MouseArea {
@@ -48,21 +54,23 @@ PopupWindow {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
width:380 width:root.width - 15
RowLayout { RowLayout {
implicitWidth: 380 implicitWidth: root.width - 15
Item { ClippingWrapperRectangle {
implicitWidth: 50 implicitWidth: 75
implicitHeight: 50 implicitHeight: 75
radius: 7
Image { Image {
anchors.fill: parent anchors.fill: parent
mipmap: true
source: root.modelData.trackArtUrl source: root.modelData.trackArtUrl
} }
} }
ColumnLayout { ColumnLayout {
spacing: 2 spacing: 2
ScrollView { ScrollView {
implicitWidth: 230 implicitWidth: 180
height: parent.height height: parent.height
Text { Text {
@@ -75,7 +83,7 @@ PopupWindow {
Text { Text {
text: root.modelData.trackArtist text: root.modelData.trackArtist
color: "white" color: "white"
font.pointSize: 6 font.pointSize: 8
antialiasing: true antialiasing: true
} }
} }
@@ -84,28 +92,41 @@ PopupWindow {
Layout.fillWidth: true Layout.fillWidth: true
} }
RowLayout { RowLayout {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// Layout.
spacing: 0 spacing: 0
// buttons // buttons
Item { Item {
width: 30 implicitWidth: 30
height: 25 implicitHeight: 25
Rectangle { Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
id: gobackButton Item {
width: 30 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
height: 25 Rectangle {
topLeftRadius: 7 id: gobackButton
bottomLeftRadius: 7 width: 30
color: "white" 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 { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: event => { onEntered: event => {
gobackButton.color = "grey" gobackButton.color = audioPopup.elementButtonHoverColor
} }
onExited: event => { onExited: event => {
gobackButton.color = "white" gobackButton.color = audioPopup.elementButtonBaseColor
}
onClicked: event => {
root.modelData.previous();
} }
} }
} }
@@ -113,6 +134,7 @@ PopupWindow {
width: 30 width: 30
height: 25 height: 25
Item { Item {
Layout.alignment: Qt.AlignCenter
width: 30 width: 30
height: 25 height: 25
Rectangle { Rectangle {
@@ -121,7 +143,13 @@ PopupWindow {
height: 25 height: 25
// topLeftRadius: 7 // topLeftRadius: 7
// bottomLeftRadius: 7 // bottomLeftRadius: 7
color: "white" 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 { MouseArea {
@@ -129,10 +157,10 @@ PopupWindow {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: event => { onEntered: event => {
pauseButton.color = "grey" pauseButton.color = audioPopup.elementButtonHoverColor
} }
onExited: event => { onExited: event => {
pauseButton.color = "white" pauseButton.color = audioPopup.elementButtonBaseColor
} }
onClicked: event => { onClicked: event => {
root.modelData.togglePlaying(); root.modelData.togglePlaying();
@@ -142,22 +170,33 @@ PopupWindow {
Item { Item {
width: 30 width: 30
height: 25 height: 25
Rectangle { Item {
id: gonextButton Layout.alignment: Qt.AlignCenter
width: 30 Rectangle {
height: 25 id: gonextButton
topRightRadius: 7 width: 30
bottomRightRadius: 7 height: 25
color: "white" topRightRadius: 7
bottomRightRadius: 7
color: audioPopup.elementButtonBaseColor
}
IconImage {
Layout.alignment: Qt.AlignCenter
implicitSize: 25
source: "root:/assets/media_player/skip_next.svg"
}
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: event => { onEntered: event => {
gonextButton.color = "grey" gonextButton.color = audioPopup.elementButtonHoverColor
} }
onExited: event => { onExited: event => {
gonextButton.color = "white" gonextButton.color = audioPopup.elementButtonBaseColor
}
onClicked: event => {
root.modelData.next();
} }
} }
} }
@@ -170,15 +209,20 @@ PopupWindow {
from: 0 from: 0
value: root.modelData.position value: root.modelData.position
to: root.modelData.length to: root.modelData.length
property double lastPosition;
property bool debounceValue: false;
onMoved: event => { onMoved: event => {
root.modelData.position = slider.value debounceValue = true; // there is insane lag if we put the move logic here, so its better to trigger a time with the logic instead
audioPopup.player.update(); // force values to update // causing ui to update with it
} }
Timer { Timer {
running: root.modelData.playbackState == MprisPlaybackState.Playing running: slider.debounceValue
interval: 500 interval: 250
repeat: true repeat: true
onTriggered: slider.value = root.modelData.position onTriggered: {
root.modelData.position = slider.value
audioPopup.player.update(); // force values to update // causing ui to update with it
slider.debounceValue = false;
}
} }
} }
Text { Text {
@@ -190,12 +234,17 @@ PopupWindow {
} }
} }
Timer { Timer {
running: root.modelData.isPlaying id: updateTimer
interval: 1000 property bool tempOneshot: false;
running: root.modelData.isPlaying || (root.modelData.position != slider.lastPosition)
interval: 750
repeat: true repeat: true
onTriggered: { onTriggered: {
trackPosition = PlayerControllerV2.trackPositionFormatter(root.modelData.position) trackPosition = PlayerControllerV2.trackPositionFormatter(root.modelData.position)
trackLength = PlayerControllerV2.trackPositionFormatter(root.modelData.length) trackLength = PlayerControllerV2.trackPositionFormatter(root.modelData.length)
updateTimer.tempOneshot = false;
slider.lastPosition = slider.value
slider.value = root.modelData.position
} }
} }
} }