From 085ce01da6fef464049ecd84e3da006db27f7e51 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, 18 Jun 2026 09:14:57 +0700 Subject: [PATCH] feat: port critical battery alert from DankBatteryAlerts plugin (#2664) * feat: port critical battery alert from DankBatteryAlerts plugin * ui: shorten notification type labels * refactor: remove duplicate battery charge limit from Power & Sleep --- quickshell/Common/SettingsData.qml | 2 ++ quickshell/Common/settings/SettingsSpec.js | 2 ++ quickshell/Modules/Settings/BatteryTab.qml | 36 ++++++++++++++++++- quickshell/Modules/Settings/PowerSleepTab.qml | 20 ----------- quickshell/Services/BatteryService.qml | 28 +++++++++++++-- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index ea4cd638..ca9774d1 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -599,6 +599,8 @@ Singleton { property int batteryPostLockMonitorTimeout: 0 property int batteryChargeLimit: 100 property bool batteryNotifyChargeLimit: false + property int batteryCriticalThreshold: 10 + property bool batteryNotifyCritical: true property int batteryLowThreshold: 20 property bool batteryNotifyLow: false property int batteryNotificationType: 0 diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 0f23f6cd..0636687a 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -306,6 +306,8 @@ var SPEC = { batteryPostLockMonitorTimeout: { def: 0 }, batteryChargeLimit: { def: 100 }, batteryNotifyChargeLimit: { def: false }, + batteryCriticalThreshold: { def: 10 }, + batteryNotifyCritical: { def: true }, batteryLowThreshold: { def: 20 }, batteryNotifyLow: { def: false }, batteryNotificationType: { def: 0 }, diff --git a/quickshell/Modules/Settings/BatteryTab.qml b/quickshell/Modules/Settings/BatteryTab.qml index fc8367ec..ac936c9c 100644 --- a/quickshell/Modules/Settings/BatteryTab.qml +++ b/quickshell/Modules/Settings/BatteryTab.qml @@ -244,7 +244,7 @@ done settingKey: "batteryNotificationType" text: I18n.tr("Notification Type") description: I18n.tr("Choose how to be notified about battery alerts.") - model: [I18n.tr("Toast Overlay"), I18n.tr("System Notification")] + model: [I18n.tr("Toast"), I18n.tr("Notification")] currentIndex: SettingsData.batteryNotificationType onSelectionChanged: (index, selected) => { if (selected) { @@ -260,6 +260,40 @@ done checked: SettingsData.batteryAutoPowerSaver onToggled: checked => SettingsData.set("batteryAutoPowerSaver", checked) } + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.15 + } + + StyledText { + text: I18n.tr("Critical Battery Alert") + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.DemiBold + color: Theme.surfaceText + topPadding: Theme.spacingM + } + + SettingsSliderRow { + settingKey: "batteryCriticalThreshold" + text: I18n.tr("Critical Threshold") + description: I18n.tr("Battery percentage to trigger a critical alert.") + value: SettingsData.batteryCriticalThreshold + minimum: 1 + maximum: 30 + defaultValue: 10 + onSliderValueChanged: newValue => SettingsData.set("batteryCriticalThreshold", newValue) + } + + SettingsToggleRow { + settingKey: "batteryNotifyCritical" + text: I18n.tr("Critical Battery Notifications") + description: I18n.tr("Show an urgent alert when battery reaches critical level.") + checked: SettingsData.batteryNotifyCritical + onToggled: checked => SettingsData.set("batteryNotifyCritical", checked) + } } // 3. Power Profiles Card diff --git a/quickshell/Modules/Settings/PowerSleepTab.qml b/quickshell/Modules/Settings/PowerSleepTab.qml index ef860c63..3fe33938 100644 --- a/quickshell/Modules/Settings/PowerSleepTab.qml +++ b/quickshell/Modules/Settings/PowerSleepTab.qml @@ -603,26 +603,6 @@ Item { } } - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Advanced") - settingKey: "powerAdvanced" - collapsible: true - expanded: false - - SettingsSliderRow { - settingKey: "batteryChargeLimit" - tags: ["battery", "charge", "limit", "percentage", "power"] - text: I18n.tr("Battery Charge Limit") - description: I18n.tr("Note: this only changes the percentage, it does not actually limit charging.") - value: SettingsData.batteryChargeLimit - minimum: 50 - maximum: 100 - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("batteryChargeLimit", newValue) - } - } } } } diff --git a/quickshell/Services/BatteryService.qml b/quickshell/Services/BatteryService.qml index 173e70ec..37816a33 100644 --- a/quickshell/Services/BatteryService.qml +++ b/quickshell/Services/BatteryService.qml @@ -103,8 +103,10 @@ Singleton { // Is the system plugged in (Is not running on battery) readonly property bool isPluggedIn: !UPower.onBattery readonly property bool isLowBattery: batteryAvailable && batteryLevel <= SettingsData.batteryLowThreshold + readonly property bool isCriticalBattery: batteryAvailable && batteryLevel <= SettingsData.batteryCriticalThreshold property bool _hasNotifiedLowBattery: false + property bool _hasNotifiedCriticalBattery: false property bool _hasNotifiedChargeLimit: false function sendAlert(title, message, isWarning, category) { @@ -129,15 +131,30 @@ Singleton { _hasNotifiedChargeLimit = false; } - if (isCharging || !isLowBattery) { + if (isCharging) { _hasNotifiedLowBattery = false; + _hasNotifiedCriticalBattery = false; return; } - if (!isCharging && isLowBattery) { + // Critical battery check (higher priority) + if (isCriticalBattery) { + if (!_hasNotifiedCriticalBattery && SettingsData.batteryNotifyCritical) { + _hasNotifiedCriticalBattery = true; + sendAlert(I18n.tr("Critical Battery"), I18n.tr("Battery is at %1% - Connect charger immediately!").arg(batteryLevel), true, "battery-critical"); + } + return; + } + + if (batteryLevel > SettingsData.batteryCriticalThreshold) { + _hasNotifiedCriticalBattery = false; + } + + // Low battery check + if (isLowBattery) { if (!_hasNotifiedLowBattery && SettingsData.batteryNotifyLow) { _hasNotifiedLowBattery = true; - sendAlert(I18n.tr("Low Battery"), I18n.tr("Battery is at %1%").arg(batteryLevel), true, "battery-low"); + sendAlert(I18n.tr("Low Battery"), I18n.tr("Battery is at %1% - Consider charging soon").arg(batteryLevel), true, "battery-low"); } if (SettingsData.batteryAutoPowerSaver && PowerProfileWatcher.available) { @@ -146,11 +163,16 @@ Singleton { } } } + + if (batteryLevel > SettingsData.batteryLowThreshold) { + _hasNotifiedLowBattery = false; + } } onIsChargingChanged: { if (isCharging) { _hasNotifiedLowBattery = false; + _hasNotifiedCriticalBattery = false; } else { _hasNotifiedChargeLimit = false; }