1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-02 11:38:30 -04:00
Files
DankMaterialShell/quickshell/Services/SystemUpdateService.qml
2026-07-17 10:18:51 -04:00

260 lines
7.9 KiB
QML

pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.Common
import qs.Services
Singleton {
id: root
property int refCount: 0
property bool sysupdateAvailable: false
property var availableUpdates: []
property var _rawUpdates: []
property bool isChecking: false
property bool isUpgrading: false
property bool hasError: false
property string errorMessage: ""
property string errorHint: ""
property string errorCode: ""
property var backends: []
property string distribution: ""
property string distributionPretty: ""
property string pkgManager: ""
property bool distributionSupported: false
property var recentLog: []
property int intervalSeconds: 1800
property int lastCheckUnix: 0
property int nextCheckUnix: 0
readonly property int updateCount: availableUpdates.length
readonly property bool helperAvailable: sysupdateAvailable && backends.length > 0
readonly property bool useCustomCommand: SettingsData.updaterUseCustomCommand && (SettingsData.updaterCustomCommand || "").trim().length > 0
// Dont allow partial updates on arch, if they wanna break their system they can do it outside of DMS:
// https://wiki.archlinux.org/title/System_maintenance#Partial_upgrades_are_unsupported
// AUR/Flatpak packages stay ignorable — holding those cannot break the repo dependency graph.
readonly property bool systemHoldsAllowed: !["pacman", "paru", "yay"].includes(pkgManager)
function canIgnorePackage(pkg) {
if (!pkg)
return false;
return systemHoldsAllowed || pkg.repo !== "system";
}
Connections {
target: DMSService
function onCapabilitiesReceived() {
root.checkCapabilities();
}
function onConnectionStateChanged() {
if (DMSService.isConnected) {
root.checkCapabilities();
} else {
root.sysupdateAvailable = false;
root._startupCheckDone = false;
}
Qt.callLater(() => root._maybeStartupCheck());
}
function onSysupdateStateUpdate(data) {
root._applyState(data);
}
}
Connections {
target: SettingsData
function onUpdaterCheckOnStartChanged() {
Qt.callLater(() => root._maybeStartupCheck());
}
function onUpdaterAllowAURChanged() {
root._refilter();
}
function onUpdaterIgnoredPackagesChanged() {
root._refilter();
}
function on_HasLoadedChanged() {
Qt.callLater(() => root._maybeStartupCheck());
}
}
Component.onCompleted: {
if (DMSService.dmsAvailable) {
checkCapabilities();
}
Qt.callLater(() => root._maybeStartupCheck());
}
function checkCapabilities() {
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
sysupdateAvailable = false;
Qt.callLater(() => root._maybeStartupCheck());
return;
}
const has = DMSService.capabilities.includes("sysupdate");
if (has && !sysupdateAvailable) {
sysupdateAvailable = true;
requestState();
} else if (!has) {
sysupdateAvailable = false;
}
Qt.callLater(() => root._maybeStartupCheck());
}
function requestState() {
if (!DMSService.isConnected || !sysupdateAvailable) {
return;
}
DMSService.sysupdateGetState(resp => {
if (resp && resp.result) {
_applyState(resp.result);
}
});
}
function _applyState(data) {
if (!data) {
return;
}
backends = data.backends || [];
const systemBackend = backends.find(b => b.repo === "system" || b.repo === "ostree");
pkgManager = systemBackend ? systemBackend.id : (backends.length > 0 ? backends[0].id : "");
_rawUpdates = data.packages || [];
availableUpdates = _filterUpdates(_rawUpdates);
distribution = data.distro || "";
distributionPretty = data.distroPretty || "";
distributionSupported = (backends.length > 0);
recentLog = data.recentLog || [];
intervalSeconds = data.intervalSeconds || 1800;
lastCheckUnix = data.lastCheckUnix || 0;
nextCheckUnix = data.nextCheckUnix || 0;
const phase = data.phase || "idle";
switch (phase) {
case "refreshing":
isChecking = true;
isUpgrading = false;
break;
case "upgrading":
isChecking = false;
isUpgrading = true;
break;
default:
isChecking = false;
isUpgrading = false;
}
if (data.error) {
hasError = true;
errorMessage = data.error.message || "";
errorCode = data.error.code || "";
errorHint = data.error.hint || "";
} else {
hasError = false;
errorMessage = "";
errorCode = "";
errorHint = "";
}
}
function _filterUpdates(pkgs) {
const ignored = SettingsData.updaterIgnoredPackages || [];
return (pkgs || []).filter(p => {
if (!SettingsData.updaterAllowAUR && p.repo === "aur")
return false;
if (!canIgnorePackage(p))
return true;
return ignored.indexOf(p.name) === -1;
});
}
function _refilter() {
availableUpdates = _filterUpdates(_rawUpdates);
}
function ignorePackage(name) {
if (!name)
return;
const list = (SettingsData.updaterIgnoredPackages || []).slice();
if (list.indexOf(name) !== -1)
return;
list.push(name);
SettingsData.set("updaterIgnoredPackages", list);
}
function unignorePackage(name) {
if (!name)
return;
const list = (SettingsData.updaterIgnoredPackages || []).filter(p => p !== name);
SettingsData.set("updaterIgnoredPackages", list);
}
function checkForUpdates() {
DMSService.sysupdateRefresh(false, null);
}
function runUpdates(opts) {
const params = opts || {};
params.ignored = SettingsData.updaterIgnoredPackages || [];
if (useCustomCommand) {
params.customCommand = SettingsData.updaterCustomCommand.trim();
const termArgs = (SettingsData.updaterTerminalAdditionalParams || "").trim();
if (termArgs.length > 0) {
params.terminalArgs = termArgs.split(/\s+/);
}
}
DMSService.sysupdateUpgrade(params, null);
}
function cancelUpdates() {
DMSService.sysupdateCancel(null);
}
function setInterval(seconds) {
DMSService.sysupdateSetInterval(seconds, null);
}
property bool _startupCheckDone: false
function _maybeStartupCheck() {
if (refCount <= 0) {
_startupCheckDone = false;
return;
}
if (!SettingsData.updaterCheckOnStart)
return;
if (_startupCheckDone)
return;
if (!DMSService.isConnected || !sysupdateAvailable)
return;
_startupCheckDone = true;
Qt.callLater(() => root.checkForUpdates());
}
onRefCountChanged: {
if (refCount <= 0)
_startupCheckDone = false;
_syncAcquire();
Qt.callLater(() => root._maybeStartupCheck());
}
onSysupdateAvailableChanged: _syncAcquire()
property bool _acquired: false
function _syncAcquire() {
const want = refCount > 0 && sysupdateAvailable;
if (want === _acquired) {
return;
}
_acquired = want;
if (want) {
DMSService.sysupdateAcquire(null);
return;
}
DMSService.sysupdateRelease(null);
}
}