From 3ffd9cdfc5b0b7f399bc170b0f1f89d2662a4e05 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 1 Aug 2026 12:51:09 -0700 Subject: [PATCH] Add battery percentage toggle to power widget --- shell/plugins/bar/README.md | 2 +- shell/plugins/panels/power/Panel.qml | 17 +++++++++++++++-- test/shell.d/power-test.sh | 6 ++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/shell/plugins/bar/README.md b/shell/plugins/bar/README.md index eec4845f..2cf61e1f 100644 --- a/shell/plugins/bar/README.md +++ b/shell/plugins/bar/README.md @@ -68,7 +68,7 @@ Example `shell.json` (bar subtree only shown): | `omarchy.network` | Wi-Fi/Ethernet icon + popup with Wi-Fi scan, signal, connect, DNS provider selection | left = popup · right = nmtui | | `omarchy.tailscale` | Tailscale status, connection switcher, machine browser, and copy actions | left = popup · right = toggle · middle = refresh | | `omarchy.model-usage` | Claude Code and Codex limits with pace, today, last week, and all-time model breakdown | left = panel · right = refresh · middle = next subscription | -| `omarchy.power` | Battery/AC icon + popup with battery stats, power profiles, and system info | left = popup | +| `omarchy.power` | Battery/AC icon + popup with battery stats, power profiles, and system info | left = popup · right = toggle percentage | | `omarchy.bluetooth` | Bluetooth icon + popup with device list, connect/disconnect, battery | left = popup · right = toggle radio · middle = bluetoothctl TUI | | `omarchy.monitor` | Brightness and laptop display controls | left = popup | diff --git a/shell/plugins/panels/power/Panel.qml b/shell/plugins/panels/power/Panel.qml index 0caf7786..6c2fe91a 100644 --- a/shell/plugins/panels/power/Panel.qml +++ b/shell/plugins/panels/power/Panel.qml @@ -16,6 +16,7 @@ Panel { property string activeProfile: "" property int profileIndex: 0 property bool cursorActive: false + readonly property bool showPercentage: setting("showPercentage", false) === true readonly property bool batteryPresent: { var device = UPower.displayDevice return !!(device && device.isPresent) @@ -161,6 +162,11 @@ Panel { actionProc.running = true } + function togglePercentage() { + root.settings = Object.assign({}, root.settings, { showPercentage: !root.showPercentage }) + if (root.bar && root.bar.shell) root.bar.shell.updateEntryInline(root.moduleName, root.settings) + } + onOpenedChanged: { if (opened) { if (!batteryPresent) { @@ -253,9 +259,16 @@ Panel { id: button anchors.fill: parent bar: root.bar - text: root.batteryIcon() + text: root.showPercentage && !vertical + ? Math.round(root.batteryFraction * 100) + "% " + root.batteryIcon() + : root.batteryIcon() + slotSize: Style.bar.iconSlot * (root.showPercentage && !vertical ? 2 : 1) tooltipText: "" - onPressed: function(b) { if (root.batteryPresent) root.toggle() } + onPressed: function(b) { + if (!root.batteryPresent) return + if (b === Qt.RightButton) root.togglePercentage() + else root.toggle() + } } KeyboardPanel { diff --git a/test/shell.d/power-test.sh b/test/shell.d/power-test.sh index 281792cc..c51cd46a 100644 --- a/test/shell.d/power-test.sh +++ b/test/shell.d/power-test.sh @@ -5,7 +5,9 @@ set -euo pipefail source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" run_node_test <<'JS' +const fs = require('fs') const power = requireFromRoot('shell/plugins/panels/power/Model.js') +const panelSource = fs.readFileSync(root + '/shell/plugins/panels/power/Panel.qml', 'utf8') const states = { Charging: 1, Discharging: 2, FullyCharged: 3, PendingCharge: 4 } assertEqual(power.selectProfileIndex(0, 1, ['balanced', 'performance']), 1, 'power advances profile selection') @@ -39,4 +41,8 @@ assertEqual( power.batteryIcon({ isPresent: true, percentage: 0.4, state: states.Discharging }, true, states), 'power shows battery icon when unplugged before battery state refreshes' ) + +assert(/if \(b === Qt\.RightButton\) root\.togglePercentage\(\)/.test(panelSource), 'power right click toggles the bar percentage') +assert(/Object\.assign\([^\n]+showPercentage: !root\.showPercentage[^\n]+\)[\s\S]*updateEntryInline/.test(panelSource), 'power persists the bar percentage setting') +assert(/Math\.round\(root\.batteryFraction \* 100\) \+ "% " \+ root\.batteryIcon\(\)/.test(panelSource), 'power places the percentage before the battery icon') JS