quickshell: add battery dropdown with power draw and profiles
Click battery to see charge %, wattage draw, and switch between power-saver/balanced/performance profiles via power-profiles-daemon. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d474f87df5
commit
2b9edcb589
1 changed files with 169 additions and 7 deletions
|
|
@ -677,6 +677,8 @@ in
|
||||||
property int batteryLevel: 0
|
property int batteryLevel: 0
|
||||||
property bool charging: false
|
property bool charging: false
|
||||||
property string batteryIcon: "\u{f008e}"
|
property string batteryIcon: "\u{f008e}"
|
||||||
|
property real powerDraw: 0.0
|
||||||
|
property string powerProfile: "balanced"
|
||||||
|
|
||||||
function updateIcon() {
|
function updateIcon() {
|
||||||
if (charging) { batteryIcon = "\u{f0084}"; return; }
|
if (charging) { batteryIcon = "\u{f0084}"; return; }
|
||||||
|
|
@ -689,30 +691,52 @@ in
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 10000
|
interval: 5000
|
||||||
running: true
|
running: true
|
||||||
repeat: true
|
repeat: true
|
||||||
triggeredOnStart: true
|
triggeredOnStart: true
|
||||||
onTriggered: batteryProc.running = true
|
onTriggered: { batteryProc.running = true; profileProc.running = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: batteryProc
|
id: batteryProc
|
||||||
command: ["sh", "-c", "cat /sys/class/power_supply/BAT0/capacity; cat /sys/class/power_supply/BAT0/status"]
|
command: ["sh", "-c", "cat /sys/class/power_supply/BAT0/capacity; cat /sys/class/power_supply/BAT0/status; cat /sys/class/power_supply/BAT0/power_now 2>/dev/null || echo 0"]
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
|
property int lineNum: 0
|
||||||
onRead: data => {
|
onRead: data => {
|
||||||
let trimmed = data.trim();
|
let trimmed = data.trim();
|
||||||
|
lineNum++;
|
||||||
|
if (lineNum === 1) {
|
||||||
let num = parseInt(trimmed);
|
let num = parseInt(trimmed);
|
||||||
if (!isNaN(num) && num >= 0 && num <= 100) {
|
if (!isNaN(num)) batteryWidget.batteryLevel = num;
|
||||||
batteryWidget.batteryLevel = num;
|
} else if (lineNum === 2) {
|
||||||
} else if (trimmed.length > 0) {
|
|
||||||
batteryWidget.charging = (trimmed === "Charging");
|
batteryWidget.charging = (trimmed === "Charging");
|
||||||
|
} else if (lineNum === 3) {
|
||||||
|
let uw = parseInt(trimmed);
|
||||||
|
if (!isNaN(uw)) batteryWidget.powerDraw = uw / 1000000.0;
|
||||||
|
lineNum = 0;
|
||||||
}
|
}
|
||||||
batteryWidget.updateIcon();
|
batteryWidget.updateIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: profileProc
|
||||||
|
command: ["${pkgs.power-profiles-daemon}/bin/powerprofilesctl", "get"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: data => {
|
||||||
|
batteryWidget.powerProfile = data.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: setProfileProc
|
||||||
|
property string target: "balanced"
|
||||||
|
command: ["${pkgs.power-profiles-daemon}/bin/powerprofilesctl", "set", target]
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
@ -737,6 +761,22 @@ in
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
if (batteryDropdown.justDismissed) return;
|
||||||
|
if (batteryDropdown.visible) {
|
||||||
|
batteryDropdown.visible = false;
|
||||||
|
} else {
|
||||||
|
batteryProc.running = true;
|
||||||
|
profileProc.running = true;
|
||||||
|
let pos = batteryWidget.mapToItem(bar.contentItem, batteryWidget.width / 2, 0);
|
||||||
|
batteryDropdown.dropdownX = pos.x;
|
||||||
|
batteryDropdown.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
''}
|
''}
|
||||||
|
|
||||||
|
|
@ -1128,6 +1168,128 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
${lib.optionalString isMacbook ''
|
||||||
|
// Battery dropdown
|
||||||
|
BarDropdown {
|
||||||
|
id: batteryDropdown
|
||||||
|
fullWidth: batteryDropdownCol.width + 24
|
||||||
|
fullHeight: batteryDropdownCol.height + 16
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: batteryDropdownCol
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 10
|
||||||
|
width: 200
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
// Battery status
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: batteryWidget.batteryIcon
|
||||||
|
color: "#${c.base05}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 18
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
Text {
|
||||||
|
text: batteryWidget.batteryLevel + "%" + (batteryWidget.charging ? " — Charging" : "")
|
||||||
|
color: "#${c.base05}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 13
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: batteryWidget.powerDraw.toFixed(1) + " W"
|
||||||
|
color: "#${c.base04}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separator
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width - 10
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
height: 1
|
||||||
|
color: "#${c.base03}"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power profile label
|
||||||
|
Text {
|
||||||
|
text: "Power Profile"
|
||||||
|
color: "#${c.base03}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profile buttons
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: [
|
||||||
|
{ name: "power-saver", label: "\u{f0425}", tip: "Saver" },
|
||||||
|
{ name: "balanced", label: "\u{f0376}", tip: "Balanced" },
|
||||||
|
{ name: "performance", label: "\u{f0e0e}", tip: "Performance" }
|
||||||
|
]
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
width: (parent.width - 8) / 3
|
||||||
|
height: 36
|
||||||
|
radius: 6
|
||||||
|
color: batteryWidget.powerProfile === modelData.name
|
||||||
|
? "#${c.base02}" : profMouse.containsMouse
|
||||||
|
? "#${c.base01}" : "transparent"
|
||||||
|
border.width: batteryWidget.powerProfile === modelData.name ? 1 : 0
|
||||||
|
border.color: "#${c.base03}"
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 1
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: modelData.label
|
||||||
|
color: batteryWidget.powerProfile === modelData.name
|
||||||
|
? "#${c.base0D}" : "#${c.base05}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 14
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: modelData.tip
|
||||||
|
color: "#${c.base04}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: profMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
setProfileProc.target = modelData.name;
|
||||||
|
setProfileProc.running = true;
|
||||||
|
batteryWidget.powerProfile = modelData.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''}
|
||||||
|
|
||||||
// Calendar popup
|
// Calendar popup
|
||||||
BarDropdown {
|
BarDropdown {
|
||||||
id: calPopup
|
id: calPopup
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue