From fde8bb64871f5cfd0175145eca5cc5ee66c887c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=E1=BB=B3nh=20Thi=E1=BB=87n=20L=E1=BB=99c?= Date: Thu, 20 Aug 2026 07:44:58 +0700 Subject: [PATCH] feat(battery): show estimated end time (#3117) --- .../Modules/DankBar/Popouts/BatteryPopout.qml | 4 ++- quickshell/Services/BatteryService.qml | 34 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml b/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml index a81507107..68a87a74f 100644 --- a/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml +++ b/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml @@ -175,7 +175,9 @@ DankPopout { return I18n.tr("Power profile management available"); const time = BatteryService.formatTimeRemaining(); if (time !== "Unknown") { - return BatteryService.isCharging ? I18n.tr("Time until full: %1").arg(time) : I18n.tr("Time remaining: %1").arg(time); + const estimated = BatteryService.formatEstimatedTime(); + const timeText = estimated ? `${time} (${estimated})` : time; + return BatteryService.isCharging ? I18n.tr("Time until full: %1").arg(timeText) : I18n.tr("Time remaining: %1").arg(timeText); } return ""; } diff --git a/quickshell/Services/BatteryService.qml b/quickshell/Services/BatteryService.qml index 1f0d98030..6663f1fd6 100644 --- a/quickshell/Services/BatteryService.qml +++ b/quickshell/Services/BatteryService.qml @@ -405,23 +405,39 @@ Singleton { return btDevices; } - // Format time remaining for charge/discharge - function formatTimeRemaining() { - if (!batteryAvailable) { - return "Unknown"; - } + function estimatedSeconds() { + if (!batteryAvailable) + return 0; const rate = _smoothedChangeRate > 0 ? _smoothedChangeRate : changeRate; const totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / rate) : (batteryEnergy / rate); - const avgTime = Math.abs(totalTime * 3600); - if (!avgTime || avgTime <= 0 || avgTime > 86400) + const seconds = Math.abs(totalTime * 3600); + if (!seconds || seconds <= 0 || seconds > 86400) + return 0; + return seconds; + } + + // Format time remaining for charge/discharge + function formatTimeRemaining() { + const seconds = estimatedSeconds(); + if (!seconds) return "Unknown"; - const hours = Math.floor(avgTime / 3600); - const minutes = Math.floor((avgTime % 3600) / 60); + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; } + function formatEstimatedTime() { + const seconds = estimatedSeconds(); + if (!seconds) + return ""; + + const target = new Date(Date.now() + seconds * 1000); + const use24Hour = SettingsData.use24HourClock !== false; + return target.toLocaleTimeString(Qt.locale(), use24Hour ? "HH:mm" : "h:mm AP"); + } + function getBatteryIcon() { if (!batteryAvailable) { return "power";