// 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 // Save and Discard for a settings page that edits a draft: its fields change // the draft, and nothing reaches the file until Save. Sits in the Page header // through Page.actions, the one place every settings page commits from. note // says what is wrong when Save is held back; the labels follow what the page // does (Apply and Reset for a staged wallpaper or cursor, Save + Restart for // a daemon that rereads only at start); busy shows while a save runs. // // The outcome of a save goes to the window's snackbar (Snack.qml), where it // is shown in full: notice is what a finished save says ("saved"), in // noticeColor, fading by itself; error is a save refused or failed, in red, // staying until dismissed. Only the draft's state stays here, beside the // buttons: "unsaved changes", or what is wrong when Save is held back. Row { id: bar property bool dirty: false property bool valid: true property string note: "" property string notice: "" property color noticeColor: Theme.green property string error: "" property string saveText: "Save" property string discardText: "Discard" property bool busy: false signal save signal discard spacing: 8 onNoticeChanged: if (bar.notice !== "") Snack.show(bar.notice, bar.noticeColor, false) onErrorChanged: if (bar.error !== "") Snack.error(bar.error) Text { anchors.verticalCenter: parent.verticalCenter visible: bar.dirty // ponytail: a long note elides; the header has one line. width: Math.min(implicitWidth, 420) elide: Text.ElideRight text: !bar.valid ? (bar.note || "fix the fields marked red") : "unsaved changes" color: bar.valid ? Theme.yellow : Theme.red font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } } Button { text: bar.discardText enabled: bar.dirty && !bar.busy onClicked: bar.discard() } Button { text: bar.busy ? bar.saveText + "…" : bar.saveText enabled: bar.dirty && bar.valid && !bar.busy onClicked: bar.save() } }