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