diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index f9adc1269..9cc7f4c31 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -15,7 +15,7 @@ Singleton { id: root readonly property var log: Log.scoped("SettingsData") - readonly property int settingsConfigVersion: 11 + readonly property int settingsConfigVersion: 12 readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" @@ -752,7 +752,9 @@ Singleton { property bool batteryNotifyCritical: true property int batteryLowThreshold: 20 property bool batteryNotifyLow: false - property int batteryNotificationType: 0 + property int batteryChargeLimitNotificationType: 0 + property int batteryLowNotificationType: 0 + property int batteryCriticalNotificationType: 1 property bool batteryAutoPowerSaver: false property bool showBatteryPercent: true property bool showBatteryPercentOnlyOnBattery: false diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 907046f6f..eee161b54 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -339,7 +339,9 @@ var SPEC = { batteryNotifyCritical: { def: true }, batteryLowThreshold: { def: 20 }, batteryNotifyLow: { def: false }, - batteryNotificationType: { def: 0 }, + batteryChargeLimitNotificationType: { def: 0 }, + batteryLowNotificationType: { def: 0 }, + batteryCriticalNotificationType: { def: 1 }, batteryAutoPowerSaver: { def: false }, lockBeforeSuspend: { def: false }, loginctlLockIntegration: { def: true }, diff --git a/quickshell/Common/settings/SettingsStore.js b/quickshell/Common/settings/SettingsStore.js index 43c017a13..6af77c360 100644 --- a/quickshell/Common/settings/SettingsStore.js +++ b/quickshell/Common/settings/SettingsStore.js @@ -252,6 +252,17 @@ function migrateToVersion(obj, targetVersion) { settings.configVersion = 11; } + if (currentVersion < 12) { + console.info("Migrating settings from version", currentVersion, "to version 12"); + if (settings.batteryNotificationType !== undefined) { + settings.batteryChargeLimitNotificationType = settings.batteryNotificationType; + settings.batteryLowNotificationType = settings.batteryNotificationType; + settings.batteryCriticalNotificationType = settings.batteryNotificationType; + delete settings.batteryNotificationType; + } + settings.configVersion = 12; + } + return settings; } diff --git a/quickshell/Modules/Settings/BatteryTab.qml b/quickshell/Modules/Settings/BatteryTab.qml index 2d3c4226b..3517ab892 100644 --- a/quickshell/Modules/Settings/BatteryTab.qml +++ b/quickshell/Modules/Settings/BatteryTab.qml @@ -52,9 +52,12 @@ done settingKey: "batteryStatusCard" Column { - width: parent.width + width: parent.width - Theme.spacingM * 2 + x: Theme.spacingM spacing: Theme.spacingM + SettingsDivider {} + Row { width: parent.width StyledText { @@ -62,6 +65,7 @@ done font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceVariantText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } StyledText { text: BatteryService.isPluggedIn ? I18n.tr("AC Adapter (Plugged In)") : I18n.tr("Battery Power") @@ -69,15 +73,11 @@ done font.weight: Font.Medium color: Theme.surfaceText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } } - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.1 - } + SettingsDivider {} Row { width: parent.width @@ -86,6 +86,7 @@ done font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceVariantText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } StyledText { text: `${BatteryService.batteryLevel}%` @@ -93,15 +94,11 @@ done font.weight: Font.Medium color: Theme.surfaceText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } } - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.1 - } + SettingsDivider {} Row { width: parent.width @@ -110,6 +107,7 @@ done font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceVariantText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } StyledText { text: BatteryService.batteryStatus @@ -117,15 +115,11 @@ done font.weight: Font.Medium color: Theme.surfaceText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } } - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.1 - } + SettingsDivider {} Row { width: parent.width @@ -134,6 +128,7 @@ done font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceVariantText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } StyledText { text: BatteryService.formatTimeRemaining() @@ -141,15 +136,11 @@ done font.weight: Font.Medium color: Theme.surfaceText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } } - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.1 - } + SettingsDivider {} Row { width: parent.width @@ -158,6 +149,7 @@ done font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceVariantText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } StyledText { text: BatteryService.batteryHealth @@ -165,6 +157,7 @@ done font.weight: Font.Medium color: Theme.surfaceText width: parent.width / 2 + horizontalAlignment: Text.AlignLeft } } } @@ -174,7 +167,7 @@ done SettingsCard { width: parent.width iconName: "tune" - title: I18n.tr("Battery Protection & Charging") + title: I18n.tr("Battery Protection") settingKey: "batteryProtection" SettingsSliderRow { @@ -191,7 +184,12 @@ done Row { width: parent.width height: applyButton.height - layoutDirection: Qt.RightToLeft + layoutDirection: I18n.isRtl ? Qt.LeftToRight : Qt.RightToLeft + + Item { + width: Theme.spacingM + height: 1 + } DankButton { id: applyButton @@ -213,12 +211,27 @@ done onToggled: checked => SettingsData.set("batteryNotifyChargeLimit", checked) } - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 + SettingsButtonGroupRow { + settingKey: "batteryChargeLimitNotificationType" + text: I18n.tr("Notification Type") + description: I18n.tr("Choose how to be notified when charge limit is reached.") + model: [I18n.tr("Toast"), I18n.tr("Notification")] + visible: SettingsData.batteryNotifyChargeLimit + currentIndex: SettingsData.batteryChargeLimitNotificationType + onSelectionChanged: (index, selected) => { + if (selected) { + SettingsData.set("batteryChargeLimitNotificationType", index); + } + } } + } + + // 3. Battery Alerts Card + SettingsCard { + width: parent.width + iconName: "notifications" + title: I18n.tr("Battery Alerts") + settingKey: "batteryAlerts" SettingsSliderRow { settingKey: "batteryLowThreshold" @@ -240,39 +253,29 @@ done } SettingsButtonGroupRow { - settingKey: "batteryNotificationType" + settingKey: "batteryLowNotificationType" text: I18n.tr("Notification Type") - description: I18n.tr("Choose how to be notified about battery alerts.") + description: I18n.tr("Choose how to be notified about low battery alerts.") model: [I18n.tr("Toast"), I18n.tr("Notification")] - currentIndex: SettingsData.batteryNotificationType + visible: SettingsData.batteryNotifyLow + currentIndex: SettingsData.batteryLowNotificationType onSelectionChanged: (index, selected) => { if (selected) { - SettingsData.set("batteryNotificationType", index); + SettingsData.set("batteryLowNotificationType", index); } } } - SettingsToggleRow { - settingKey: "batteryAutoPowerSaver" - text: I18n.tr("Auto Power Saver") - description: I18n.tr("Automatically turn on Power Saver profile when battery is low.") - checked: SettingsData.batteryAutoPowerSaver - onToggled: checked => SettingsData.set("batteryAutoPowerSaver", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } + SettingsDivider {} StyledText { text: I18n.tr("Critical Battery Alert") font.pixelSize: Theme.fontSizeMedium font.weight: Font.DemiBold color: Theme.surfaceText - topPadding: Theme.spacingM + x: Theme.spacingM + width: parent.width - Theme.spacingM * 2 + topPadding: Theme.spacingS } SettingsSliderRow { @@ -293,14 +296,38 @@ done checked: SettingsData.batteryNotifyCritical onToggled: checked => SettingsData.set("batteryNotifyCritical", checked) } + + SettingsButtonGroupRow { + settingKey: "batteryCriticalNotificationType" + text: I18n.tr("Notification Type") + description: I18n.tr("Choose how to be notified about critical battery alerts.") + model: [I18n.tr("Toast"), I18n.tr("Notification")] + visible: SettingsData.batteryNotifyCritical + currentIndex: SettingsData.batteryCriticalNotificationType + onSelectionChanged: (index, selected) => { + if (selected) { + SettingsData.set("batteryCriticalNotificationType", index); + } + } + } } - // 3. Power Profiles Card + // 4. Power Profiles & Saving Card SettingsCard { width: parent.width iconName: "power" - title: I18n.tr("Power Profiles Auto-Switching") - settingKey: "powerProfilesAuto" + title: I18n.tr("Power Profiles & Saving") + settingKey: "powerProfilesSaving" + + SettingsToggleRow { + settingKey: "batteryAutoPowerSaver" + text: I18n.tr("Auto Power Saver") + description: I18n.tr("Automatically turn on Power Saver profile when battery is low.") + checked: SettingsData.batteryAutoPowerSaver + onToggled: checked => SettingsData.set("batteryAutoPowerSaver", checked) + } + + SettingsDivider {} SettingsDropdownRow { settingKey: "acProfileName" diff --git a/quickshell/Services/BatteryService.qml b/quickshell/Services/BatteryService.qml index a5bfb2ace..9475710bf 100644 --- a/quickshell/Services/BatteryService.qml +++ b/quickshell/Services/BatteryService.qml @@ -121,8 +121,8 @@ Singleton { Component.onCompleted: _syncLastIsCharging() - function sendAlert(title, message, isWarning, category) { - if (SettingsData.batteryNotificationType === 1) { + function sendAlert(title, message, isWarning, category, notificationType) { + if (notificationType === 1) { Quickshell.execDetached(["notify-send", "-u", isWarning ? "critical" : "normal", "-a", "DMS", "-i", isWarning ? "battery-caution" : "battery-charging", title, message]); } else { if (isWarning) { @@ -137,7 +137,7 @@ Singleton { if (isCharging && batteryLevel >= SettingsData.batteryChargeLimit) { if (!_hasNotifiedChargeLimit && SettingsData.batteryNotifyChargeLimit) { _hasNotifiedChargeLimit = true; - sendAlert(I18n.tr("Charge Limit Reached"), I18n.tr("Battery has charged to your set limit of %1%").arg(SettingsData.batteryChargeLimit), false, "battery-charge-limit"); + sendAlert(I18n.tr("Charge Limit Reached"), I18n.tr("Battery has charged to your set limit of %1%").arg(SettingsData.batteryChargeLimit), false, "battery-charge-limit", SettingsData.batteryChargeLimitNotificationType); } } else if (!isCharging || batteryLevel < SettingsData.batteryChargeLimit - 2) { _hasNotifiedChargeLimit = false; @@ -153,7 +153,7 @@ Singleton { 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"); + sendAlert(I18n.tr("Critical Battery"), I18n.tr("Battery is at %1% - Connect charger immediately!").arg(batteryLevel), true, "battery-critical", SettingsData.batteryCriticalNotificationType); } return; } @@ -166,7 +166,7 @@ Singleton { if (isLowBattery) { if (!_hasNotifiedLowBattery && SettingsData.batteryNotifyLow) { _hasNotifiedLowBattery = true; - sendAlert(I18n.tr("Low Battery"), I18n.tr("Battery is at %1% - Consider charging soon").arg(batteryLevel), true, "battery-low"); + sendAlert(I18n.tr("Low Battery"), I18n.tr("Battery is at %1% - Consider charging soon").arg(batteryLevel), true, "battery-low", SettingsData.batteryLowNotificationType); } if (SettingsData.batteryAutoPowerSaver && PowerProfileWatcher.available) {