noctalia-shell/Services/ArchUpdaterService.qml
2025-08-24 10:46:28 -04:00

156 lines
3.8 KiB
QML

pragma Singleton
import Quickshell
import QtQuick
import Quickshell.Io
Singleton {
id: updateService
// Core properties
readonly property bool busy: checkupdatesProcess.running
readonly property int updates: updatePackages.length
property var updatePackages: []
property var selectedPackages: []
property int selectedPackagesCount: 0
property bool updateInProgress: false
// Process for checking updates
Process {
id: checkupdatesProcess
command: ["checkupdates"]
onExited: function (exitCode) {
if (exitCode !== 0 && exitCode !== 2) {
console.warn("[UpdateService] checkupdates failed (code:", exitCode, ")")
updatePackages = []
return
}
}
stdout: StdioCollector {
onStreamFinished: {
parseCheckupdatesOutput(text)
}
}
}
// Parse checkupdates output
function parseCheckupdatesOutput(output) {
const lines = output.trim().split('\n').filter(line => line.trim())
const packages = []
for (const line of lines) {
const m = line.match(/^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/)
if (m) {
packages.push({
"name": m[1],
"oldVersion": m[2],
"newVersion": m[3],
"description": `${m[1]} ${m[2]} -> ${m[3]}`
})
}
}
updatePackages = packages
}
// Check for updates
function doPoll() {
if (busy)
return
checkupdatesProcess.running = true
}
// Update all packages
function runUpdate() {
if (updates === 0) {
doPoll()
return
}
updateInProgress = true
Quickshell.execDetached(["pkexec", "pacman", "-Syu", "--noconfirm"])
// Refresh after updates with multiple attempts
refreshAfterUpdate()
}
// Update selected packages
function runSelectiveUpdate() {
if (selectedPackages.length === 0)
return
updateInProgress = true
const command = ["pkexec", "pacman", "-S", "--noconfirm"].concat(selectedPackages)
Quickshell.execDetached(command)
// Clear selection and refresh
selectedPackages = []
selectedPackagesCount = 0
refreshAfterUpdate()
}
// Package selection functions
function togglePackageSelection(packageName) {
const index = selectedPackages.indexOf(packageName)
if (index > -1) {
selectedPackages.splice(index, 1)
} else {
selectedPackages.push(packageName)
}
selectedPackagesCount = selectedPackages.length
}
function selectAllPackages() {
selectedPackages = updatePackages.map(pkg => pkg.name)
selectedPackagesCount = selectedPackages.length
}
function deselectAllPackages() {
selectedPackages = []
selectedPackagesCount = 0
}
function isPackageSelected(packageName) {
return selectedPackages.indexOf(packageName) > -1
}
// Robust refresh after updates
function refreshAfterUpdate() {
// First refresh attempt after 3 seconds
Qt.callLater(() => {
doPoll()
}, 3000)
// Second refresh attempt after 8 seconds
Qt.callLater(() => {
doPoll()
}, 8000)
// Third refresh attempt after 15 seconds
Qt.callLater(() => {
doPoll()
updateInProgress = false
}, 15000)
// Final refresh attempt after 30 seconds
Qt.callLater(() => {
doPoll()
}, 30000)
}
// Notification helper
function notify(title, body) {
Quickshell.execDetached(["notify-send", "-a", "UpdateService", "-i", "system-software-update", title, body])
}
// Auto-poll every 15 minutes
Timer {
interval: 15 * 60 * 1000 // 15 minutes
repeat: true
running: true
onTriggered: doPoll()
}
// Initial check
Component.onCompleted: doPoll()
}