mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-09 23:15:38 -05:00
Fixed battery status on laptops. Updated power profiles.
This commit is contained in:
@@ -1,120 +1,182 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
|
import Quickshell.Io
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// Debug mode for testing on desktop systems without batteries
|
// Debug mode for testing (disabled for now)
|
||||||
property bool debugMode: false // Set to true to enable fake battery for testing
|
property bool debugMode: false
|
||||||
|
|
||||||
// Debug fake battery data
|
// Battery properties - using shell command method (native UPower API commented out due to issues)
|
||||||
property int debugBatteryLevel: 65
|
property bool batteryAvailable: systemBatteryPercentage > 0
|
||||||
property string debugBatteryStatus: "Discharging"
|
property int batteryLevel: systemBatteryPercentage
|
||||||
property int debugTimeRemaining: 7200 // 2 hours in seconds
|
property string batteryStatus: {
|
||||||
property bool debugIsCharging: false
|
return systemBatteryState === "charging" ? "Charging" :
|
||||||
property int debugBatteryHealth: 88
|
systemBatteryState === "discharging" ? "Discharging" :
|
||||||
property string debugBatteryTechnology: "Li-ion"
|
systemBatteryState === "fully-charged" ? "Full" :
|
||||||
property int debugBatteryCapacity: 45000 // 45 Wh in mWh
|
systemBatteryState === "empty" ? "Empty" : "Unknown"
|
||||||
|
}
|
||||||
|
property int timeRemaining: 0 // Not implemented for shell fallback
|
||||||
|
property bool isCharging: systemBatteryState === "charging"
|
||||||
|
property bool isLowBattery: systemBatteryPercentage <= 20
|
||||||
|
|
||||||
property bool batteryAvailable: debugMode || (battery.ready && battery.isLaptopBattery)
|
/* Native UPower API (commented out - not working correctly, returns 1% instead of actual values)
|
||||||
property int batteryLevel: debugMode ? debugBatteryLevel : Math.round(battery.percentage)
|
property bool batteryAvailable: (UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.percentage > 0) || systemBatteryPercentage > 0
|
||||||
property string batteryStatus: debugMode ? debugBatteryStatus : UPowerDeviceState.toString(battery.state)
|
property int batteryLevel: {
|
||||||
property int timeRemaining: debugMode ? debugTimeRemaining : (battery.timeToEmpty || battery.timeToFull)
|
if (UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.percentage > 0) {
|
||||||
property bool isCharging: debugMode ? debugIsCharging : (battery.state === UPowerDeviceState.Charging)
|
return Math.round(UPower.displayDevice.percentage)
|
||||||
property bool isLowBattery: debugMode ? (debugBatteryLevel <= 20) : (battery.percentage <= 20)
|
}
|
||||||
property int batteryHealth: debugMode ? debugBatteryHealth : (battery.healthSupported ? Math.round(battery.healthPercentage) : 100)
|
return systemBatteryPercentage
|
||||||
property string batteryTechnology: {
|
}
|
||||||
if (debugMode) return debugBatteryTechnology
|
property string batteryStatus: {
|
||||||
|
if (UPower.displayDevice && UPower.displayDevice.ready) {
|
||||||
// Try to get technology from any available laptop battery
|
switch(UPower.displayDevice.state) {
|
||||||
for (let i = 0; i < UPower.devices.length; i++) {
|
case UPowerDeviceState.Charging: return "Charging"
|
||||||
let device = UPower.devices[i]
|
case UPowerDeviceState.Discharging: return "Discharging"
|
||||||
if (device.isLaptopBattery && device.ready) {
|
case UPowerDeviceState.FullyCharged: return "Full"
|
||||||
// UPower doesn't expose technology directly, but we can get it from the model
|
case UPowerDeviceState.Empty: return "Empty"
|
||||||
let model = device.model || ""
|
case UPowerDeviceState.PendingCharge: return "Pending Charge"
|
||||||
if (model.toLowerCase().includes("li-ion") || model.toLowerCase().includes("lithium")) {
|
case UPowerDeviceState.PendingDischarge: return "Pending Discharge"
|
||||||
return "Li-ion"
|
case UPowerDeviceState.Unknown:
|
||||||
} else if (model.toLowerCase().includes("li-po") || model.toLowerCase().includes("polymer")) {
|
default: return "Unknown"
|
||||||
return "Li-polymer"
|
|
||||||
} else if (model.toLowerCase().includes("nimh")) {
|
|
||||||
return "NiMH"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return systemBatteryState === "charging" ? "Charging" :
|
||||||
|
systemBatteryState === "discharging" ? "Discharging" :
|
||||||
|
systemBatteryState === "fully-charged" ? "Full" :
|
||||||
|
systemBatteryState === "empty" ? "Empty" : "Unknown"
|
||||||
}
|
}
|
||||||
return "Unknown"
|
property int timeRemaining: (UPower.displayDevice && UPower.displayDevice.ready) ? (UPower.displayDevice.timeToEmpty || UPower.displayDevice.timeToFull || 0) : 0
|
||||||
|
property bool isCharging: {
|
||||||
|
if (UPower.displayDevice && UPower.displayDevice.ready) {
|
||||||
|
return UPower.displayDevice.state === UPowerDeviceState.Charging
|
||||||
}
|
}
|
||||||
property int cycleCount: 0 // UPower doesn't expose cycle count
|
return systemBatteryState === "charging"
|
||||||
property int batteryCapacity: debugMode ? debugBatteryCapacity : Math.round(battery.energyCapacity * 1000)
|
}
|
||||||
|
property bool isLowBattery: {
|
||||||
|
if (UPower.displayDevice && UPower.displayDevice.ready) {
|
||||||
|
return UPower.displayDevice.percentage <= 20
|
||||||
|
}
|
||||||
|
return systemBatteryPercentage <= 20
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
property int batteryHealth: 100 // Default fallback
|
||||||
|
property string batteryTechnology: "Li-ion" // Default fallback
|
||||||
|
property int cycleCount: 0 // Not implemented for shell fallback
|
||||||
|
property int batteryCapacity: 45000 // Default fallback
|
||||||
property var powerProfiles: availableProfiles
|
property var powerProfiles: availableProfiles
|
||||||
property string activePowerProfile: PowerProfile.toString(PowerProfiles.profile)
|
property string activePowerProfile: "balanced" // Default fallback
|
||||||
|
|
||||||
property var battery: UPower.displayDevice
|
// System battery info from shell command (primary source)
|
||||||
|
property int systemBatteryPercentage: 100 // Default value, will be updated by shell command
|
||||||
|
property string systemBatteryState: "charging" // Default value, will be updated by shell command
|
||||||
|
|
||||||
property var availableProfiles: {
|
// Shell command fallback for battery info
|
||||||
let profiles = []
|
Process {
|
||||||
if (PowerProfiles.profile !== undefined) {
|
id: batteryProcess
|
||||||
profiles.push("power-saver")
|
running: false
|
||||||
profiles.push("balanced")
|
command: ["upower", "-i", "/org/freedesktop/UPower/devices/battery_BAT1"]
|
||||||
if (PowerProfiles.hasPerformanceProfile) {
|
|
||||||
profiles.push("performance")
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
if (text.trim()) {
|
||||||
|
let output = text.trim()
|
||||||
|
let percentageMatch = output.match(/percentage:\s*(\d+)%/)
|
||||||
|
let stateMatch = output.match(/state:\s*(\w+)/)
|
||||||
|
|
||||||
|
if (percentageMatch) {
|
||||||
|
root.systemBatteryPercentage = parseInt(percentageMatch[1])
|
||||||
|
console.log("Battery percentage updated to:", root.systemBatteryPercentage)
|
||||||
|
}
|
||||||
|
if (stateMatch) {
|
||||||
|
root.systemBatteryState = stateMatch[1]
|
||||||
|
console.log("Battery state updated to:", root.systemBatteryState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return profiles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer to simulate battery changes in debug mode
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("Battery process failed with exit code:", exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Timer to periodically check battery status
|
||||||
Timer {
|
Timer {
|
||||||
id: debugTimer
|
interval: 5000 // Check every 5 seconds
|
||||||
interval: 5000 // Update every 5 seconds
|
running: true
|
||||||
running: debugMode
|
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
// Simulate battery discharge/charge
|
batteryProcess.running = true
|
||||||
if (debugIsCharging) {
|
|
||||||
debugBatteryLevel = Math.min(100, debugBatteryLevel + 1)
|
|
||||||
if (debugBatteryLevel >= 100) {
|
|
||||||
debugBatteryStatus = "Full"
|
|
||||||
debugIsCharging = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debugBatteryLevel = Math.max(0, debugBatteryLevel - 1)
|
|
||||||
if (debugBatteryLevel <= 15) {
|
|
||||||
debugBatteryStatus = "Charging"
|
|
||||||
debugIsCharging = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update time remaining
|
Component.onCompleted: {
|
||||||
debugTimeRemaining = debugIsCharging ?
|
// Initial battery check
|
||||||
Math.max(0, debugTimeRemaining - 300) : // 5 minutes less to full
|
batteryProcess.running = true
|
||||||
Math.max(0, debugTimeRemaining - 300) // 5 minutes less remaining
|
// Get current power profile
|
||||||
|
getCurrentProfile()
|
||||||
|
console.log("BatteryService initialized with shell command approach")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property var availableProfiles: {
|
||||||
|
// Try to use power-profiles-daemon via shell command
|
||||||
|
return ["power-saver", "balanced", "performance"]
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBatteryProfile(profileName) {
|
function setBatteryProfile(profileName) {
|
||||||
let profile = PowerProfile.Balanced
|
|
||||||
|
|
||||||
if (profileName === "power-saver") {
|
|
||||||
profile = PowerProfile.PowerSaver
|
|
||||||
} else if (profileName === "balanced") {
|
|
||||||
profile = PowerProfile.Balanced
|
|
||||||
} else if (profileName === "performance") {
|
|
||||||
if (PowerProfiles.hasPerformanceProfile) {
|
|
||||||
profile = PowerProfile.Performance
|
|
||||||
} else {
|
|
||||||
console.warn("Performance profile not available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn("Invalid power profile:", profileName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Setting power profile to:", profileName)
|
console.log("Setting power profile to:", profileName)
|
||||||
PowerProfiles.profile = profile
|
powerProfileProcess.command = ["powerprofilesctl", "set", profileName]
|
||||||
|
powerProfileProcess.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process to set power profile
|
||||||
|
Process {
|
||||||
|
id: powerProfileProcess
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
console.log("Power profile set successfully")
|
||||||
|
// Update current profile
|
||||||
|
getCurrentProfile()
|
||||||
|
} else {
|
||||||
|
console.warn("Failed to set power profile, exit code:", exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process to get current power profile
|
||||||
|
Process {
|
||||||
|
id: getCurrentProfileProcess
|
||||||
|
running: false
|
||||||
|
command: ["powerprofilesctl", "get"]
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
if (text.trim()) {
|
||||||
|
root.activePowerProfile = text.trim()
|
||||||
|
console.log("Current power profile:", root.activePowerProfile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("Failed to get current power profile, exit code:", exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentProfile() {
|
||||||
|
getCurrentProfileProcess.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBatteryIcon() {
|
function getBatteryIcon() {
|
||||||
|
|||||||
Reference in New Issue
Block a user