noctalia-shell/Services/ArchUpdaterService.qml
2025-08-24 16:35:10 +02:00

153 lines
4.2 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()
}