pragma Singleton import QtQuick import Quickshell import Quickshell.Io import Quickshell.Services.UPower import "." as S QtObject { id: root readonly property var dev: UPower.displayDevice readonly property bool available: dev?.isLaptopBattery ?? false readonly property real pct: (dev?.percentage ?? 0) * 100 readonly property bool charging: dev?.state === UPowerDeviceState.Charging readonly property real changeRate: dev?.changeRate ?? 0 readonly property int timeToFull: dev?.timeToFull ?? 0 readonly property int timeToEmpty: dev?.timeToEmpty ?? 0 readonly property bool healthSupported: dev?.healthSupported ?? false readonly property real healthPct: (dev?.healthPercentage ?? 1) * 100 readonly property int critThresh: S.Modules.battery.critical || 15 readonly property int warnThresh: S.Modules.battery.warning || 25 readonly property bool critical: pct < critThresh && !charging readonly property color stateColor: charging ? S.Theme.base0B : critical ? S.Theme.base09 : pct < warnThresh ? S.Theme.base0A : S.Theme.base05 // 24h history (1440 samples @ 60s) property var history: [] property var _histTimer: Timer { interval: 60000 running: root.available repeat: true triggeredOnStart: true onTriggered: { const h = root.history.concat([root.pct]); root.history = h.length > 1440 ? h.slice(h.length - 1440) : h; } } // Low battery notifications property bool _warnSent: false property bool _critSent: false property var _chargingWatcher: Connections { target: root function onChargingChanged() { root._warnSent = false; root._critSent = false; } function onPctChanged() { if (root.charging) return; if (root.pct < root.critThresh && !root._critSent) { root._critSent = true; root._warnSent = true; _notifProc.command = ["notify-send", "--urgency=critical", "--icon=battery-low", "--category=device", "Very Low Battery", "Connect to power now!"]; _notifProc.running = true; } else if (root.pct < root.warnThresh && !root._warnSent) { root._warnSent = true; _notifProc.command = ["notify-send", "--icon=battery-caution", "--category=device", "Low Battery"]; _notifProc.running = true; } } } property var _notifProc: Process {} function fmtTime(secs) { if (!secs || secs <= 0) return ""; const h = Math.floor(secs / 3600); const m = Math.floor((secs % 3600) / 60); return h > 0 ? h + "h " + m + "m" : m + "m"; } }