brightess and volume control

This commit is contained in:
2026-03-26 13:15:54 -07:00
parent 80efc104ed
commit 5b8d82a934
20 changed files with 588 additions and 37 deletions

View File

@@ -10,14 +10,13 @@ Column {
width: Math.max(childrenRect.width, 300)
height: childrenRect.height
anchors.topMargin: 6
TapHandler {onTapped: console.log(width)}
Rectangle {
radius: 12
height: 40
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 6
color: "#181818"
color: "#111"
Rectangle {
color: "white"
width: (parent.width - anchors.margins * 2)/3
@@ -116,7 +115,7 @@ Column {
id: card
required property var data
required property var label
color: "#181818"
color: "#111"
height: 60
width: 100
radius: 12

154
Panes/Brightness.qml Normal file
View File

@@ -0,0 +1,154 @@
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import QtQuick
import qs.Services
import qs.Widgets as Widgets
Column {
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
margins: 6
}
width: 300
height: childrenRect.height + anchors.margins * 2
spacing: 6
Item {
anchors {
left: parent.left
right: parent.right
margins: 12
}
width: childrenRect.width
height: children[1].height
Image {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
verticalCenterOffset: 1
}
width: 24
height: width
sourceSize {width: width; height: height}
source: Quickshell.iconPath("brightnesssettings")
}
Text {
anchors {
top: parent.top
left: parent.children[0].right
leftMargin: 6
}
font.pixelSize: 16
color: "white"
text: "Laptop display"
}
}
Widgets.Slider {
anchors {
left: parent.left
right: parent.right
margins: 12
}
height: 24
value: Brightness.monitors[0].value / Brightness.monitors[0].max
onMoved: {
Brightness.monitors[0].set(Math.round(Brightness.monitors[0].max * position))
}
}
component ToggleButton: Item {
id: toggleButton
anchors {
left: parent.left
right: parent.right
margins: 12
}
height: children[0].height
property bool active: false
property var text
Text {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
height: 24
font.pixelSize: 14
color: "white"
text: toggleButton.text
}
Rectangle {
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: (24 - width)/2 + (36-24)/2
}
radius: height/2
color: parent.active ? "white" : "#00ffffff"
height: 10
width: parent.active ? 36 : 24
border.width: parent.active ? height/2 : 2
border.color: "white"
Behavior on width {NumberAnimation { duration: 150; easing.type: Easing.OutCubic }}
Behavior on border.width {NumberAnimation { duration: 150; easing.type: Easing.OutCubic }}
}
}
ToggleButton {
id: sunsetToggle
text: "Night Light"
Process {
running: true
command: [ "pgrep", "-x", "sunset" ]
onExited: (exitCode) => {if (!exitCode) sunsetToggle.active = true}
}
TapHandler {
property var idleProc: Process {command: ["hyprsunset"]}
property var idleKill: Process {command: ["pkill", "-x", "hyprsunset"]}
onTapped: {
parent.active = !parent.active
if (parent.active)
idleProc.startDetached()
else
idleKill.startDetached()
}
}
}
ToggleButton {
id: idleToggle
text: "Idle Timer"
Process {
running: true
command: [ "pgrep", "-x", "hypridle" ]
onExited: (exitCode) => {if (!exitCode) idleToggle.active = true}
}
TapHandler {
property var idleProc: Process {command: ["hypridle"]}
property var idleKill: Process {command: ["pkill", "-x", "hypridle"]}
onTapped: {
parent.active = !parent.active
if (parent.active)
idleProc.startDetached()
else
idleKill.startDetached()
}
}
}
ToggleButton {
id: dpmsToggle
text: "Screen on"
active: true
TapHandler {
property var resetTimer: Timer {
interval: 500
running: false
repeat: false
onTriggered: dpmsToggle.active = true
}
onTapped: {
dpmsToggle.active = false;
Hyprland.dispatch("dpms off");
resetTimer.start();
root.close();
}
}
}
}

View File

@@ -38,7 +38,7 @@ Item {
margins: 6
}
height: 48
color: "#181818"
color: "#111"
radius: 10
TextInput {
id: input
@@ -95,7 +95,6 @@ Item {
property: "x"
duration: 300
easing.type: Easing.OutQuint
onStarted: console.log("displaced")
}
NumberAnimation {
property: "opacity"
@@ -146,7 +145,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
width: 64
height: width
source: Quickshell.iconPath(modelData.icon)
source: Quickshell.iconPath(modelData.icon, "application-default")
}
Text {
anchors.horizontalCenter: parent.horizontalCenter

View File

@@ -20,7 +20,7 @@ Item {
Rectangle {
width: 400
height: 300
color: "#181818"
color: "#111"
radius: 10
Column {
anchors.centerIn: parent
@@ -47,7 +47,6 @@ Item {
anchors.rightMargin: anchors.leftMargin
clip: true
spacing: 4
interactive: background.index === 3
add: Transition {NumberAnimation {
property: "opacity"
@@ -69,7 +68,7 @@ Item {
header: Item {height: 4; width: 1}
model: Array.from(notifServer.trackedNotifications.values)
delegate: Widgets.Notification {
color: "#222"
color: "#181818"
}
}
}
@@ -98,25 +97,32 @@ Item {
}
}
Column {
anchors.centerIn: parent
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
margins: 6
}
opacity: Mpris.players.values.length
Behavior on opacity {NumberAnimation {duration: 150}}
Shape {
id: progressShape
anchors.horizontalCenter: parent.horizontalCenter
width: 180
height: 180
width: 160
height: width
property var strokeWidth: 6
preferredRendererType: Shape.CurveRenderer
ShapePath {
capStyle: ShapePath.RoundCap
strokeColor: "#444"
fillColor: "transparent"
strokeWidth: 4
strokeWidth: progressShape.strokeWidth
PathAngleArc {
moveToStart: true
radiusX: 90 - 6
radiusY: 90 - 6
centerX: 90
centerY: 90
radiusX: (progressShape.width-progressShape.strokeWidth)/2
radiusY: (progressShape.height-progressShape.strokeWidth)/2
centerX: progressShape.width/2
centerY: progressShape.height/2
startAngle: 90 + 20
sweepAngle: 360 - 40
}
@@ -125,13 +131,13 @@ Item {
capStyle: ShapePath.RoundCap
strokeColor: "white"
fillColor: "transparent"
strokeWidth: 4
strokeWidth: 6
PathAngleArc {
moveToStart: true
radiusX: 90 - 6
radiusY: 90 - 6
centerX: 90
centerY: 90
radiusX: (progressShape.width-progressShape.strokeWidth)/2
radiusY: (progressShape.height-progressShape.strokeWidth)/2
centerX: progressShape.width/2
centerY: progressShape.height/2
startAngle: 90 + 20
sweepAngle: (player.modelData?.position/player.modelData.length) * (360 - 40)
}
@@ -140,9 +146,12 @@ Item {
color: "transparent"
radius: height/2
anchors.fill: parent
anchors.margins: 12
anchors.margins: progressShape.strokeWidth*2
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
mipmap: true
smooth: true
source: player.modelData?.trackArtUrl ?? source
}
NumberAnimation on rotation {
@@ -159,15 +168,25 @@ Item {
}
Item {width: 1; height: 10}
Text {
anchors {
left: parent.left
right: parent.right
}
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
color: "white"
text: player.modelData?.trackTitle ?? ""
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 16
}
Text {
anchors {
left: parent.left
right: parent.right
}
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
color: "white"
text: player.modelData?.trackArtist ?? ""
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 12
}
Item {width: 1; height: 8}

View File

@@ -9,7 +9,7 @@ Item {
horizontalCenter: parent.horizontalCenter
}
width: 350
height: childrenRect.height
height: childrenRect.height + 12
Connections {
target: notifServer
function onNotification(notif) {
@@ -22,6 +22,7 @@ Item {
}
Widgets.Notification {
id: notifPopup
y: 6
anchors.margins: 6
modelData: notifServer.trackedNotifications.values[0] ?? undefined
color: "transparent"
@@ -32,4 +33,8 @@ Item {
interval: 3000
onTriggered: root.close()
}
Connections {
target: background
function onIndexChanged() { timeout.stop() }
}
}

View File

@@ -16,6 +16,8 @@ Item {
bottom: parent.bottom
}
Widgets.Battery {}
Widgets.Volume {}
Widgets.Brightness {}
}
Widgets.Workspaces {
height: parent.height
@@ -31,6 +33,7 @@ Item {
right: parent.right
bottom: parent.bottom
}
Widgets.Uptime {}
Widgets.Time {}
}
}

104
Panes/Volume.qml Normal file
View File

@@ -0,0 +1,104 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Controls
import Quickshell
import Quickshell.Widgets
import Quickshell.Services.Pipewire
import qs.Widgets as Widgets
Row {
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
}
padding: 6
height: 316
spacing: 6
PwObjectTracker {
objects: Pipewire.nodes.values.filter(node => [17, 21].includes(node.type))
}
component NodeList: ClippingRectangle {
id: nodeListRect
width: 350
color: "transparent"
anchors {
top: parent.top
bottom: parent.bottom
bottomMargin: 6
}
radius: 10
property var model
clip: true
ListView {
anchors.fill: parent
spacing: 6
header: Item {width: 1; height: 6}
footer: header
model: nodeListRect.model
delegate: Rectangle {
anchors {
left: parent.left
right: parent.right
}
radius: 12
color: "#111"
height: children[1].height
Image {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 6
}
sourceSize {width: width; height: height}
source: Quickshell.iconPath((() => {
const description = modelData.description.toLowerCase();
if (description.search("hdmi") !== -1)
return "display"
if (description.search("speaker") !== -1)
return "audio-speakers"
if (description.search("earphone") !== -1 || description.search("headphone") !== -1)
return "audio-headset"
if (modelData.properties["device.icon-name"])
return modelData.properties["device.icon-name"]
return modelData.properties["application.name"]
})()?.toLowerCase(), "audio-on")
width: 32
height: width
}
Column {
anchors {
left: parent.children[0].right
right: parent.right
verticalCenter: parent.verticalCenter
margins: 6
rightMargin: 12
}
topPadding: 6
bottomPadding: 6
spacing: 2
Text {
text: {
if (modelData.nickname !== "") return modelData.nickname
if (modelData.description !== "") return description
return modelData.name
}
color: "white"
font.pixelSize: 16
}
Widgets.Slider {
value: modelData.audio.volume
onMoved: modelData.audio.volume = position
}
}
}
}
}
NodeList {
model: Pipewire.nodes.values.filter(node => node.type === 17)
}
NodeList {
model: Pipewire.nodes.values.filter(node => node.type === 21)
}
}