aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/updates/UpdatesPage.qml
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-15 12:33:18 +0200
committerDanilo M. <danix@danix.xyz>2026-10-15 12:33:18 +0200
commitd41ead57885d5008922fdada2d702dc6488e09d6 (patch)
tree4bdbdf54d3b752fd29c9223555500216af10a8e9 /desktop/modules/updates/UpdatesPage.qml
parent36b272482a57f3edd14782171d5979756d8fde9c (diff)
downloadquickshell-d41ead57885d5008922fdada2d702dc6488e09d6.tar.gz
quickshell-d41ead57885d5008922fdada2d702dc6488e09d6.zip
feat(updates): a page that reads at a glance
The first cut was small type in one long list: 471 Slackware upgrades pushed everything below them out of sight, and the repo tag, the versions and the name ran together across the row. Type is 2px larger and rows taller. A section over ten rows starts folded behind a clickable heading with its count. The version being moved to is bright, the one being left dim, both in Inconsolata so digits line up. Every other row is shaded to carry the eye across, and the repo is a pill in one colour per repo, never red, green, yellow or the accent, which mean something elsewhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules/updates/UpdatesPage.qml')
-rw-r--r--desktop/modules/updates/UpdatesPage.qml136
1 files changed, 106 insertions, 30 deletions
diff --git a/desktop/modules/updates/UpdatesPage.qml b/desktop/modules/updates/UpdatesPage.qml
index 967b0e0..2cce13c 100644
--- a/desktop/modules/updates/UpdatesPage.qml
+++ b/desktop/modules/updates/UpdatesPage.qml
@@ -23,23 +23,30 @@ Column {
spacing: 16
+ // Rows carry `from` and `to` apart so the target can stand out; a row
+ // with a single value (new, removed) leaves `from` empty.
function tracked(list) {
- return list.map(r => ({ name: r.name, repo: r.repo, ver: r.from + " → " + r.to }));
+ return list.map(r => ({ name: r.name, repo: r.repo, from: r.from, to: r.to }));
}
readonly property var sections: !d ? [] : [
{ title: "Slackware upgrades", err: d.errors.mirror || "",
- rows: d.slackware.upgrade.map(r => ({ name: r.name, repo: "", ver: r.from + " → " + r.to })) },
+ rows: d.slackware.upgrade.map(r => ({ name: r.name, repo: "", from: r.from, to: r.to })) },
{ title: "New in Slackware", err: "",
- rows: d.slackware.new.map(r => ({ name: r.name, repo: "", ver: r.version })) },
+ rows: d.slackware.new.map(r => ({ name: r.name, repo: "", from: "", to: r.version })) },
{ title: "Removed from Slackware", err: "",
- rows: d.slackware.removed.map(r => ({ name: r.name, repo: "", ver: "removed " + r.date })) },
+ rows: d.slackware.removed.map(r => ({ name: r.name, repo: "", from: "", to: "removed " + r.date })) },
{ title: "Upgrade here", err: d.errors.repo || "", rows: tracked(d.upgrade) },
{ title: "Awaiting build", err: "", rows: tracked(d.build) },
{ title: "Upstream newer", err: d.errors.nvchecker || "", rows: tracked(d.upstream) },
{ title: "App updates", err: "", rows: tracked(d.apps) },
]
+ function repoColor(r) {
+ return { "personal": Theme.blue, "my-sbo": Theme.mauve, "pentesting": Theme.peach,
+ "SBo": Theme.teal }[r] || Theme.overlay;
+ }
+
function ago(t) {
const m = Math.round((Date.now() / 1000 - t) / 60);
return m < 1 ? "just now" : m < 60 ? m + " min ago" : Math.round(m / 60) + " h ago";
@@ -50,61 +57,130 @@ Column {
&& page.d.upstream.length === 0 && page.d.apps.length === 0
text: "Up to date"
color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize }
}
Repeater {
model: page.sections
Column {
+ id: section
required property var modelData
width: page.width
- spacing: 4
+ spacing: 2
visible: modelData.rows.length > 0 || modelData.err !== ""
- Text {
- text: modelData.title + (modelData.rows.length ? " " + modelData.rows.length : "")
- color: Theme.text
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1; bold: true }
+ // A long section starts folded, so 471 Slackware upgrades do not
+ // bury everything below them. A refresh rebuilds the delegates
+ // and folds it again.
+ property bool open: modelData.rows.length <= 10
+
+ Item {
+ width: page.width
+ height: heading.implicitHeight + 6
+
+ Row {
+ id: heading
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: 8
+
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ width: 14
+ text: section.open ? "\uf078" : "\uf054"
+ color: Theme.subtext
+ font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 3 }
+ }
+ Text {
+ text: section.modelData.title
+ color: Theme.text
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize + 1; bold: true }
+ }
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ visible: section.modelData.rows.length > 0
+ text: section.modelData.rows.length
+ color: Theme.subtext
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1 }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: section.open = !section.open
+ }
}
Text {
- visible: modelData.err !== ""
- text: modelData.err
+ visible: section.modelData.err !== ""
+ text: section.modelData.err
color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3; italic: true }
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1; italic: true }
}
Repeater {
- model: modelData.rows
+ model: section.open ? section.modelData.rows : []
- Item {
+ Rectangle {
required property var modelData
+ required property int index
width: page.width
- height: 22
+ height: 26
+ radius: 4
+ // Every other row shaded, to carry the eye from the name
+ // across to its version.
+ color: index % 2 ? Qt.alpha(Theme.surface, 0.45) : "transparent"
Text {
- anchors { left: parent.left; right: repo.left; rightMargin: 8; verticalCenter: parent.verticalCenter }
+ anchors { left: parent.left; leftMargin: 8; right: repo.left; rightMargin: 8; verticalCenter: parent.verticalCenter }
elide: Text.ElideRight
textFormat: Text.PlainText
text: modelData.name
color: Theme.text
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1 }
}
- Text {
+ // The repo as a pill, one colour per repo. Never red, green,
+ // yellow or the accent: those carry meaning elsewhere.
+ Rectangle {
id: repo
- anchors { right: ver.left; rightMargin: 12; verticalCenter: parent.verticalCenter }
- text: modelData.repo
- color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
+ readonly property color tint: page.repoColor(modelData.repo)
+ anchors { right: ver.left; rightMargin: 16; verticalCenter: parent.verticalCenter }
+ visible: modelData.repo !== ""
+ width: visible ? repoText.implicitWidth + 14 : 0
+ height: repoText.implicitHeight + 4
+ radius: height / 2
+ color: Qt.alpha(tint, 0.18)
+ border { width: 1; color: Qt.alpha(tint, 0.5) }
+
+ Text {
+ id: repoText
+ anchors.centerIn: parent
+ text: modelData.repo
+ color: repo.tint
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
+ }
}
- Text {
+ // Monospace so digits line up down the column; the
+ // version being moved to is the bright one.
+ Row {
id: ver
- anchors { right: parent.right; verticalCenter: parent.verticalCenter }
- textFormat: Text.PlainText
- text: modelData.ver
- color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
+ anchors { right: parent.right; rightMargin: 8; verticalCenter: parent.verticalCenter }
+ spacing: 6
+
+ Text {
+ visible: modelData.from !== ""
+ textFormat: Text.PlainText
+ text: modelData.from + " →"
+ color: Theme.subtext
+ font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 1 }
+ }
+ Text {
+ textFormat: Text.PlainText
+ text: modelData.to
+ color: Theme.text
+ font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 1 }
+ }
}
}
}
@@ -119,7 +195,7 @@ Column {
text: page.up.checking ? "checking…"
: page.d && page.d.checked ? "checked " + page.ago(page.d.checked) : ""
color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1 }
}
Button {