diff --git a/Daemons/Battery.qml b/Daemons/BatteryService.qml similarity index 80% rename from Daemons/Battery.qml rename to Daemons/BatteryService.qml index 446fc58..00ccd98 100644 --- a/Daemons/Battery.qml +++ b/Daemons/BatteryService.qml @@ -4,11 +4,11 @@ import QtQuick import ZShell import qs.Config import qs.Components.Toast +import qs.Helpers Scope { id: root - readonly property real currentPerc: UPower.displayDevice.percentage readonly property list popupThresholds: [...Config.general.battery.popupThresholds].sort((a, b) => b.perc - a.perc) function nearestThresholdAbove(p: real): var { @@ -23,13 +23,13 @@ Scope { Connections { function onOnBatteryChanged(): void { - if (!UPower.displayDevice.ready) + if (!Battery.ready) return; - if (UPower.onBattery) { + if (Battery.onBattery) { if (Config.utilities.toasts.chargingChanged) 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); 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); @@ -39,15 +39,15 @@ Scope { } } - target: UPower + target: Battery } Connections { - function onPercentageChanged(): void { - if (!UPower.onBattery) + function onCurrentPercChanged(): void { + if (!Battery.onBattery) return; - const p = root.currentPerc * 100; + const p = Battery.currentPerc * 100; for (const perc of root.popupThresholds) { 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); @@ -56,15 +56,15 @@ Scope { } function onReadyChanged(): void { - if (!UPower.displayDevice.ready) + if (!Battery.ready) return; - const p = root.currentPerc * 100; + const p = Battery.currentPerc * 100; const perc = root.nearestThresholdAbove(p); 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); } - target: UPower.displayDevice + target: Battery } } diff --git a/Helpers/Battery.qml b/Helpers/Battery.qml new file mode 100644 index 0000000..3acf45c --- /dev/null +++ b/Helpers/Battery.qml @@ -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 +} diff --git a/Helpers/UPower.qml b/Helpers/UPower.qml deleted file mode 100644 index cef9b1a..0000000 --- a/Helpers/UPower.qml +++ /dev/null @@ -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 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 ")) - // } - // } -} diff --git a/Modules/SysTray/Widgets/UPowerWidget.qml b/Modules/SysTray/Widgets/UPowerWidget.qml index e7810e5..2e52af4 100644 --- a/Modules/SysTray/Widgets/UPowerWidget.qml +++ b/Modules/SysTray/Widgets/UPowerWidget.qml @@ -3,33 +3,122 @@ import QtQuick import QtQuick.Layouts import qs.Components import qs.Config -import qs.Helpers as Helpers +import qs.Helpers -RowLayout { +Item { id: root - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - animate: true - color: !Helpers.UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3error - fill: 1 - text: { - if (!Helpers.UPower.displayDevice.isLaptopBattery) { - if (PowerProfiles.profile === PowerProfile.PowerSaver) - return "nest_eco_leaf"; - if (PowerProfiles.profile === PowerProfile.Performance) - return "bolt"; - return "power_settings_new"; + implicitHeight: Battery.isLaptop ? batteryIconLoader.item.implicitHeight : upowerIconLoader.item.implicitHeight + implicitWidth: Battery.isLaptop ? batteryIconLoader.item.implicitWidth : upowerIconLoader.item.implicitWidth + + Loader { + id: batteryIconLoader + + active: Battery.isLaptop + anchors.centerIn: parent + + sourceComponent: Row { + id: batteryIcon + + 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; - const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(Helpers.UPower.displayDevice.state); - if (perc === 1) - return charging ? "battery_charging_full" : "battery_full"; - let level = Math.floor(perc * 7); - if (charging && (level === 4 || level === 1)) - level--; - return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`; + CustomRect { + id: nub + + anchors.verticalCenter: parent.verticalCenter + bottomRightRadius: 20 + color: Battery.currentPerc < 0.99 ? track.color : fill.color + height: batteryIcon.nubHeight + 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"; + } + } } } } diff --git a/shell.qml b/shell.qml index 5e756cb..c5c5b7f 100644 --- a/shell.qml +++ b/shell.qml @@ -48,7 +48,7 @@ ShellRoot { LazyLoader { activeAsync: root.laptop - component: Battery { + component: BatteryService { } } }