From 903ef0cc7222f24796abde076ec590fb9a9a8361 Mon Sep 17 00:00:00 2001 From: bbedward Date: Mon, 15 Sep 2025 11:55:15 -0400 Subject: [PATCH] make system updater widget more generic --- Modules/Settings/TopBarTab.qml | 8 +-- ...daterPopout.qml => SystemUpdatePopout.qml} | 56 +++++++++---------- .../{ArchUpdater.qml => SystemUpdate.qml} | 10 ++-- Modules/TopBar/TopBar.qml | 18 +++--- ...terService.qml => SystemUpdateService.qml} | 49 ++++++++++++---- shell.qml | 6 +- 6 files changed, 86 insertions(+), 61 deletions(-) rename Modules/{ArchUpdaterPopout.qml => SystemUpdatePopout.qml} (84%) rename Modules/TopBar/{ArchUpdater.qml => SystemUpdate.qml} (90%) rename Services/{ArchUpdaterService.qml => SystemUpdateService.qml} (59%) diff --git a/Modules/Settings/TopBarTab.qml b/Modules/Settings/TopBarTab.qml index c5519f83..02d543e6 100644 --- a/Modules/Settings/TopBarTab.qml +++ b/Modules/Settings/TopBarTab.qml @@ -164,11 +164,11 @@ Item { "icon": "palette", "enabled": true }, { - "id": "archUpdater", - "text": "Arch Updater", - "description": "Check for updates in Arch-based systems", + "id": "systemUpdate", + "text": "System Update", + "description": "Check for system updates", "icon": "update", - "enabled": true + "enabled": SystemUpdateService.distributionSupported }] property var defaultLeftWidgets: [{ "id": "launcherButton", diff --git a/Modules/ArchUpdaterPopout.qml b/Modules/SystemUpdatePopout.qml similarity index 84% rename from Modules/ArchUpdaterPopout.qml rename to Modules/SystemUpdatePopout.qml index 3954db53..28b883c7 100644 --- a/Modules/ArchUpdaterPopout.qml +++ b/Modules/SystemUpdatePopout.qml @@ -9,7 +9,7 @@ import qs.Services import qs.Widgets DankPopout { - id: archUpdaterPopout + id: systemUpdatePopout property var parentWidget: null property string triggerSection: "right" @@ -35,8 +35,8 @@ DankPopout { onShouldBeVisibleChanged: { if (shouldBeVisible) { - if (ArchUpdaterService.updateCount === 0 && !ArchUpdaterService.isChecking) { - ArchUpdaterService.checkForUpdates() + if (SystemUpdateService.updateCount === 0 && !SystemUpdateService.isChecking) { + SystemUpdateService.checkForUpdates() } } } @@ -103,14 +103,14 @@ DankPopout { StyledText { anchors.verticalCenter: parent.verticalCenter text: { - if (ArchUpdaterService.isChecking) return "Checking..."; - if (ArchUpdaterService.hasError) return "Error"; - if (ArchUpdaterService.updateCount === 0) return "Up to date"; - return ArchUpdaterService.updateCount + " updates"; + if (SystemUpdateService.isChecking) return "Checking..."; + if (SystemUpdateService.hasError) return "Error"; + if (SystemUpdateService.updateCount === 0) return "Up to date"; + return SystemUpdateService.updateCount + " updates"; } font.pixelSize: Theme.fontSizeMedium color: { - if (ArchUpdaterService.hasError) return Theme.error; + if (SystemUpdateService.hasError) return Theme.error; return Theme.surfaceText; } } @@ -122,10 +122,10 @@ DankPopout { iconSize: 18 z: 15 iconColor: Theme.surfaceText - enabled: !ArchUpdaterService.isChecking + enabled: !SystemUpdateService.isChecking opacity: enabled ? 1.0 : 0.5 onClicked: { - ArchUpdaterService.checkForUpdates() + SystemUpdateService.checkForUpdates() } RotationAnimation { @@ -134,7 +134,7 @@ DankPopout { from: 0 to: 360 duration: 1000 - running: ArchUpdaterService.isChecking + running: SystemUpdateService.isChecking loops: Animation.Infinite onRunningChanged: { @@ -168,39 +168,39 @@ DankPopout { id: statusText width: parent.width text: { - if (ArchUpdaterService.hasError) { - return "Failed to check for updates:\n" + ArchUpdaterService.errorMessage; + if (SystemUpdateService.hasError) { + return "Failed to check for updates:\n" + SystemUpdateService.errorMessage; } - if (!ArchUpdaterService.helperAvailable) { - return "No AUR helper found. Please install 'paru' or 'yay' to check for updates."; + if (!SystemUpdateService.helperAvailable) { + return "No package manager found. Please install 'paru' or 'yay' to check for updates."; } - if (ArchUpdaterService.isChecking) { + if (SystemUpdateService.isChecking) { return "Checking for updates..."; } - if (ArchUpdaterService.updateCount === 0) { + if (SystemUpdateService.updateCount === 0) { return "Your system is up to date!"; } - return `Found ${ArchUpdaterService.updateCount} packages to update:`; + return `Found ${SystemUpdateService.updateCount} packages to update:`; } font.pixelSize: Theme.fontSizeMedium color: { - if (ArchUpdaterService.hasError) return Theme.errorText; + if (SystemUpdateService.hasError) return Theme.errorText; return Theme.surfaceText; } wrapMode: Text.WordWrap - visible: ArchUpdaterService.updateCount === 0 || ArchUpdaterService.hasError || ArchUpdaterService.isChecking + visible: SystemUpdateService.updateCount === 0 || SystemUpdateService.hasError || SystemUpdateService.isChecking } DankListView { id: packagesList width: parent.width - height: parent.height - (ArchUpdaterService.updateCount === 0 || ArchUpdaterService.hasError || ArchUpdaterService.isChecking ? statusText.height + Theme.spacingM : 0) - visible: ArchUpdaterService.updateCount > 0 && !ArchUpdaterService.isChecking && !ArchUpdaterService.hasError + height: parent.height - (SystemUpdateService.updateCount === 0 || SystemUpdateService.hasError || SystemUpdateService.isChecking ? statusText.height + Theme.spacingM : 0) + visible: SystemUpdateService.updateCount > 0 && !SystemUpdateService.isChecking && !SystemUpdateService.hasError clip: true spacing: Theme.spacingXS - model: ArchUpdaterService.availableUpdates + model: SystemUpdateService.availableUpdates delegate: Rectangle { width: ListView.view.width - Theme.spacingM @@ -265,7 +265,7 @@ DankPopout { height: parent.height radius: Theme.cornerRadius color: updateMouseArea.containsMouse ? Theme.primaryHover : Theme.secondaryHover - opacity: ArchUpdaterService.updateCount > 0 ? 1.0 : 0.5 + opacity: SystemUpdateService.updateCount > 0 ? 1.0 : 0.5 Behavior on color { ColorAnimation { duration: Theme.shortDuration } @@ -296,10 +296,10 @@ DankPopout { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - enabled: ArchUpdaterService.updateCount > 0 + enabled: SystemUpdateService.updateCount > 0 onClicked: { - ArchUpdaterService.runUpdates() - archUpdaterPopout.close() + SystemUpdateService.runUpdates() + systemUpdatePopout.close() } } } @@ -341,7 +341,7 @@ DankPopout { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { - archUpdaterPopout.close() + systemUpdatePopout.close() } } } diff --git a/Modules/TopBar/ArchUpdater.qml b/Modules/TopBar/SystemUpdate.qml similarity index 90% rename from Modules/TopBar/ArchUpdater.qml rename to Modules/TopBar/SystemUpdate.qml index 4313a613..1844b8dd 100644 --- a/Modules/TopBar/ArchUpdater.qml +++ b/Modules/TopBar/SystemUpdate.qml @@ -13,8 +13,8 @@ Rectangle { property real widgetHeight: 30 property real barHeight: 48 readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) - readonly property bool hasUpdates: ArchUpdaterService.updateCount > 0 - readonly property bool isChecking: ArchUpdaterService.isChecking + readonly property bool hasUpdates: SystemUpdateService.updateCount > 0 + readonly property bool isChecking: SystemUpdateService.isChecking signal clicked() @@ -42,13 +42,13 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter name: { if (isChecking) return "refresh"; - if (ArchUpdaterService.hasError) return "error"; + if (SystemUpdateService.hasError) return "error"; if (hasUpdates) return "system_update_alt"; return "check_circle"; } size: Theme.iconSize - 6 color: { - if (ArchUpdaterService.hasError) return Theme.error; + if (SystemUpdateService.hasError) return Theme.error; if (hasUpdates) return Theme.primary; return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText); } @@ -75,7 +75,7 @@ Rectangle { id: countText anchors.verticalCenter: parent.verticalCenter - text: ArchUpdaterService.updateCount.toString() + text: SystemUpdateService.updateCount.toString() font.pixelSize: Theme.fontSizeSmall font.weight: Font.Medium color: Theme.surfaceText diff --git a/Modules/TopBar/TopBar.qml b/Modules/TopBar/TopBar.qml index 26b16449..6e4c0d76 100644 --- a/Modules/TopBar/TopBar.qml +++ b/Modules/TopBar/TopBar.qml @@ -184,7 +184,7 @@ PanelWindow { "loader": clipboardHistoryModalPopup, "prop": "visible" }, { - "loader": archUpdaterLoader, + "loader": systemUpdateLoader, "prop": "shouldBeVisible" }] return notepadInstanceVisible || loaders.some(item => { @@ -377,7 +377,7 @@ PanelWindow { "vpn": vpnComponent, "notepadButton": notepadButtonComponent, "colorPicker": colorPickerComponent, - "archUpdater": archUpdaterComponent + "systemUpdate": systemUpdateComponent }) function getWidgetComponent(widgetId) { @@ -1022,21 +1022,21 @@ PanelWindow { } Component { - id: archUpdaterComponent + id: systemUpdateComponent - ArchUpdater { - isActive: archUpdaterLoader.item ? archUpdaterLoader.item.shouldBeVisible : false + SystemUpdate { + isActive: systemUpdateLoader.item ? systemUpdateLoader.item.shouldBeVisible : false widgetHeight: root.widgetHeight barHeight: root.effectiveBarHeight section: topBarContent.getWidgetSection(parent) || "right" popupTarget: { - archUpdaterLoader.active = true - return archUpdaterLoader.item + systemUpdateLoader.active = true + return systemUpdateLoader.item } parentScreen: root.screen onClicked: { - archUpdaterLoader.active = true - archUpdaterLoader.item?.toggle() + systemUpdateLoader.active = true + systemUpdateLoader.item?.toggle() } } } diff --git a/Services/ArchUpdaterService.qml b/Services/SystemUpdateService.qml similarity index 59% rename from Services/ArchUpdaterService.qml rename to Services/SystemUpdateService.qml index 8300a957..b71c6bd4 100644 --- a/Services/ArchUpdaterService.qml +++ b/Services/SystemUpdateService.qml @@ -14,23 +14,48 @@ Singleton { property bool isChecking: false property bool hasError: false property string errorMessage: "" - property string aurHelper: "" + property string pkgManager: "" + property string distribution: "" + property bool distributionSupported: false + readonly property list supportedDistributions: ["arch", "cachyos", "manjaro", "endeavouros"] readonly property int updateCount: availableUpdates.length - readonly property bool helperAvailable: aurHelper !== "" + readonly property bool helperAvailable: pkgManager !== "" && distributionSupported Process { - id: helperDetection - command: ["sh", "-c", "which paru || which yay"] + id: distributionDetection + command: ["sh", "-c", "cat /etc/os-release | grep '^ID=' | cut -d'=' -f2 | tr -d '\"'"] running: true + onExited: (exitCode) => { + if (exitCode === 0) { + distribution = stdout.text.trim().toLowerCase() + distributionSupported = supportedDistributions.includes(distribution) + + if (distributionSupported) { + helperDetection.running = true + } else { + console.warn("SystemUpdate: Unsupported distribution:", distribution) + } + } else { + console.warn("SystemUpdate: Failed to detect distribution") + } + } + + stdout: StdioCollector {} + } + + Process { + id: helperDetection + command: ["sh", "-c", "which paru || which yay"] + onExited: (exitCode) => { if (exitCode === 0) { const helperPath = stdout.text.trim() - aurHelper = helperPath.split('/').pop() + pkgManager = helperPath.split('/').pop() checkForUpdates() } else { - console.warn("ArchUpdater: No AUR helper found") + console.warn("SystemUpdate: No package manager found") } } @@ -50,7 +75,7 @@ Singleton { } else { hasError = true errorMessage = "Failed to check for updates" - console.warn("ArchUpdater: Update check failed with code:", exitCode) + console.warn("SystemUpdate: Update check failed with code:", exitCode) } } @@ -65,11 +90,11 @@ Singleton { } function checkForUpdates() { - if (!helperAvailable || isChecking) return + if (!distributionSupported || !pkgManager || isChecking) return isChecking = true hasError = false - updateChecker.command = [aurHelper, "-Qu"] + updateChecker.command = [pkgManager, "-Qu"] updateChecker.running = true } @@ -93,10 +118,10 @@ Singleton { } function runUpdates() { - if (!helperAvailable || updateCount === 0) return + if (!distributionSupported || !pkgManager || updateCount === 0) return const terminal = Quickshell.env("TERMINAL") || "xterm" - const updateCommand = `${aurHelper} -Syu && echo "Updates complete! Press Enter to close..." && read` + const updateCommand = `${pkgManager} -Syu && echo "Updates complete! Press Enter to close..." && read` updater.command = [terminal, "-e", "sh", "-c", updateCommand] updater.running = true @@ -105,7 +130,7 @@ Singleton { Timer { interval: 30 * 60 * 1000 repeat: true - running: helperAvailable + running: distributionSupported && pkgManager onTriggered: checkForUpdates() } } \ No newline at end of file diff --git a/shell.qml b/shell.qml index 1759dcd5..8285a23e 100644 --- a/shell.qml +++ b/shell.qml @@ -274,12 +274,12 @@ ShellRoot { } LazyLoader { - id: archUpdaterLoader + id: systemUpdateLoader active: false - ArchUpdaterPopout { - id: archUpdaterPopout + SystemUpdatePopout { + id: systemUpdatePopout } }