mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-30 17:42:06 -04:00
system updater: complete overhaul
Move system update flow to GO, with a CLI (convenient AIO tool) and server integration. All lifecycle, scheduling, execution occurs on backend side. Run some backends via pkexec, some via terminal like paru/yay. Incorporate flatpak as an option to update. Add terminal override setting in GUI, in addition to $TERMINAL env variable. fixes #2307 fixes #822 fixes #1102 fixes #1812 fixes #1087 fixes #1743
This commit is contained in:
@@ -189,10 +189,10 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!SystemUpdateService.shellVersion && !DMSService.cliVersion)
|
||||
if (!ShellVersionService.shellVersion && !DMSService.cliVersion)
|
||||
return "dms";
|
||||
|
||||
let version = SystemUpdateService.shellVersion || "";
|
||||
let version = ShellVersionService.shellVersion || "";
|
||||
let cliVersion = DMSService.cliVersion || "";
|
||||
|
||||
// Debian/Ubuntu/OpenSUSE git format: 1.0.3+git2264.c5c5ce84
|
||||
@@ -218,7 +218,7 @@ Item {
|
||||
|
||||
let baseVersion = extractBaseVersion(cliVersion);
|
||||
if (!baseVersion)
|
||||
baseVersion = extractBaseVersion(SystemUpdateService.semverVersion);
|
||||
baseVersion = extractBaseVersion(ShellVersionService.semverVersion);
|
||||
if (baseVersion) {
|
||||
return `dms (git) v${baseVersion}-${match[1]}`;
|
||||
}
|
||||
@@ -253,8 +253,8 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: SystemUpdateService.shellCodename.length > 0
|
||||
text: `"${SystemUpdateService.shellCodename}"`
|
||||
visible: ShellVersionService.shellCodename.length > 0
|
||||
text: `"${ShellVersionService.shellCodename}"`
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.italic: true
|
||||
color: Theme.surfaceVariantText
|
||||
|
||||
@@ -325,6 +325,8 @@ Item {
|
||||
placeholderText: I18n.tr("Enter launch prefix (e.g., 'uwsm-app')")
|
||||
onTextEdited: SettingsData.set("launchPrefix", text)
|
||||
}
|
||||
|
||||
TerminalPickerRow {}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
|
||||
@@ -1,11 +1,53 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var intervalOptions: [
|
||||
{
|
||||
label: I18n.tr("Every 15 minutes"),
|
||||
seconds: 900
|
||||
},
|
||||
{
|
||||
label: I18n.tr("Every 30 minutes"),
|
||||
seconds: 1800
|
||||
},
|
||||
{
|
||||
label: I18n.tr("Every hour"),
|
||||
seconds: 3600
|
||||
},
|
||||
{
|
||||
label: I18n.tr("Every 4 hours"),
|
||||
seconds: 14400
|
||||
},
|
||||
{
|
||||
label: I18n.tr("Once a day"),
|
||||
seconds: 86400
|
||||
}
|
||||
]
|
||||
|
||||
function intervalLabelFor(seconds) {
|
||||
for (const opt of intervalOptions) {
|
||||
if (opt.seconds === seconds) {
|
||||
return opt.label;
|
||||
}
|
||||
}
|
||||
return intervalOptions[1].label;
|
||||
}
|
||||
|
||||
function intervalSecondsFor(label) {
|
||||
for (const opt of intervalOptions) {
|
||||
if (opt.label === label) {
|
||||
return opt.seconds;
|
||||
}
|
||||
}
|
||||
return 1800;
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
@@ -25,18 +67,60 @@ Item {
|
||||
title: I18n.tr("System Updater")
|
||||
settingKey: "systemUpdater"
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Hide Updater Widget", "When updater widget is used, then hide it if no update found")
|
||||
description: I18n.tr("When updater widget is used, then hide it if no update found")
|
||||
checked: SettingsData.updaterHideWidget
|
||||
onToggled: checked => {
|
||||
SettingsData.set("updaterHideWidget", checked);
|
||||
StyledText {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
visible: SystemUpdateService.backends.length > 0
|
||||
text: {
|
||||
const names = (SystemUpdateService.backends || []).map(b => b.displayName).join(", ");
|
||||
return I18n.tr("Detected backends: %1").arg(names);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Check interval")
|
||||
description: I18n.tr("How often the server polls for new updates.")
|
||||
options: root.intervalOptions.map(o => o.label)
|
||||
currentValue: root.intervalLabelFor(SettingsData.updaterIntervalSeconds)
|
||||
onValueChanged: label => {
|
||||
const secs = root.intervalSecondsFor(label);
|
||||
SettingsData.set("updaterIntervalSeconds", secs);
|
||||
SystemUpdateService.setInterval(secs);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Use Custom Command")
|
||||
description: I18n.tr("Use custom command for update your system")
|
||||
text: I18n.tr("Include Flatpak updates")
|
||||
description: I18n.tr("Apply Flatpak updates alongside system updates when running 'Update All'.")
|
||||
visible: (SystemUpdateService.backends || []).some(b => b.repo === "flatpak")
|
||||
checked: SettingsData.updaterIncludeFlatpak
|
||||
onToggled: checked => SettingsData.set("updaterIncludeFlatpak", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Include AUR updates")
|
||||
description: I18n.tr("Run paru/yay with AUR enabled when 'Update All' is clicked.")
|
||||
visible: (SystemUpdateService.backends || []).some(b => b.id === "paru" || b.id === "yay")
|
||||
checked: SettingsData.updaterAllowAUR
|
||||
onToggled: checked => SettingsData.set("updaterAllowAUR", checked)
|
||||
}
|
||||
|
||||
TerminalPickerRow {}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "tune"
|
||||
title: I18n.tr("Advanced")
|
||||
settingKey: "systemUpdaterAdvanced"
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Use custom command")
|
||||
description: I18n.tr("Open a terminal and run a custom command instead of the in-shell upgrade flow.")
|
||||
checked: SettingsData.updaterUseCustomCommand
|
||||
onToggled: checked => {
|
||||
if (!checked) {
|
||||
@@ -49,11 +133,32 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
visible: SettingsData.updaterUseCustomCommand
|
||||
height: warnText.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
|
||||
|
||||
StyledText {
|
||||
id: warnText
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
text: I18n.tr("Custom command and terminal params are split on whitespace; paths with spaces will break.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
height: customCommandColumn.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
visible: SettingsData.updaterUseCustomCommand
|
||||
|
||||
Column {
|
||||
id: customCommandColumn
|
||||
@@ -61,7 +166,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("System update custom command")
|
||||
text: I18n.tr("Custom update command")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -69,7 +174,7 @@ Item {
|
||||
DankTextField {
|
||||
id: updaterCustomCommand
|
||||
width: parent.width
|
||||
placeholderText: "myPkgMngr --sysupdate"
|
||||
placeholderText: "topgrade --no-retry"
|
||||
backgroundColor: Theme.surfaceContainerHighest
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
@@ -98,6 +203,7 @@ Item {
|
||||
height: terminalParamsColumn.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
visible: SettingsData.updaterUseCustomCommand
|
||||
|
||||
Column {
|
||||
id: terminalParamsColumn
|
||||
@@ -105,7 +211,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Terminal custom additional parameters")
|
||||
text: I18n.tr("Terminal additional parameters")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -113,7 +219,7 @@ Item {
|
||||
DankTextField {
|
||||
id: updaterTerminalCustomClass
|
||||
width: parent.width
|
||||
placeholderText: "-T udpClass"
|
||||
placeholderText: "-T updater"
|
||||
backgroundColor: Theme.surfaceContainerHighest
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
|
||||
31
quickshell/Modules/Settings/Widgets/TerminalPickerRow.qml
Normal file
31
quickshell/Modules/Settings/Widgets/TerminalPickerRow.qml
Normal file
@@ -0,0 +1,31 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: root
|
||||
|
||||
readonly property string autoLabel: I18n.tr("Auto")
|
||||
|
||||
text: I18n.tr("Terminal")
|
||||
settingKey: "terminalOverride"
|
||||
|
||||
options: {
|
||||
const opts = [autoLabel];
|
||||
const installed = SessionData.installedTerminals || [];
|
||||
const list = installed.length > 0 ? installed : SessionData.terminalOptions;
|
||||
for (const t of list) {
|
||||
opts.push(t);
|
||||
}
|
||||
if (SessionData.terminalOverride && !opts.includes(SessionData.terminalOverride)) {
|
||||
opts.push(SessionData.terminalOverride);
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
currentValue: SessionData.terminalOverride.length > 0 ? SessionData.terminalOverride : autoLabel
|
||||
|
||||
onValueChanged: label => {
|
||||
const next = label === autoLabel ? "" : label;
|
||||
SessionData.set("terminalOverride", next);
|
||||
}
|
||||
}
|
||||
@@ -246,7 +246,8 @@ Item {
|
||||
"text": I18n.tr("System Update"),
|
||||
"description": I18n.tr("Check for system updates"),
|
||||
"icon": "update",
|
||||
"enabled": SystemUpdateService.distributionSupported
|
||||
"enabled": SystemUpdateService.sysupdateAvailable,
|
||||
"warning": SystemUpdateService.sysupdateAvailable ? undefined : I18n.tr("Requires DMS server with sysupdate capability")
|
||||
},
|
||||
{
|
||||
"id": "powerMenuButton",
|
||||
@@ -430,7 +431,7 @@ Item {
|
||||
"id": widget.id,
|
||||
"enabled": widget.enabled
|
||||
};
|
||||
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion"];
|
||||
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion", "hideWhenIdle"];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (widget[keys[i]] !== undefined)
|
||||
result[keys[i]] = widget[keys[i]];
|
||||
@@ -579,6 +580,17 @@ Item {
|
||||
setWidgetsForSection(sectionId, widgets);
|
||||
}
|
||||
|
||||
function handleHideWhenIdleChanged(sectionId, widgetIndex, enabled) {
|
||||
var widgets = getWidgetsForSection(sectionId).slice();
|
||||
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
|
||||
return;
|
||||
}
|
||||
var newWidget = cloneWidgetData(widgets[widgetIndex]);
|
||||
newWidget.hideWhenIdle = enabled;
|
||||
widgets[widgetIndex] = newWidget;
|
||||
setWidgetsForSection(sectionId, widgets);
|
||||
}
|
||||
|
||||
function handleDiskUsageModeChanged(sectionId, widgetIndex, mode) {
|
||||
var widgets = getWidgetsForSection(sectionId).slice();
|
||||
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
|
||||
@@ -714,6 +726,8 @@ Item {
|
||||
item.barShowOverflowBadge = widget.barShowOverflowBadge;
|
||||
if (widget.trayUseInlineExpansion !== undefined)
|
||||
item.trayUseInlineExpansion = widget.trayUseInlineExpansion;
|
||||
if (widget.hideWhenIdle !== undefined)
|
||||
item.hideWhenIdle = widget.hideWhenIdle;
|
||||
}
|
||||
widgets.push(item);
|
||||
});
|
||||
@@ -1003,6 +1017,9 @@ Item {
|
||||
onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => {
|
||||
widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value);
|
||||
}
|
||||
onHideWhenIdleChanged: (sectionId, widgetIndex, enabled) => {
|
||||
widgetsTab.handleHideWhenIdleChanged(sectionId, widgetIndex, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,6 +1087,9 @@ Item {
|
||||
onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => {
|
||||
widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value);
|
||||
}
|
||||
onHideWhenIdleChanged: (sectionId, widgetIndex, enabled) => {
|
||||
widgetsTab.handleHideWhenIdleChanged(sectionId, widgetIndex, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1137,6 +1157,9 @@ Item {
|
||||
onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => {
|
||||
widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value);
|
||||
}
|
||||
onHideWhenIdleChanged: (sectionId, widgetIndex, enabled) => {
|
||||
widgetsTab.handleHideWhenIdleChanged(sectionId, widgetIndex, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ Column {
|
||||
signal showInGbChanged(string sectionId, int widgetIndex, bool enabled)
|
||||
signal diskUsageModeChanged(string sectionId, int widgetIndex, int mode)
|
||||
signal overflowSettingChanged(string sectionId, int widgetIndex, string settingName, var value)
|
||||
signal hideWhenIdleChanged(string sectionId, int widgetIndex, bool enabled)
|
||||
|
||||
function cloneWidgetData(widget) {
|
||||
var result = {
|
||||
@@ -335,6 +336,25 @@ Column {
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: hideWhenIdleButton
|
||||
buttonSize: 28
|
||||
visible: modelData.id === "systemUpdate"
|
||||
iconName: "visibility_off"
|
||||
iconSize: 16
|
||||
iconColor: (modelData.hideWhenIdle === true) ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
root.hideWhenIdleChanged(root.sectionId, index, modelData.hideWhenIdle !== true);
|
||||
}
|
||||
onEntered: {
|
||||
const tooltipText = modelData.hideWhenIdle === true ? "Hide when no updates: ON" : "Hide when no updates: OFF";
|
||||
sharedTooltip.show(tooltipText, hideWhenIdleButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: memMenuButton
|
||||
visible: modelData.id === "memUsage"
|
||||
|
||||
Reference in New Issue
Block a user