From 3d045076d49ee7cc074f670806a823099ea9fb09 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 7 Nov 2026 12:38:18 +0100 Subject: settings: one snackbar for every page's messages Save, apply and upload results went to the page header, one line capped at 420px and cut with an ellipsis. They now go to a snackbar at the foot of the settings window, wrapped in full: green fades after 6s, yellow and red stay until dismissed or replaced, and changing page clears it. Snack.qml is the singleton pages call (ok, wait, error); Snackbar.qml draws it once in Settings.qml. SaveBar forwards its notice and error, so the 24 pages using it change nothing; the header keeps only the draft's state. The boot logo page calls Snack directly. Co-Authored-By: Claude Opus 5.5 --- desktop/Snackbar.qml | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 desktop/Snackbar.qml (limited to 'desktop/Snackbar.qml') diff --git a/desktop/Snackbar.qml b/desktop/Snackbar.qml new file mode 100644 index 0000000..467ac73 --- /dev/null +++ b/desktop/Snackbar.qml @@ -0,0 +1,71 @@ +// Copyright (C) 2026 Danilo M. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +import QtQuick + +// Snack's message at the foot of the settings window: wrapped in full, a +// stripe in its colour, a cross to dismiss. Place it once per window. +Rectangle { + id: bar + + readonly property bool shown: Snack.text !== "" + + implicitHeight: Math.max(msg.implicitHeight, 20) + 20 + radius: 10 + color: Theme.surface + border.width: 1 + border.color: Qt.alpha(Snack.color, 0.6) + opacity: shown ? 1 : 0 + visible: opacity > 0 + Behavior on opacity { NumberAnimation { duration: 160 } } + + Timer { + id: fade + interval: 6000 + onTriggered: Snack.clear() + } + Connections { + target: Snack + function onSerialChanged() { if (Snack.sticky) fade.stop(); else fade.restart(); } + } + + Rectangle { + anchors { left: parent.left; top: parent.top; bottom: parent.bottom; margins: 6 } + width: 4 + radius: 2 + color: Snack.color + } + + Text { + id: msg + anchors { left: parent.left; leftMargin: 20; right: close.left; rightMargin: 12; verticalCenter: parent.verticalCenter } + wrapMode: Text.Wrap + textFormat: Text.PlainText + text: Snack.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + color: Theme.text + } + + Text { + id: close + anchors { right: parent.right; rightMargin: 12; verticalCenter: parent.verticalCenter } + text: "" // nf-fa-xmark + font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 2 } + color: hit.containsMouse ? Theme.text : Theme.subtext + MouseArea { + id: hit + anchors { fill: parent; margins: -6 } + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: Snack.clear() + } + } +} -- cgit v1.2.3