Compare commits

...

3 commits

Author SHA1 Message Date
Benjamin Palko
95d3eb2bcc basic mpris controller 2025-08-27 12:43:56 -04:00
Benjamin Palko
e01096691f update mpris with slider 2025-08-27 12:00:20 -04:00
Benjamin Palko
399f69a68a styled slider 2025-08-27 12:00:10 -04:00
5 changed files with 204 additions and 18 deletions

View file

@ -0,0 +1,99 @@
pragma ComponentBehavior: Bound
import qs.components
import qs.config
import qs.constants
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Mpris
import Quickshell.Widgets
WrapperRectangle {
id: root
required property MprisPlayer player
color: Theme.palette.base200
radius: 8
margin: 16
ColumnLayout {
spacing: 12
implicitWidth: 800
StyledText {
Layout.alignment: Qt.AlignHCenter
text: {
if (root.player.identity) {
const words = root.player.identity.split("-");
const capitalized = words.map(val => String(val).charAt(0).toUpperCase() + String(val).slice(1));
console.log(capitalized);
return capitalized.join(" ");
}
return root.player.desktopEntry ?? root.player.dbusName ?? "unknown";
}
font.pixelSize: 20
}
StyledText {
id: text
Layout.alignment: Qt.AlignHCenter
text: `${root.player.trackTitle} - ${root.player.trackArtist}`
font.pixelSize: Dimensions.mpris.fontSize
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
StyledButton {
id: backButton
content: LucideIcon {
color: backButton.containsMouse ? Theme.palette.primarycontent : Theme.palette.basecontent
text: Icons.skipBack
}
onClicked: {
root.player.previous();
}
}
StyledButton {
id: playPauseButton
content: LucideIcon {
color: playPauseButton.containsMouse ? Theme.palette.primarycontent : Theme.palette.basecontent
text: root.player.isPlaying ? Icons.square : Icons.play
}
onClicked: {
root.player.isPlaying = !root.player.isPlaying;
}
}
StyledButton {
id: forwardButton
content: LucideIcon {
color: forwardButton.containsMouse ? Theme.palette.primarycontent : Theme.palette.basecontent
text: Icons.skipForward
}
onClicked: {
root.player.next();
}
}
}
StyledSlider {
from: 0
to: root.player.length ?? 0
value: root.player.position
implicitHeight: 6
Layout.fillWidth: true
onMoved: {
root.player.position = value;
}
Timer {
running: root.player.isPlaying
interval: 1000
repeat: true
onTriggered: root.player.positionChanged()
}
}
}
}

View file

@ -0,0 +1,33 @@
import qs.config
import QtQuick
import QtQuick.Controls
Slider {
id: control
height: 24
background: Rectangle {
x: control.leftPadding
y: control.topPadding + control.availableHeight / 2 - height / 2
implicitWidth: 200
implicitHeight: control.height
width: control.availableWidth
height: implicitHeight
radius: 8
color: Theme.palette.base100
Rectangle {
width: control.visualPosition * parent.width
Behavior on width {
NumberAnimation {
duration: 75
}
}
height: parent.height
color: Theme.palette.primary
radius: 8
}
}
handle: null
}

View file

@ -19,6 +19,8 @@ Singleton {
property string memoryStick: "\u{E44a}" property string memoryStick: "\u{E44a}"
property string play: "\u{E140}" property string play: "\u{E140}"
property string search: "\u{E155}" property string search: "\u{E155}"
property string skipBack: "\u{E163}"
property string skipForward: "\u{E164}"
property string stop: "\u{E132}" property string stop: "\u{E132}"
property string square: "\u{E16B}" property string square: "\u{E16B}"
property string wifiOff: "\u{E1af}" property string wifiOff: "\u{E1af}"

View file

@ -1,13 +1,17 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import qs.components
import qs.config import qs.config
import qs.services import qs.services
import qs.widgets import qs.widgets
import QtQuick import QtQuick
import QtQuick.Layouts
StyledButton { StyledButton {
id: root id: root
padding: 6
onClicked: { onClicked: {
if (!Mpris.active.canTogglePlaying) { if (!Mpris.active.canTogglePlaying) {
return; return;
@ -19,29 +23,54 @@ StyledButton {
} }
} }
content: StyledText { content: ColumnLayout {
id: text id: content
text: `${Mpris.active?.isPlaying ? "" : ""} ${Mpris.active?.trackTitle} - ${Mpris.active?.trackArtist}`
font.pixelSize: Dimensions.mpris.fontSize spacing: 0
states: State { implicitWidth: text.width
name: "hovered" implicitHeight: text.height
when: root.containsMouse StyledText {
PropertyChanges { id: text
text { text: `${Mpris.active?.isPlaying ? "" : ""} ${Mpris.active?.trackTitle} - ${Mpris.active?.trackArtist}`
color: Theme.palette.base300
font.pixelSize: Dimensions.mpris.fontSize
states: State {
name: "hovered"
when: root.containsMouse
PropertyChanges {
text {
color: Theme.palette.primarycontent
}
}
}
transitions: Transition {
from: ""
to: "hovered"
reversible: true
ColorAnimation {
properties: "color"
duration: 100
easing.type: Easing.InOutCubic
} }
} }
} }
transitions: Transition { StyledSlider {
from: "" from: 0
to: "hovered" to: Mpris.active?.length ?? 0
reversible: true value: Mpris.active?.position
ColorAnimation { implicitHeight: 6
properties: "color" Layout.fillWidth: true
duration: 200 onMoved: {
easing.type: Easing.InOutCubic Mpris.active.position = value;
}
Timer {
running: Mpris.active?.isPlaying
interval: 1000
repeat: true
onTriggered: Mpris.active?.positionChanged()
} }
} }
} }

View file

@ -69,6 +69,29 @@ StyledWindow {
} }
} }
ColumnLayout {
StyledText {
text: "Slider"
font.pixelSize: 18
}
StyledSlider {
id: slider
from: 0
to: 100
value: 50
}
}
ColumnLayout {
StyledText {
text: "Mpris Controller"
font.pixelSize: 18
}
MprisController {
player: Mpris.active ?? null
}
}
ColumnLayout { ColumnLayout {
StyledText { StyledText {
text: "Drawer" text: "Drawer"