mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 07:52:50 -05:00
Add an ArchUpdater widget (#201)
This commit is contained in:
353
Modules/ArchUpdaterPopout.qml
Normal file
353
Modules/ArchUpdaterPopout.qml
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
DankPopout {
|
||||||
|
id: archUpdaterPopout
|
||||||
|
|
||||||
|
property var parentWidget: null
|
||||||
|
property string triggerSection: "right"
|
||||||
|
property var triggerScreen: null
|
||||||
|
|
||||||
|
function setTriggerPosition(x, y, width, section, screen) {
|
||||||
|
triggerX = x;
|
||||||
|
triggerY = y;
|
||||||
|
triggerWidth = width;
|
||||||
|
triggerSection = section;
|
||||||
|
triggerScreen = screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
popupWidth: 400
|
||||||
|
popupHeight: 500
|
||||||
|
triggerX: Screen.width - 600 - Theme.spacingL
|
||||||
|
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.spacingXS
|
||||||
|
triggerWidth: 55
|
||||||
|
positioning: "center"
|
||||||
|
screen: triggerScreen
|
||||||
|
visible: shouldBeVisible
|
||||||
|
shouldBeVisible: false
|
||||||
|
|
||||||
|
onShouldBeVisibleChanged: {
|
||||||
|
if (shouldBeVisible) {
|
||||||
|
if (ArchUpdaterService.updateCount === 0 && !ArchUpdaterService.isChecking) {
|
||||||
|
ArchUpdaterService.checkForUpdates()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content: Component {
|
||||||
|
Rectangle {
|
||||||
|
id: updaterPanel
|
||||||
|
|
||||||
|
color: Theme.popupBackground()
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
antialiasing: true
|
||||||
|
smooth: true
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: [{
|
||||||
|
"margin": -3,
|
||||||
|
"color": Qt.rgba(0, 0, 0, 0.05),
|
||||||
|
"z": -3
|
||||||
|
}, {
|
||||||
|
"margin": -2,
|
||||||
|
"color": Qt.rgba(0, 0, 0, 0.08),
|
||||||
|
"z": -2
|
||||||
|
}, {
|
||||||
|
"margin": 0,
|
||||||
|
"color": Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12),
|
||||||
|
"z": -1
|
||||||
|
}]
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: modelData.margin
|
||||||
|
color: "transparent"
|
||||||
|
radius: parent.radius + Math.abs(modelData.margin)
|
||||||
|
border.color: modelData.color
|
||||||
|
border.width: 1
|
||||||
|
z: modelData.z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Theme.spacingL * 2
|
||||||
|
height: parent.height - Theme.spacingL * 2
|
||||||
|
x: Theme.spacingL
|
||||||
|
y: Theme.spacingL
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: 40
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "System Updates"
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: {
|
||||||
|
if (ArchUpdaterService.hasError) return Theme.error;
|
||||||
|
return Theme.surfaceText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: checkForUpdatesButton
|
||||||
|
buttonSize: 28
|
||||||
|
iconName: "refresh"
|
||||||
|
iconSize: 18
|
||||||
|
z: 15
|
||||||
|
iconColor: Theme.surfaceText
|
||||||
|
enabled: !ArchUpdaterService.isChecking
|
||||||
|
opacity: enabled ? 1.0 : 0.5
|
||||||
|
onClicked: {
|
||||||
|
ArchUpdaterService.checkForUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
|
RotationAnimation {
|
||||||
|
target: checkForUpdatesButton
|
||||||
|
property: "rotation"
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 1000
|
||||||
|
running: ArchUpdaterService.isChecking
|
||||||
|
loops: Animation.Infinite
|
||||||
|
|
||||||
|
onRunningChanged: {
|
||||||
|
if (!running) {
|
||||||
|
checkForUpdatesButton.rotation = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: {
|
||||||
|
let usedHeight = 40 + Theme.spacingL
|
||||||
|
usedHeight += 48 + Theme.spacingL
|
||||||
|
return parent.height - usedHeight
|
||||||
|
}
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
anchors.rightMargin: 0
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: statusText
|
||||||
|
width: parent.width
|
||||||
|
text: {
|
||||||
|
if (ArchUpdaterService.hasError) {
|
||||||
|
return "Failed to check for updates:\n" + ArchUpdaterService.errorMessage;
|
||||||
|
}
|
||||||
|
if (!ArchUpdaterService.helperAvailable) {
|
||||||
|
return "No AUR helper found. Please install 'paru' or 'yay' to check for updates.";
|
||||||
|
}
|
||||||
|
if (ArchUpdaterService.isChecking) {
|
||||||
|
return "Checking for updates...";
|
||||||
|
}
|
||||||
|
if (ArchUpdaterService.updateCount === 0) {
|
||||||
|
return "Your system is up to date!";
|
||||||
|
}
|
||||||
|
return `Found ${ArchUpdaterService.updateCount} packages to update:`;
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: {
|
||||||
|
if (ArchUpdaterService.hasError) return Theme.errorText;
|
||||||
|
return Theme.surfaceText;
|
||||||
|
}
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
visible: ArchUpdaterService.updateCount === 0 || ArchUpdaterService.hasError || ArchUpdaterService.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
|
||||||
|
clip: true
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
model: ArchUpdaterService.availableUpdates
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: ListView.view.width - Theme.spacingM
|
||||||
|
height: 48
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: packageMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent"
|
||||||
|
border.color: Theme.outlineLight
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width - 24 - Theme.spacingM
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: modelData.name || ""
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: `${modelData.currentVersion} → ${modelData.newVersion}`
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation { duration: Theme.shortDuration }
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: packageMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
height: 48
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: (parent.width - Theme.spacingM) / 2
|
||||||
|
height: parent.height
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: updateMouseArea.containsMouse ? Theme.primaryHover : Theme.secondaryHover
|
||||||
|
opacity: ArchUpdaterService.updateCount > 0 ? 1.0 : 0.5
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation { duration: Theme.shortDuration }
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "system_update_alt"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Update All"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: updateMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: ArchUpdaterService.updateCount > 0
|
||||||
|
onClicked: {
|
||||||
|
ArchUpdaterService.runUpdates()
|
||||||
|
archUpdaterPopout.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: (parent.width - Theme.spacingM) / 2
|
||||||
|
height: parent.height
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: closeMouseArea.containsMouse ? Theme.errorPressed : Theme.secondaryHover
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation { duration: Theme.shortDuration }
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "close"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Close"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: closeMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
archUpdaterPopout.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -163,6 +163,12 @@ Item {
|
|||||||
"description": "Quick access to color picker",
|
"description": "Quick access to color picker",
|
||||||
"icon": "palette",
|
"icon": "palette",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
|
}, {
|
||||||
|
"id": "archUpdater",
|
||||||
|
"text": "Arch Updater",
|
||||||
|
"description": "Check for updates in Arch-based systems",
|
||||||
|
"icon": "update",
|
||||||
|
"enabled": true
|
||||||
}]
|
}]
|
||||||
property var defaultLeftWidgets: [{
|
property var defaultLeftWidgets: [{
|
||||||
"id": "launcherButton",
|
"id": "launcherButton",
|
||||||
|
|||||||
110
Modules/TopBar/ArchUpdater.qml
Normal file
110
Modules/TopBar/ArchUpdater.qml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool isActive: false
|
||||||
|
property string section: "right"
|
||||||
|
property var popupTarget: null
|
||||||
|
property var parentScreen: null
|
||||||
|
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
|
||||||
|
|
||||||
|
signal clicked()
|
||||||
|
|
||||||
|
width: updaterIcon.width + horizontalPadding * 2
|
||||||
|
height: widgetHeight
|
||||||
|
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
|
color: {
|
||||||
|
if (SettingsData.topBarNoBackground) {
|
||||||
|
return "transparent";
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseColor = updaterArea.containsMouse || root.isActive ? Theme.primaryPressed : Theme.secondaryHover;
|
||||||
|
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: updaterIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
id: statusIcon
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
name: {
|
||||||
|
if (isChecking) return "refresh";
|
||||||
|
if (ArchUpdaterService.hasError) return "error";
|
||||||
|
if (hasUpdates) return "system_update_alt";
|
||||||
|
return "check_circle";
|
||||||
|
}
|
||||||
|
size: Theme.iconSize - 6
|
||||||
|
color: {
|
||||||
|
if (ArchUpdaterService.hasError) return Theme.error;
|
||||||
|
if (hasUpdates) return Theme.primary;
|
||||||
|
return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText);
|
||||||
|
}
|
||||||
|
|
||||||
|
RotationAnimation {
|
||||||
|
id: rotationAnimation
|
||||||
|
target: statusIcon
|
||||||
|
property: "rotation"
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 1000
|
||||||
|
running: isChecking
|
||||||
|
loops: Animation.Infinite
|
||||||
|
|
||||||
|
onRunningChanged: {
|
||||||
|
if (!running) {
|
||||||
|
statusIcon.rotation = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: countText
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: ArchUpdaterService.updateCount.toString()
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
visible: hasUpdates && !isChecking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: updaterArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onPressed: {
|
||||||
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
|
const globalPos = mapToGlobal(0, 0);
|
||||||
|
const currentScreen = parentScreen || Screen;
|
||||||
|
const screenX = currentScreen.x || 0;
|
||||||
|
const relativeX = globalPos.x - screenX;
|
||||||
|
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
|
||||||
|
}
|
||||||
|
root.clicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -183,6 +183,9 @@ PanelWindow {
|
|||||||
}, {
|
}, {
|
||||||
"loader": clipboardHistoryModalPopup,
|
"loader": clipboardHistoryModalPopup,
|
||||||
"prop": "visible"
|
"prop": "visible"
|
||||||
|
}, {
|
||||||
|
"loader": archUpdaterLoader,
|
||||||
|
"prop": "shouldBeVisible"
|
||||||
}]
|
}]
|
||||||
return notepadInstanceVisible || loaders.some(item => {
|
return notepadInstanceVisible || loaders.some(item => {
|
||||||
if (item.loader) {
|
if (item.loader) {
|
||||||
@@ -373,7 +376,8 @@ PanelWindow {
|
|||||||
"keyboard_layout_name": keyboardLayoutNameComponent,
|
"keyboard_layout_name": keyboardLayoutNameComponent,
|
||||||
"vpn": vpnComponent,
|
"vpn": vpnComponent,
|
||||||
"notepadButton": notepadButtonComponent,
|
"notepadButton": notepadButtonComponent,
|
||||||
"colorPicker": colorPickerComponent
|
"colorPicker": colorPickerComponent,
|
||||||
|
"archUpdater": archUpdaterComponent
|
||||||
})
|
})
|
||||||
|
|
||||||
function getWidgetComponent(widgetId) {
|
function getWidgetComponent(widgetId) {
|
||||||
@@ -1016,6 +1020,26 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: archUpdaterComponent
|
||||||
|
|
||||||
|
ArchUpdater {
|
||||||
|
isActive: archUpdaterLoader.item ? archUpdaterLoader.item.shouldBeVisible : false
|
||||||
|
widgetHeight: root.widgetHeight
|
||||||
|
barHeight: root.effectiveBarHeight
|
||||||
|
section: topBarContent.getWidgetSection(parent) || "right"
|
||||||
|
popupTarget: {
|
||||||
|
archUpdaterLoader.active = true
|
||||||
|
return archUpdaterLoader.item
|
||||||
|
}
|
||||||
|
parentScreen: root.screen
|
||||||
|
onClicked: {
|
||||||
|
archUpdaterLoader.active = true
|
||||||
|
archUpdaterLoader.item?.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
111
Services/ArchUpdaterService.qml
Normal file
111
Services/ArchUpdaterService.qml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var availableUpdates: []
|
||||||
|
property bool isChecking: false
|
||||||
|
property bool hasError: false
|
||||||
|
property string errorMessage: ""
|
||||||
|
property string aurHelper: ""
|
||||||
|
|
||||||
|
readonly property int updateCount: availableUpdates.length
|
||||||
|
readonly property bool helperAvailable: aurHelper !== ""
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: helperDetection
|
||||||
|
command: ["sh", "-c", "which paru || which yay"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
const helperPath = stdout.text.trim()
|
||||||
|
aurHelper = helperPath.split('/').pop()
|
||||||
|
checkForUpdates()
|
||||||
|
} else {
|
||||||
|
console.warn("ArchUpdater: No AUR helper found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: updateChecker
|
||||||
|
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
isChecking = false
|
||||||
|
if (exitCode === 0 || exitCode === 1) {
|
||||||
|
// Exit code 0 = updates available, 1 = no updates
|
||||||
|
parseUpdates(stdout.text)
|
||||||
|
hasError = false
|
||||||
|
errorMessage = ""
|
||||||
|
} else {
|
||||||
|
hasError = true
|
||||||
|
errorMessage = "Failed to check for updates"
|
||||||
|
console.warn("ArchUpdater: Update check failed with code:", exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: updater
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
checkForUpdates()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForUpdates() {
|
||||||
|
if (!helperAvailable || isChecking) return
|
||||||
|
|
||||||
|
isChecking = true
|
||||||
|
hasError = false
|
||||||
|
updateChecker.command = [aurHelper, "-Qu"]
|
||||||
|
updateChecker.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseUpdates(output) {
|
||||||
|
const lines = output.trim().split('\n').filter(line => line.trim())
|
||||||
|
const updates = []
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const match = line.match(/^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/)
|
||||||
|
if (match) {
|
||||||
|
updates.push({
|
||||||
|
name: match[1],
|
||||||
|
currentVersion: match[2],
|
||||||
|
newVersion: match[3],
|
||||||
|
description: `${match[1]} ${match[2]} → ${match[3]}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
availableUpdates = updates
|
||||||
|
}
|
||||||
|
|
||||||
|
function runUpdates() {
|
||||||
|
if (!helperAvailable || updateCount === 0) return
|
||||||
|
|
||||||
|
const terminal = Quickshell.env("TERMINAL") || "xterm"
|
||||||
|
const updateCommand = `${aurHelper} -Syu && echo "Updates complete! Press Enter to close..." && read`
|
||||||
|
|
||||||
|
updater.command = [terminal, "-e", "sh", "-c", updateCommand]
|
||||||
|
updater.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 30 * 60 * 1000
|
||||||
|
repeat: true
|
||||||
|
running: helperAvailable
|
||||||
|
onTriggered: checkForUpdates()
|
||||||
|
}
|
||||||
|
}
|
||||||
10
shell.qml
10
shell.qml
@@ -273,6 +273,16 @@ ShellRoot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: archUpdaterLoader
|
||||||
|
|
||||||
|
active: false
|
||||||
|
|
||||||
|
ArchUpdaterPopout {
|
||||||
|
id: archUpdaterPopout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
id: notepadSlideoutVariants
|
id: notepadSlideoutVariants
|
||||||
model: SettingsData.getFilteredScreens("notepad")
|
model: SettingsData.getFilteredScreens("notepad")
|
||||||
|
|||||||
Reference in New Issue
Block a user