Files
noctalia-shell/Services/BatteryService.qml
T
ItsLemmy 101b27fcc7 New windowing system
Large commit that totally refactor of the way we handle the bar and
panels.

Testing should focus on Panels, Bar, Keyboard Focus, IPC calls.

Changes brief:
- One NFullScreenWindow per screen which handle it's bar and dedicated
panels.
- Added shadows
- Reintroduced dimming
- New panels animations
- Proper Z ordering
- Panels on overlay laywer is not reimplemented, if we do it then the
bar will be on the Overlay too
- Panel dragging was not reimplemented, to be discussed before
reimplementing
- Still a WIP, need to work more on shadows and polishing + debugging.
2025-11-03 00:53:02 -05:00

248 lines
8.1 KiB
QML

pragma Singleton
import Quickshell
import Quickshell.Io
import Quickshell.Services.UPower
import qs.Commons
import qs.Services
Singleton {
id: root
enum ChargingMode {
Disabled = 0,
Full,
Balanced,
Lifespan
}
property int chargingMode: Settings.data.battery.chargingMode
readonly property string batterySetterScript: Quickshell.shellDir + '/Bin/battery-manager/set-battery-treshold.sh'
readonly property string batteryInstallerScript: Quickshell.shellDir + '/Bin/battery-manager/install-battery-manager.sh'
readonly property string batteryUninstallerScript: Quickshell.shellDir + '/Bin/battery-manager/uninstall-battery-manager.sh'
// This is used to omit toast message and writing mode to settings on startup
property bool initialSetter: true
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
return "battery-exclamation"
}
if (charging) {
return "battery-charging"
} else {
if (percent >= 90)
return "battery-4"
if (percent >= 50)
return "battery-3"
if (percent >= 25)
return "battery-2"
if (percent >= 0)
return "battery-1"
return "battery"
}
}
function getThresholdValue(chargingMode) {
switch (chargingMode) {
case BatteryService.ChargingMode.Full:
return "100"
case BatteryService.ChargingMode.Balanced:
return "80"
case BatteryService.ChargingMode.Lifespan:
return "60"
}
}
function toggleEnabled(enabled) {
if (enabled) {
setChargingMode(BatteryService.ChargingMode.Full)
} else {
BatteryService.initialSetter = true
ToastService.showNotice(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.uninstall-setup"))
PanelService.getPanel("batteryPanel", screen)?.toggle(this)
uninstallerProcess.running = true
}
}
function setChargingMode(newMode) {
if (newMode !== BatteryService.ChargingMode.Full && newMode !== BatteryService.ChargingMode.Balanced && newMode !== BatteryService.ChargingMode.Lifespan) {
Logger.w("BatteryService", `Invalid charging mode set ${newMode}`)
return
}
BatteryService.chargingMode = newMode
BatteryService.applyChargingMode()
}
function cycleModes() {
// Cycles charging modes from full to lifespan while skipping disabled
const nextMode = (chargingMode % 3) + 1
setChargingMode(nextMode)
}
function applyChargingMode() {
let command = [batterySetterScript]
// Currently the script sends notifications by default but quickshell
// uses toast messages so the flag is passed to supress notifs
command.push("-q")
command.push(BatteryService.getThresholdValue(BatteryService.chargingMode))
setterProcess.command = command
setterProcess.running = true
}
function runInstaller() {
installerProcess.command = ["pkexec", batteryInstallerScript]
installerProcess.running = true
}
function init() {
if (BatteryService.chargingMode !== BatteryService.ChargingMode.Disabled && BatteryService.chargingMode !== BatteryService.ChargingMode.Full) {
BatteryService.applyChargingMode()
}
}
Process {
id: setterProcess
workingDirectory: Quickshell.shellDir
running: false
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
Logger.i("BatteryService", "Battery threshold set successfully")
if (BatteryService.initialSetter) {
BatteryService.initialSetter = false
return
}
ToastService.showNotice(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.set-success-desc", {
"percent": BatteryService.getThresholdValue(BatteryService.chargingMode)
}), "battery")
Settings.data.battery.chargingMode = BatteryService.chargingMode
} else if (exitCode === 2) {
ToastService.showWarning(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.initial-setup"))
PanelService.getPanel("batteryPanel", screen)?.toggle(this)
BatteryService.runInstaller()
} else {
ToastService.showError(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.set-failed"))
Logger.e("BatteryService", `Setter process failed with exit code: ${exitCode}`)
}
}
stderr: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.w("BatteryService", "SetterProcess stderr:", this.text)
}
}
}
stdout: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.i("BatteryService", "SetterProcess stdout:", this.text)
}
}
}
}
// Installer process - installs battery manager components
Process {
id: installerProcess
workingDirectory: Quickshell.shellDir
running: false
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
ToastService.showNotice(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.install-success"))
BatteryService.applyChargingMode()
} else if (exitCode === 2) {
ToastService.showError(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.install-missing"))
} else if (exitCode === 3) {
ToastService.showError(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.install-unsupported"))
} else {
ToastService.showError(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.install-failed"))
}
if (exitCode !== 0) {
BatteryService.chargingMode = BatteryService.ChargingMode.Disabled
}
}
stderr: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.w("BatteryService", "InstallerProcess stderr:", this.text)
}
}
}
stdout: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.i("BatteryService", "InstallerProcess stdout:", this.text)
}
}
}
}
Process {
id: uninstallerProcess
workingDirectory: Quickshell.shellDir
command: ["pkexec", batteryUninstallerScript]
running: false
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
Logger.i("BatteryService", "Battery Manager uninstalled successfully")
ToastService.showNotice(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.uninstall-success"))
Settings.data.battery.chargingMode = BatteryService.chargingMode
BatteryService.chargingMode = BatteryService.ChargingMode.Disabled
cleanupProcess.running = true
} else {
ToastService.showError(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.uninstall-failed"))
Logger.e("BatteryService", `Uninstaller process failed with exit code: ${exitCode}`)
}
}
stderr: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.w("BatteryService", "UninstallerProcess stderr:", this.text)
}
}
}
stdout: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.i("BatteryService", "UninstallerProcess stdout:", this.text)
}
}
}
}
// Cleanup process - deletes uninstaller after it sucessfull ;
Process {
id: cleanupProcess
workingDirectory: Quickshell.shellDir
command: ["rm", "-rf", batteryUninstallerScript]
running: false
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
Logger.i("BatteryService", "Battery Manager uninstalled successfully")
} else {
Logger.e("BatteryService", `Cleanup process failed with exit code: ${exitCode}`)
}
}
stderr: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.w("BatteryService", "CleanupProcess stderr:", this.text)
}
}
}
stdout: StdioCollector {
onStreamFinished: {
if (this.text) {
Logger.i("BatteryService", "CleanupProcess stdout:", this.text)
}
}
}
}
}