summaryrefslogtreecommitdiff
path: root/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml
diff options
context:
space:
mode:
authornippy <you@example.com>2026-04-18 13:49:56 +0200
committernippy <you@example.com>2026-04-18 13:49:56 +0200
commit5d94c0a7d44a2255b81815a52a7056a94a39842d (patch)
tree759bdea9645c6a62f9e1e4c001f7d81cccd120d2 /raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml
parente79cdf210b267f21a186255ce1a4d50029439d54 (diff)
downloadRaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.tar.gz
RaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.zip
update Raveos themes
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml')
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml271
1 files changed, 271 insertions, 0 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml
new file mode 100644
index 0000000..e7cea56
--- /dev/null
+++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml
@@ -0,0 +1,271 @@
+pragma Singleton
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import Quickshell
+import Quickshell.Services.UPower
+import qs.Common
+
+Singleton {
+ id: root
+
+ property bool suppressSound: true
+ property bool previousPluggedState: false
+
+ readonly property var scale: 100 / SettingsData.batteryChargeLimit
+
+ Timer {
+ id: startupTimer
+ interval: 500
+ repeat: false
+ running: true
+ onTriggered: root.suppressSound = false
+ }
+
+ readonly property string preferredBatteryOverride: Quickshell.env("DMS_PREFERRED_BATTERY")
+
+ // List of laptop batteries
+ readonly property var batteries: UPower.devices.values.filter(dev => dev.isLaptopBattery)
+
+ readonly property bool usePreferred: preferredBatteryOverride && preferredBatteryOverride.length > 0
+
+ // Main battery (for backward compatibility)
+ readonly property UPowerDevice device: {
+ var preferredDev;
+ if (usePreferred) {
+ preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase()));
+ }
+ return preferredDev || batteries[0] || null;
+ }
+ // Whether at least one battery is available
+ readonly property bool batteryAvailable: batteries.length > 0
+ // Aggregated charge level (percentage)
+ readonly property real batteryLevel: {
+ if (!batteryAvailable)
+ return 0;
+ if (batteryCapacity === 0) {
+ if (usePreferred && device && device.ready)
+ return Math.round(device.percentage * 100 * scale);
+ const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0);
+ if (validBatteries.length === 0)
+ return 0;
+ const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length;
+ return Math.round(avgPercentage * 100 * scale);
+ }
+ return Math.round((batteryEnergy * 100) / batteryCapacity * scale);
+ }
+ readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging)
+
+ // Is the system plugged in (Is not running on battery)
+ readonly property bool isPluggedIn: !UPower.onBattery
+ readonly property bool isLowBattery: batteryAvailable && batteryLevel <= 20
+
+ onIsPluggedInChanged: {
+ if (suppressSound || !batteryAvailable) {
+ previousPluggedState = isPluggedIn;
+ return;
+ }
+
+ if (SettingsData.soundsEnabled && SettingsData.soundPluggedIn) {
+ if (isPluggedIn && !previousPluggedState) {
+ AudioService.playPowerPlugSound();
+ } else if (!isPluggedIn && previousPluggedState) {
+ AudioService.playPowerUnplugSound();
+ }
+ }
+
+ const profileValue = BatteryService.isPluggedIn ? SettingsData.acProfileName : SettingsData.batteryProfileName;
+
+ if (profileValue !== "") {
+ const targetProfile = parseInt(profileValue);
+ if (!isNaN(targetProfile) && PowerProfiles.profile !== targetProfile) {
+ PowerProfiles.profile = targetProfile;
+ }
+ }
+
+ previousPluggedState = isPluggedIn;
+ }
+
+ // Aggregated charge/discharge rate
+ readonly property real changeRate: {
+ if (!batteryAvailable)
+ return 0;
+ if (usePreferred && device && device.ready)
+ return device.changeRate;
+ return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0;
+ }
+
+ // Aggregated battery health
+ readonly property string batteryHealth: {
+ if (!batteryAvailable)
+ return "N/A";
+
+ // If a preferred battery is selected and ready
+ if (usePreferred && device && device.ready && device.healthSupported)
+ return `${Math.round(device.healthPercentage)}%`;
+
+ // Otherwise, calculate the average health of all laptop batteries
+ const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0);
+ if (validBatteries.length === 0)
+ return "N/A";
+
+ const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length;
+ return `${Math.round(avgHealth)}%`;
+ }
+
+ readonly property real batteryEnergy: {
+ if (!batteryAvailable)
+ return 0;
+ if (usePreferred && device && device.ready)
+ return device.energy;
+ return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0;
+ }
+
+ // Total battery capacity (Wh)
+ readonly property real batteryCapacity: {
+ if (!batteryAvailable)
+ return 0;
+ if (usePreferred && device && device.ready)
+ return device.energyCapacity;
+ return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0;
+ }
+
+ function translateBatteryState(state) {
+ switch (state) {
+ case UPowerDeviceState.Charging:
+ return I18n.tr("Charging", "battery status");
+ case UPowerDeviceState.Discharging:
+ return I18n.tr("Discharging", "battery status");
+ case UPowerDeviceState.Empty:
+ return I18n.tr("Empty", "battery status");
+ case UPowerDeviceState.FullyCharged:
+ return I18n.tr("Fully Charged", "battery status");
+ case UPowerDeviceState.PendingCharge:
+ return I18n.tr("Pending Charge", "battery status");
+ case UPowerDeviceState.PendingDischarge:
+ return I18n.tr("Pending Discharge", "battery status");
+ default:
+ return I18n.tr("Unknown", "battery status");
+ }
+ }
+
+ // Aggregated battery status
+ readonly property string batteryStatus: {
+ if (!batteryAvailable) {
+ return I18n.tr("No Battery", "battery status");
+ }
+
+ if (isCharging && !batteries.some(b => b.changeRate > 0))
+ return I18n.tr("Plugged In", "battery status");
+
+ const states = batteries.map(b => b.state);
+ if (states.every(s => s === states[0]))
+ return translateBatteryState(states[0]);
+
+ return isCharging ? I18n.tr("Charging", "battery status") : (isPluggedIn ? I18n.tr("Plugged In", "battery status") : I18n.tr("Discharging", "battery status"));
+ }
+
+ readonly property bool suggestPowerSaver: false
+
+ readonly property var bluetoothDevices: {
+ const btDevices = [];
+ const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers];
+
+ for (var i = 0; i < UPower.devices.count; i++) {
+ const dev = UPower.devices.get(i);
+ if (dev && dev.ready && bluetoothTypes.includes(dev.type)) {
+ btDevices.push({
+ "name": dev.model || UPowerDeviceType.toString(dev.type),
+ "percentage": Math.round(dev.percentage * 100),
+ "type": dev.type
+ });
+ }
+ }
+ return btDevices;
+ }
+
+ // Format time remaining for charge/discharge
+ function formatTimeRemaining() {
+ if (!batteryAvailable) {
+ return "Unknown";
+ }
+
+ let totalTime = 0;
+ totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate);
+ const avgTime = Math.abs(totalTime * 3600);
+ if (!avgTime || avgTime <= 0 || avgTime > 86400)
+ return "Unknown";
+
+ const hours = Math.floor(avgTime / 3600);
+ const minutes = Math.floor((avgTime % 3600) / 60);
+ return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
+ }
+
+ function getBatteryIcon() {
+ if (!batteryAvailable) {
+ return "power";
+ }
+
+ if (isCharging) {
+ if (batteryLevel >= 90) {
+ return "battery_charging_full";
+ }
+ if (batteryLevel >= 80) {
+ return "battery_charging_90";
+ }
+ if (batteryLevel >= 60) {
+ return "battery_charging_80";
+ }
+ if (batteryLevel >= 50) {
+ return "battery_charging_60";
+ }
+ if (batteryLevel >= 30) {
+ return "battery_charging_50";
+ }
+ if (batteryLevel >= 20) {
+ return "battery_charging_30";
+ }
+ return "battery_charging_20";
+ }
+ if (isPluggedIn) {
+ if (batteryLevel >= 90) {
+ return "battery_charging_full";
+ }
+ if (batteryLevel >= 80) {
+ return "battery_charging_90";
+ }
+ if (batteryLevel >= 60) {
+ return "battery_charging_80";
+ }
+ if (batteryLevel >= 50) {
+ return "battery_charging_60";
+ }
+ if (batteryLevel >= 30) {
+ return "battery_charging_50";
+ }
+ if (batteryLevel >= 20) {
+ return "battery_charging_30";
+ }
+ return "battery_charging_20";
+ }
+ if (batteryLevel >= 95) {
+ return "battery_full";
+ }
+ if (batteryLevel >= 85) {
+ return "battery_6_bar";
+ }
+ if (batteryLevel >= 70) {
+ return "battery_5_bar";
+ }
+ if (batteryLevel >= 55) {
+ return "battery_4_bar";
+ }
+ if (batteryLevel >= 40) {
+ return "battery_3_bar";
+ }
+ if (batteryLevel >= 25) {
+ return "battery_2_bar";
+ }
+ return "battery_1_bar";
+ }
+}