pragma Singleton import QtQuick import Quickshell.Services.Notifications 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 percent: { const p = dev?.percentage; return (p !== undefined && p !== null && !isNaN(p)) ? p * 100 : 0; } 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 healthPercent: (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: percent < critThresh && !charging readonly property color stateColor: charging ? S.Theme.base0B : critical ? S.Theme.base09 : percent < warnThresh ? S.Theme.base0A : S.Theme.base05 // 24h history (1440 samples @ 60s) property var history: [] // Wattage history (60 samples @ 60s = 1h), signed: positive = charging property var rateHistory: [] property var _histTimer: Timer { interval: 60000 running: root.available repeat: true triggeredOnStart: true onTriggered: { const h = root.history.concat([root.percent]); root.history = h.length > 1440 ? h.slice(h.length - 1440) : h; const w = root.charging ? root.changeRate : -root.changeRate; const rh = root.rateHistory.concat([w]); root.rateHistory = rh.length > 60 ? rh.slice(rh.length - 60) : rh; } } // 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 onPercentChanged() { if (root.charging) return; if (root.percent < root.critThresh && !root._critSent) { root._critSent = true; root._warnSent = true; S.NotifService.send("Very Low Battery", "Connect to power now!", NotificationUrgency.Critical, "battery-low"); } else if (root.percent < root.warnThresh && !root._warnSent) { root._warnSent = true; S.NotifService.send("Low Battery", "", NotificationUrgency.Normal, "battery-caution"); } } } 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"; } }