mirror of
https://github.com/kossLAN/dots.git
synced 2025-11-04 22:49:50 -05:00
mpris: add ipc handler for multimedia keys
This commit is contained in:
parent
15ffd6d5b0
commit
233e12e094
8 changed files with 43 additions and 456 deletions
|
|
@ -1,177 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
import Quickshell
|
|
||||||
import "../.."
|
|
||||||
import "../../widgets" as Widgets
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
required property var player
|
|
||||||
|
|
||||||
radius: 5
|
|
||||||
color: "transparent"
|
|
||||||
implicitHeight: 220
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: cardLayout
|
|
||||||
spacing: 15
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
leftMargin: 10
|
|
||||||
rightMargin: 10
|
|
||||||
topMargin: 10 // Added top margin for better spacing
|
|
||||||
bottomMargin: 10 // Added bottom margin for better spacing
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: mprisImage
|
|
||||||
color: "transparent"
|
|
||||||
radius: 10
|
|
||||||
width: 200
|
|
||||||
height: 200
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
visible: true
|
|
||||||
|
|
||||||
Image {
|
|
||||||
anchors.fill: parent
|
|
||||||
source: player.trackArtUrl
|
|
||||||
sourceSize.width: 1024
|
|
||||||
sourceSize.height: 1024
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: OpacityMask {
|
|
||||||
source: Rectangle {
|
|
||||||
width: mprisImage.width
|
|
||||||
height: mprisImage.height
|
|
||||||
radius: 10
|
|
||||||
color: "white"
|
|
||||||
}
|
|
||||||
|
|
||||||
maskSource: Rectangle {
|
|
||||||
width: mprisImage.width
|
|
||||||
height: mprisImage.height
|
|
||||||
radius: 10
|
|
||||||
color: "black"
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: DropShadow {
|
|
||||||
transparentBorder: true
|
|
||||||
spread: 0.02
|
|
||||||
samples: 25
|
|
||||||
color: "#80000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: player.trackArtist
|
|
||||||
color: "white"
|
|
||||||
font.pointSize: 13
|
|
||||||
font.bold: true
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: player.trackTitle
|
|
||||||
color: "white"
|
|
||||||
font.pointSize: 13
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: 6
|
|
||||||
|
|
||||||
ColorQuantizer {
|
|
||||||
id: colorQuantizer
|
|
||||||
source: Qt.resolvedUrl(Media.trackedPlayer?.trackArtUrl ?? "")
|
|
||||||
depth: 0
|
|
||||||
rescaleSize: 64
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: timeStr(player.position)
|
|
||||||
color: "white"
|
|
||||||
|
|
||||||
font {
|
|
||||||
pointSize: 9
|
|
||||||
bold: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widgets.RoundSlider {
|
|
||||||
from: 0
|
|
||||||
to: 1
|
|
||||||
accentColor: colorQuantizer.colors[0]
|
|
||||||
//value: root.node.audio.volume
|
|
||||||
//onValueChanged: node.audio.volume = value
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 16
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: timeStr(player.length)
|
|
||||||
color: "white"
|
|
||||||
|
|
||||||
font {
|
|
||||||
pointSize: 9
|
|
||||||
bold: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Music Controls
|
|
||||||
RowLayout {
|
|
||||||
spacing: 2
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
|
|
||||||
Widgets.IconButton {
|
|
||||||
implicitSize: 36
|
|
||||||
activeRectangle: false
|
|
||||||
padding: 4
|
|
||||||
source: "root:resources/mpris/previous.svg"
|
|
||||||
onClicked: player.previous()
|
|
||||||
}
|
|
||||||
|
|
||||||
Widgets.IconButton {
|
|
||||||
implicitSize: 36
|
|
||||||
activeRectangle: false
|
|
||||||
padding: 4
|
|
||||||
source: player?.isPlaying ? "root:resources/mpris/pause.svg" : "root:resources/mpris/play.svg"
|
|
||||||
onClicked: {
|
|
||||||
if (!player.canPlay)
|
|
||||||
return;
|
|
||||||
player.isPlaying ? player.pause() : player.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widgets.IconButton {
|
|
||||||
implicitSize: 36
|
|
||||||
activeRectangle: false
|
|
||||||
padding: 4
|
|
||||||
source: "root:resources/mpris/next.svg"
|
|
||||||
onClicked: player.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function timeStr(time: int): string {
|
|
||||||
const seconds = time % 60;
|
|
||||||
const minutes = Math.floor(time / 60);
|
|
||||||
|
|
||||||
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Services.Mpris
|
|
||||||
import "../.."
|
|
||||||
|
|
||||||
PopupWindow {
|
|
||||||
id: root
|
|
||||||
width: mediaPlayerContainer.width + 10
|
|
||||||
height: mediaPlayerContainer.height + 10
|
|
||||||
color: "transparent"
|
|
||||||
visible: mediaPlayerContainer.opacity > 0
|
|
||||||
|
|
||||||
anchor.rect.x: parentWindow.width / 2 - width / 2
|
|
||||||
anchor.rect.y: parentWindow.height
|
|
||||||
|
|
||||||
function show() {
|
|
||||||
mediaPlayerContainer.opacity = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
mediaPlayerContainer.opacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
id: hoverHandler
|
|
||||||
enabled: true
|
|
||||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
|
||||||
onHoveredChanged: {
|
|
||||||
if (hovered == false) {
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: mediaPlayerContainer
|
|
||||||
width: 500
|
|
||||||
height: mediaPlayerColumn.height + 20
|
|
||||||
color: ShellGlobals.colors.background
|
|
||||||
radius: 5
|
|
||||||
opacity: 0
|
|
||||||
anchors.centerIn: parent
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: OpacityMask {
|
|
||||||
source: Rectangle {
|
|
||||||
width: mediaPlayerContainer.width
|
|
||||||
height: mediaPlayerContainer.height
|
|
||||||
radius: mediaPlayerContainer.radius
|
|
||||||
color: "white"
|
|
||||||
}
|
|
||||||
|
|
||||||
maskSource: Rectangle {
|
|
||||||
width: mediaPlayerContainer.width
|
|
||||||
height: mediaPlayerContainer.height
|
|
||||||
radius: mediaPlayerContainer.radius
|
|
||||||
color: "black"
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: DropShadow {
|
|
||||||
transparentBorder: true
|
|
||||||
spread: 0.02
|
|
||||||
samples: 25
|
|
||||||
color: "#80000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorQuantizer {
|
|
||||||
id: colorQuantizer
|
|
||||||
source: Qt.resolvedUrl(Media.trackedPlayer?.trackArtUrl ?? "")
|
|
||||||
depth: 2
|
|
||||||
rescaleSize: 64
|
|
||||||
|
|
||||||
onColorsChanged: {
|
|
||||||
Media.colors = colors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderEffect {
|
|
||||||
property color topLeftColor: colorQuantizer?.colors[0]?.lighter(1.2) ?? "white"
|
|
||||||
property color topRightColor: colorQuantizer?.colors[1]?.lighter(1.2) ?? "black"
|
|
||||||
property color bottomLeftColor: colorQuantizer?.colors[2]?.lighter(1.2) ?? "white"
|
|
||||||
property color bottomRightColor: colorQuantizer?.colors[3]?.lighter(1.2) ?? "black"
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
fragmentShader: "root:/shaders/vertexgradient.frag.qsb"
|
|
||||||
vertexShader: "root:/shaders/vertexgradient.vert.qsb"
|
|
||||||
|
|
||||||
Behavior on topLeftColor {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: 500
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on topRightColor {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: 500
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on bottomLeftColor {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: 500
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on bottomRightColor {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: 500
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: mediaPlayerColumn
|
|
||||||
spacing: 10
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredWidth: parent.width
|
|
||||||
Layout.margins: 10
|
|
||||||
implicitHeight: childrenRect.height
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
margins: 10
|
|
||||||
}
|
|
||||||
|
|
||||||
// Media Cards
|
|
||||||
Repeater {
|
|
||||||
model: Mpris.players
|
|
||||||
|
|
||||||
Card {
|
|
||||||
required property var modelData
|
|
||||||
player: modelData
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import Quickshell.Widgets
|
|
||||||
import Quickshell.Services.Mpris
|
|
||||||
import "../.."
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
required property var bar
|
|
||||||
|
|
||||||
width: statusInfo.width + 125
|
|
||||||
height: parent.height
|
|
||||||
visible: Mpris.players.values.length != 0
|
|
||||||
|
|
||||||
Player {
|
|
||||||
id: mediaPlayer
|
|
||||||
anchor.window: bar
|
|
||||||
anchor.rect.x: parentWindow.width / 2 - width / 2
|
|
||||||
anchor.rect.y: parentWindow.height
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: playButton
|
|
||||||
hoverEnabled: true
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
onClicked: mouse => {
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
|
||||||
if (mediaPlayer.visible) {
|
|
||||||
mediaPlayer.hide();
|
|
||||||
} else {
|
|
||||||
mediaPlayer.show();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!Media.trackedPlayer.canPlay || Media.trackedPlayer == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Media.trackedPlayer.isPlaying)
|
|
||||||
Media.trackedPlayer.pause();
|
|
||||||
else
|
|
||||||
Media.trackedPlayer.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: statusInfo
|
|
||||||
width: statusIcon.width + statusIcon.anchors.rightMargin + nowPlayingText.width
|
|
||||||
height: parent.height
|
|
||||||
visible: Media.trackedPlayer != null
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
top: parent.top
|
|
||||||
bottom: parent.botton
|
|
||||||
margins: 3.5
|
|
||||||
}
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
id: statusIcon
|
|
||||||
implicitSize: 13
|
|
||||||
source: Media.trackedPlayer?.isPlaying ? "root:resources/mpris/pause.svg" : "root:resources/mpris/play.svg"
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
right: nowPlayingText.left
|
|
||||||
rightMargin: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: nowPlayingText
|
|
||||||
color: ShellGlobals.colors.text
|
|
||||||
text: `${Media.trackedPlayer?.trackArtist} - ${Media.trackedPlayer?.trackTitle}`
|
|
||||||
font.pointSize: 11
|
|
||||||
width: Math.min(implicitWidth, 250)
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
# Lockscreen
|
|
||||||
|
|
||||||
This is a simple but functional lockscreen that follows the system color scheme.
|
|
||||||
The only authentication method it supports is a password.
|
|
||||||
|
|
||||||
You can run the lockscreen with `quickshell -p shell.qml`.
|
|
||||||
|
|
||||||
You can run the lockscreen in test mode (as a window) with `quickshell -p test.qml`.
|
|
||||||
|
|
||||||

|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
|
|
@ -1,25 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
ShellRoot {
|
|
||||||
LockContext {
|
|
||||||
id: lockContext
|
|
||||||
onUnlocked: Qt.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
FloatingWindow {
|
|
||||||
LockSurface {
|
|
||||||
anchors.fill: parent
|
|
||||||
context: lockContext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// exit the example if the window closes
|
|
||||||
Connections {
|
|
||||||
target: Quickshell
|
|
||||||
|
|
||||||
function onLastWindowClosed() {
|
|
||||||
Qt.quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,42 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
property MprisPlayer trackedPlayer
|
property MprisPlayer trackedPlayer
|
||||||
property var colors: ["white"]
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "mpris"
|
||||||
|
|
||||||
|
function next(): void {
|
||||||
|
root.trackedPlayer.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
function prev(): void {
|
||||||
|
root.trackedPlayer.previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
function play(): void {
|
||||||
|
root.trackedPlayer.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
function pause(): void {
|
||||||
|
root.trackedPlayer.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
function play_pause(): void {
|
||||||
|
if (root.trackedPlayer.isPlaying) {
|
||||||
|
root.trackedPlayer.pause();
|
||||||
|
} else {
|
||||||
|
root.trackedPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: Mpris.players
|
model: Mpris.players
|
||||||
|
|
@ -31,8 +60,8 @@ Singleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackedPlayer == null && Mpris.players.values.length != 0) {
|
if (root.trackedPlayer == null && Mpris.players.values.length != 0) {
|
||||||
trackedPlayer = Mpris.players.values[0];
|
root.trackedPlayer = Mpris.players.values[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -43,4 +72,6 @@ Singleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function init() {}
|
||||||
}
|
}
|
||||||
13
shell.qml
13
shell.qml
|
|
@ -5,6 +5,7 @@ import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "bar" as Bar
|
import "bar" as Bar
|
||||||
import "notifications" as Notifications
|
import "notifications" as Notifications
|
||||||
|
import "mpris" as Mpris
|
||||||
import "volume-osd" as VolumeOSD
|
import "volume-osd" as VolumeOSD
|
||||||
import "settings" as Settings
|
import "settings" as Settings
|
||||||
import "launcher" as Launcher
|
import "launcher" as Launcher
|
||||||
|
|
@ -13,13 +14,16 @@ import "wallpaper" as Wallpaper
|
||||||
import "screencapture" as ScreenCapture
|
import "screencapture" as ScreenCapture
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
|
// Singleton's that need to be loaded in some way
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Launcher.Controller.init();
|
Launcher.Controller.init();
|
||||||
Settings.Controller.init();
|
Settings.Controller.init();
|
||||||
Notifications.NotificationCenter.init();
|
|
||||||
ScreenCapture.Controller.init();
|
ScreenCapture.Controller.init();
|
||||||
|
Mpris.Controller.init();
|
||||||
|
Notifications.NotificationCenter.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Elements that need context from all screens
|
||||||
Variants {
|
Variants {
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
|
@ -31,13 +35,14 @@ ShellRoot {
|
||||||
screen: scope.modelData
|
screen: scope.modelData
|
||||||
}
|
}
|
||||||
|
|
||||||
LockScreen.Controller {
|
LockScreen.Controller {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On activation components
|
||||||
Notifications.Controller {}
|
Notifications.Controller {}
|
||||||
VolumeOSD.Controller {}
|
VolumeOSD.Controller {}
|
||||||
|
|
||||||
|
// this is an exception...
|
||||||
Wallpaper.Controller {}
|
Wallpaper.Controller {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue