Better battery indicator and dedicated Battery singleton in helpers

This commit is contained in:
2026-06-01 15:04:48 +02:00
parent ebedf4b6fe
commit 7eba84c8be
5 changed files with 155 additions and 60 deletions
@@ -4,11 +4,11 @@ import QtQuick
import ZShell import ZShell
import qs.Config import qs.Config
import qs.Components.Toast import qs.Components.Toast
import qs.Helpers
Scope { Scope {
id: root id: root
readonly property real currentPerc: UPower.displayDevice.percentage
readonly property list<var> popupThresholds: [...Config.general.battery.popupThresholds].sort((a, b) => b.perc - a.perc) readonly property list<var> popupThresholds: [...Config.general.battery.popupThresholds].sort((a, b) => b.perc - a.perc)
function nearestThresholdAbove(p: real): var { function nearestThresholdAbove(p: real): var {
@@ -23,13 +23,13 @@ Scope {
Connections { Connections {
function onOnBatteryChanged(): void { function onOnBatteryChanged(): void {
if (!UPower.displayDevice.ready) if (!Battery.ready)
return; return;
if (UPower.onBattery) { if (Battery.onBattery) {
if (Config.utilities.toasts.chargingChanged) if (Config.utilities.toasts.chargingChanged)
Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is discharging"), "power_off"); Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is discharging"), "power_off");
const p = root.currentPerc * 100; const p = Battery.currentPerc * 100;
const perc = root.nearestThresholdAbove(p); const perc = root.nearestThresholdAbove(p);
if (perc) if (perc)
Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning); Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning);
@@ -39,15 +39,15 @@ Scope {
} }
} }
target: UPower target: Battery
} }
Connections { Connections {
function onPercentageChanged(): void { function onCurrentPercChanged(): void {
if (!UPower.onBattery) if (!Battery.onBattery)
return; return;
const p = root.currentPerc * 100; const p = Battery.currentPerc * 100;
for (const perc of root.popupThresholds) { for (const perc of root.popupThresholds) {
if (p == perc.perc) { if (p == perc.perc) {
Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery perc is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning); Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery perc is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning);
@@ -56,15 +56,15 @@ Scope {
} }
function onReadyChanged(): void { function onReadyChanged(): void {
if (!UPower.displayDevice.ready) if (!Battery.ready)
return; return;
const p = root.currentPerc * 100; const p = Battery.currentPerc * 100;
const perc = root.nearestThresholdAbove(p); const perc = root.nearestThresholdAbove(p);
if (perc) if (perc)
Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning); Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning);
} }
target: UPower.displayDevice target: Battery
} }
} }
+32
View File
@@ -0,0 +1,32 @@
pragma Singleton
import Quickshell
import Quickshell.Services.UPower
import qs.Config
Singleton {
id: root
readonly property var colors: {
if (deviceState === UPowerDeviceState.Charging || deviceState === UPowerDeviceState.FullyCharged)
return {
fg: DynamicColors.palette.m3primary,
bg: DynamicColors.palette.m3onPrimary
};
else if (currentPerc <= 0.2)
return {
fg: DynamicColors.palette.m3error,
bg: DynamicColors.palette.m3onError
};
else
return {
fg: DynamicColors.palette.m3onSurface,
bg: DynamicColors.palette.m3surface
};
}
readonly property real currentPerc: UPower.displayDevice.percentage
readonly property var deviceState: UPower.displayDevice.state
readonly property bool isLaptop: UPower.displayDevice.isLaptopBattery
readonly property bool onBattery: UPower.onBattery
readonly property bool ready: UPower.displayDevice.ready
}
-26
View File
@@ -1,26 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Services.UPower
Singleton {
id: root
readonly property real batteryPercent: UPower.displayDevice.percentage
readonly property list<UPowerDevice> devices: UPower.devices.values
readonly property UPowerDevice displayDevice: UPower.displayDevice
readonly property bool onBattery: UPower.onBattery
// property bool toastShown
//
// Connections {
// target: UPower
//
// function onPercentageChanged(): {
// if (root.batteryPercent >= 0.2 && toastShown)
// return;
//
// root.toastShown = true;
// Toaster.toast(qsTr("Battery "))
// }
// }
}
+111 -22
View File
@@ -3,33 +3,122 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Components import qs.Components
import qs.Config import qs.Config
import qs.Helpers as Helpers import qs.Helpers
RowLayout { Item {
id: root id: root
MaterialIcon { implicitHeight: Battery.isLaptop ? batteryIconLoader.item.implicitHeight : upowerIconLoader.item.implicitHeight
Layout.alignment: Qt.AlignVCenter implicitWidth: Battery.isLaptop ? batteryIconLoader.item.implicitWidth : upowerIconLoader.item.implicitWidth
animate: true
color: !Helpers.UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3error Loader {
fill: 1 id: batteryIconLoader
text: {
if (!Helpers.UPower.displayDevice.isLaptopBattery) { active: Battery.isLaptop
if (PowerProfiles.profile === PowerProfile.PowerSaver) anchors.centerIn: parent
return "nest_eco_leaf";
if (PowerProfiles.profile === PowerProfile.Performance) sourceComponent: Row {
return "bolt"; id: batteryIcon
return "power_settings_new";
property real batHeight: 16
property real batWidth: 30
property real nubHeight: 6
property real nubWidth: 2
property real radius: Appearance.rounding.smallest / 2
spacing: 1
Component.onCompleted: console.log(Battery.isLaptop)
CustomRect {
id: track
anchors.verticalCenter: parent.verticalCenter
color: Battery.colors.bg
height: batteryIcon.batHeight
radius: batteryIcon.radius
width: batteryIcon.batWidth
CustomText {
color: Battery.colors.fg
font.pointSize: Appearance.font.size.larger / 1.5
font.weight: 800
height: track.height
horizontalAlignment: Text.AlignHCenter
text: Math.round(Battery.currentPerc * 100)
verticalAlignment: Text.AlignVCenter
width: track.width
}
Item {
clip: true
width: parent.width * Battery.currentPerc
anchors {
bottom: parent.bottom
left: parent.left
top: parent.top
}
CustomRect {
id: fill
color: Battery.colors.fg
height: track.height
radius: track.radius
width: track.width
CustomText {
id: batteryLabel
clip: true
color: Battery.colors.bg
font.pointSize: 7.5
font.weight: 800
height: track.height
horizontalAlignment: Text.AlignHCenter
text: Math.round(Battery.currentPerc * 100)
verticalAlignment: Text.AlignVCenter
width: track.width
}
}
}
} }
const perc = Helpers.UPower.displayDevice.percentage; CustomRect {
const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(Helpers.UPower.displayDevice.state); id: nub
if (perc === 1)
return charging ? "battery_charging_full" : "battery_full"; anchors.verticalCenter: parent.verticalCenter
let level = Math.floor(perc * 7); bottomRightRadius: 20
if (charging && (level === 4 || level === 1)) color: Battery.currentPerc < 0.99 ? track.color : fill.color
level--; height: batteryIcon.nubHeight
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`; topRightRadius: 20
width: batteryIcon.nubWidth
}
}
}
Loader {
id: upowerIconLoader
active: !Battery.isLaptop
anchors.centerIn: parent
sourceComponent: RowLayout {
id: upowerIcon
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
animate: true
fill: 1
text: {
if (PowerProfiles.profile === PowerProfile.PowerSaver)
return "nest_eco_leaf";
if (PowerProfiles.profile === PowerProfile.Performance)
return "bolt";
return "power_settings_new";
}
}
} }
} }
} }
+1 -1
View File
@@ -48,7 +48,7 @@ ShellRoot {
LazyLoader { LazyLoader {
activeAsync: root.laptop activeAsync: root.laptop
component: Battery { component: BatteryService {
} }
} }
} }