diff options
Diffstat (limited to 'desktop/modules')
| -rw-r--r-- | desktop/modules/updates/UpdatesPage.qml | 136 |
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 { |
