Files
dualsense-qs/DualsenseWidget.qml
T
2026-09-29 01:05:45 +02:00

237 lines
5.6 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Io
PanelWindow {
id: root
visible: controller !== null && controller.connected
aboveWindows: false
anchors {
right: true
top: true
}
margins {
top: 16
right: 8
}
implicitWidth: expanded ? 300 : 22
implicitHeight: 120
color: "transparent"
property bool expanded: false
Controller {
id: controller
connected: false
}
Process {
id: connectionProcess
command: ["sh", "-c", "dualsensectl monitor add 'echo connected' remove 'echo disconnected'"]
running: true
stdout: SplitParser {
onRead: line => {
if (line === "connected") {
controller.connected = true
} else {
controller.connected = false
}
}
}
}
Timer {
interval: 30000
running: true
repeat: true
onTriggered: batteryProcess.running = true
}
Timer {
interval: 1000
running: true
onTriggered: batteryProcess.running = true
}
Process {
id: batteryProcess
command: ["sh", "-c", "dualsensectl battery"]
running: true
stdout: StdioCollector {
onStreamFinished: () => {
const s = text.split(" ");
controller.percentage = s[0];
controller.chargingState = s[1];
if (s[1].indexOf("charging") === 0) {
controller.chargingState = "Charging"
}
if (s[1].indexOf("discharging") === 0) {
controller.chargingState = "Discharging"
}
if (s[1].indexOf("full") === 0) {
controller.chargingState = "Full"
}
}
}
}
Rectangle {
id: surface
anchors {
right: parent.right
top: parent.top
bottom: parent.bottom
}
width: root.expanded ? parent.width : 22
radius: 10
color: '#1e1e2e'
border.color: "#555c637a"
border.width: 1
clip: true
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: (evt) => {
root.expanded = !root.expanded
}
}
HoverHandler {
id: hoverHandler
onHoveredChanged: {
if (!hovered)
root.expanded = false
}
}
Rectangle {
id: edgeHandle
width: 5
height: 70
radius: 3
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: 8
}
color: '#828282'
Rectangle {
id: powerLevel
anchors {
bottom: parent.bottom
}
width: parent.width
height: controller.percentage * 0.01 * parent.height
radius: 3
color: controller.chargingState === "Charging"
? "#f5c542"
: controller.chargingState === "Full" ? '#68b864' : "#8ab4f8"
}
}
RowLayout {
visible: root.expanded
anchors {
left: parent.left
right: edgeHandle.left
verticalCenter: parent.verticalCenter
leftMargin: 16
rightMargin: 8
}
spacing: 10
Image {
id: image
source: "icons/dualsense.png"
Layout.preferredWidth: 100
Layout.preferredHeight: parent.height
fillMode: Image.PreserveAspectFit
}
ColumnLayout {
Label {
Layout.fillWidth: true
text: "Dualsense"
color: "white"
font.bold: true
font.pixelSize: 16
elide: Text.ElideRight
}
Label {
Layout.fillWidth: true
text: `Battery: ${Math.round(controller.percentage)} %`
color: "#d8dee9"
font.pixelSize: 14
}
Label {
Layout.fillWidth: true
text: `Status: ${controller.chargingState}`
color: root.chargingState === "charging"
? "#f5c542"
: "#d8dee9"
font.pixelSize: 14
}
}
Button {
contentItem: Image {
source: "icons/power.svg"
height: 48
fillMode: Image.PreserveAspectFit
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: 'transparent'
height: 48
border.width: 0
}
onClicked: {
disconnectProcess.running = true
}
}
Process {
id: disconnectProcess
command: ["sh", "-c", "dualsensectl power-off"]
}
}
}
}