diff --git a/components/MprisController.qml b/components/MprisController.qml new file mode 100644 index 0000000..2873909 --- /dev/null +++ b/components/MprisController.qml @@ -0,0 +1,98 @@ +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)); + 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() + } + } + } +} diff --git a/constants/Icons.qml b/constants/Icons.qml index 3311396..2e077d2 100644 --- a/constants/Icons.qml +++ b/constants/Icons.qml @@ -19,6 +19,8 @@ Singleton { property string memoryStick: "\u{E44a}" property string play: "\u{E140}" property string search: "\u{E155}" + property string skipBack: "\u{E163}" + property string skipForward: "\u{E164}" property string stop: "\u{E132}" property string square: "\u{E16B}" property string wifiOff: "\u{E1af}" diff --git a/modules/storybook/Storybook.qml b/modules/storybook/Storybook.qml index f2565dc..402c3b9 100644 --- a/modules/storybook/Storybook.qml +++ b/modules/storybook/Storybook.qml @@ -82,6 +82,16 @@ StyledWindow { } } + ColumnLayout { + StyledText { + text: "Mpris Controller" + font.pixelSize: 18 + } + MprisController { + player: Mpris.active ?? null + } + } + ColumnLayout { StyledText { text: "Drawer"