feat(ui): Review & apply greyed out while nothing would change; the Done screen shows why a run stopped

This commit is contained in:
theupriser committed 2026-09-27 17:11:46 +02:00
1 parent 66dd04799b
commit 50b50cb726
4 files changed
+28 -7

No files matched your search

+10 -2
View File
@@ -18,6 +18,10 @@ Item {
property var steps: ({}) // id -> "wait"|"run"|"ok"|"fail" property var steps: ({}) // id -> "wait"|"run"|"ok"|"fail"
property var failed: [] property var failed: []
property bool restartNeeded: false property bool restartNeeded: false
// Review & apply only when something would change; "Re-apply what's on"
// is for when nothing did.
readonly property bool canApply: computePlan().length > 0
onCanApplyChanged: if (!canApply && sel === rows.length) sel = Math.max(0, rows.length - 1)
property string runError: "" property string runError: ""
property bool wrongPassword: false property bool wrongPassword: false
property bool typing: false // a text field has the keys property bool typing: false // a text field has the keys
@@ -93,7 +97,10 @@ Item {
if (want.gaming && boot !== bootNow) p.push({ id: "boot", action: boot === "desktop" ? "desktop" : "gaming" }); if (want.gaming && boot !== bootNow) p.push({ id: "boot", action: boot === "desktop" ? "desktop" : "gaming" });
return p; return p;
} }
function goReview(again) { reapply = again; plan = computePlan(); screen = "review"; } function goReview(again) {
if (!again && !canApply) return;
reapply = again; plan = computePlan(); screen = "review";
}
function wantedIds() { function wantedIds() {
var ids = []; var ids = [];
for (var i = 0; i < items.length; i++) for (var i = 0; i < items.length; i++)
@@ -195,7 +202,8 @@ Item {
if (screen === "menu") { if (screen === "menu") {
if (biosChecking) return; if (biosChecking) return;
if (a === "up") sel = Math.max(0, sel - 1); if (a === "up") sel = Math.max(0, sel - 1);
else if (a === "down") sel = Math.min(rows.length, sel + 1); // The greyed-out Apply button can't be selected.
else if (a === "down") sel = Math.min(canApply ? rows.length : rows.length - 1, sel + 1);
else if (a === "accept") { else if (a === "accept") {
if (sel === rows.length) { goReview(false); return; } if (sel === rows.length) { goReview(false); return; }
var r = rows[sel]; var r = rows[sel];
+4 -2
View File
@@ -10,11 +10,13 @@ Rectangle {
signal clicked signal clicked
height: 48; radius: 12; width: row.implicitWidth + 36 height: 48; radius: 12; width: row.implicitWidth + 36
color: primary ? Theme.accent : Theme.button color: primary ? Theme.accent : Theme.button
border.width: focusRing ? 2 : 0; border.color: Theme.textHi border.width: focusRing && enabled ? 2 : 0; border.color: Theme.textHi
// Greyed out while there's nothing to do.
opacity: enabled ? 1 : 0.4
Row { id: row; anchors.centerIn: parent; spacing: 10 Row { id: row; anchors.centerIn: parent; spacing: 10
Glyph { k: btn.k; visible: btn.k !== ""; dark: btn.primary; anchors.verticalCenter: parent.verticalCenter } Glyph { k: btn.k; visible: btn.k !== ""; dark: btn.primary; anchors.verticalCenter: parent.verticalCenter }
Text { text: btn.text; color: btn.primary ? Theme.ink : Theme.text; font.family: Theme.body; font.pixelSize: 15; font.weight: Font.DemiBold Text { text: btn.text; color: btn.primary ? Theme.ink : Theme.text; font.family: Theme.body; font.pixelSize: 15; font.weight: Font.DemiBold
anchors.verticalCenter: parent.verticalCenter } anchors.verticalCenter: parent.verticalCenter }
} }
MouseArea { anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: btn.clicked() } MouseArea { anchors.fill: parent; enabled: btn.enabled; cursorShape: Qt.PointingHandCursor; onClicked: btn.clicked() }
} }
+12 -2
View File
@@ -1,5 +1,8 @@
// The result of a run: all done, a problem, or nothing changed. // The result of a run: all done, a problem, or nothing changed. With a
// problem, the run's output is shown below it (a BIOS check has no progress
// screen, so this is the only place to read why it stopped).
import QtQuick import QtQuick
import QtQuick.Controls.Basic
Item { Item {
required property AppState app required property AppState app
@@ -20,7 +23,14 @@ Item {
Text { width: parent.width; horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap; color: Theme.soft; font.family: Theme.body; font.pixelSize: 17; text: message } Text { width: parent.width; horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap; color: Theme.soft; font.family: Theme.body; font.pixelSize: 17; text: message }
Rectangle { visible: app.failed.length > 0; anchors.horizontalCenter: parent.horizontalCenter; width: ft.implicitWidth + 32; height: 44; radius: 12; color: Theme.warnBg Rectangle { visible: app.failed.length > 0; anchors.horizontalCenter: parent.horizontalCenter; width: ft.implicitWidth + 32; height: 44; radius: 12; color: Theme.warnBg
Text { id: ft; anchors.centerIn: parent; color: "#f2c27a"; font.family: Theme.body; font.pixelSize: 14 Text { id: ft; anchors.centerIn: parent; color: "#f2c27a"; font.family: Theme.body; font.pixelSize: 14
text: "Had a problem: " + app.failed.map(function (id) { return Texts.label(id); }).join(", ") + ". See the details." } } text: "Had a problem: " + app.failed.map(function (id) { return Texts.label(id); }).join(", ") + (app.log.count ? ". Details below." : ".") } }
Rectangle { visible: app.failed.length > 0 && app.log.count > 0; width: parent.width; height: 190; radius: 14; color: Theme.card
ListView { id: details; anchors.fill: parent; anchors.margins: 16; clip: true; model: app.log
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
// The end is where it stopped.
onCountChanged: positionViewAtEnd()
onVisibleChanged: if (visible) positionViewAtEnd()
delegate: Text { required property string line; width: details.width - 12; text: line; color: "#aab5c4"; font.family: Theme.mono; font.pixelSize: 13; wrapMode: Text.WrapAnywhere } } }
Row { anchors.horizontalCenter: parent.horizontalCenter; spacing: 14; topPadding: 8 Row { anchors.horizontalCenter: parent.horizontalCenter; spacing: 14; topPadding: 8
Btn { k: Input.g.back; text: "Back to the menu"; height: 52; onClicked: app.act("back") } Btn { k: Input.g.back; text: "Back to the menu"; height: 52; onClicked: app.act("back") }
Btn { visible: app.restartNeeded; k: Input.g.ok; text: "Restart now"; primary: true; height: 52; onClicked: app.backend.restart() } } Btn { visible: app.restartNeeded; k: Input.g.ok; text: "Restart now"; primary: true; height: 52; onClicked: app.backend.restart() } }
+2 -1
View File
@@ -70,7 +70,8 @@ Item {
Text { readonly property int n: app.computePlan().length Text { readonly property int n: app.computePlan().length
text: n === 0 ? "Everything is the way you want it" : n + (n === 1 ? " change" : " changes") text: n === 0 ? "Everything is the way you want it" : n + (n === 1 ? " change" : " changes")
color: Theme.faint; font.family: Theme.body; font.pixelSize: 14; anchors.verticalCenter: parent.verticalCenter } color: Theme.faint; font.family: Theme.body; font.pixelSize: 14; anchors.verticalCenter: parent.verticalCenter }
Btn { k: screen.g.apply; text: "Review & apply"; primary: true; focusRing: app.sel === app.rows.length; height: 44; onClicked: app.goReview(false) } Btn { k: screen.g.apply; text: "Review & apply"; primary: true; enabled: app.canApply
focusRing: app.sel === app.rows.length; height: 44; onClicked: app.goReview(false) }
} }
} }
} }