import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Window 2.15 import QtGraphicalEffects 1.15 import utils 1.0 import shared.controls 1.0 import shared.panels 1.0 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 Rectangle { id: root property bool loading: false property bool active: false property bool cancelButtonVisible: true property bool saveChangesButtonEnabled: false property bool saveForLaterButtonVisible property alias saveChangesText: saveChangesButton.text property string saveChangesTooltipText property alias saveForLaterText: saveForLaterButton.text property alias cancelChangesText: cancelChangesButton.text property alias changesDetectedText: changesDetectedTextItem.text property alias additionalComponent: additionalTextComponent readonly property string defaultChangesDetectedText: qsTr("Changes detected") readonly property string defaultSaveChangesText: qsTr("Save changes") readonly property string defaultSaveForLaterText: qsTr("Save for later") readonly property string defaultCancelChangesText: qsTr("Cancel") property Flickable flickable: null enum Type { Danger, Info } property int type: SettingsDirtyToastMessage.Type.Danger signal saveChangesClicked signal saveForLaterClicked signal resetChangesClicked function notifyDirty() { toastAlertAnimation.running = true saveChangesButton.forceActiveFocus() } implicitHeight: toastContent.implicitHeight + toastContent.anchors.topMargin + toastContent.anchors.bottomMargin implicitWidth: toastContent.implicitWidth + toastContent.anchors.leftMargin + toastContent.anchors.rightMargin opacity: active ? 1 : 0 color: Theme.palette.statusToastMessage.backgroundColor radius: 8 border.color: type === SettingsDirtyToastMessage.Type.Danger ? Theme.palette.dangerColor2 : Theme.palette.primaryColor2 border.width: 2 layer.enabled: true layer.effect: DropShadow { verticalOffset: 3 radius: 8 samples: 15 fast: true cached: true color: root.border.color spread: 0.1 } onActiveChanged: { if (!active || !flickable) return; const item = Window.window.activeFocusItem; const h1 = this.height; const y1 = this.mapToGlobal(0, 0).y; const h2 = item.height; const y2 = item.mapToGlobal(0, 0).y; const margin = 20; const offset = h2 - (y1 - y2); if (offset <= 0 || flickable.contentHeight <= 0) return; toastFlickAnimation.from = flickable.contentY; toastFlickAnimation.to = flickable.contentY + offset + margin; toastFlickAnimation.start() } NumberAnimation { id: toastFlickAnimation target: root.flickable property: "contentY" duration: 150 easing.type: Easing.InOutQuad } NumberAnimation on border.width { id: toastAlertAnimation from: 0 to: 4 loops: 2 duration: 600 onFinished: root.border.width = 2 } Behavior on opacity { NumberAnimation {} } MouseArea { anchors.fill: parent visible: root.active // This is required not to change cursorShape enabled: root.active hoverEnabled: true } ColumnLayout { id: toastContent anchors.fill: parent anchors.margins: Style.current.padding spacing: Style.current.padding RowLayout { Layout.alignment: Qt.AlignHCenter StatusBaseText { id: changesDetectedTextItem Layout.fillWidth: true padding: 8 horizontalAlignment: Text.AlignHCenter color: Theme.palette.directColor1 text: root.defaultChangesDetectedText } StatusButton { id: cancelChangesButton text: root.defaultCancelChangesText enabled: !root.loading && root.active visible: root.cancelButtonVisible type: StatusBaseButton.Type.Danger onClicked: root.resetChangesClicked() } StatusFlatButton { id: saveForLaterButton text: root.defaultSaveForLaterText loading: root.loading enabled: root.active && root.saveChangesButtonEnabled visible: root.saveForLaterButtonVisible onClicked: root.saveForLaterClicked() } StatusButton { id: saveChangesButton objectName: "settingsDirtyToastMessageSaveButton" loading: root.loading text: root.defaultSaveChangesText interactive: root.active && root.saveChangesButtonEnabled tooltip.text: root.saveChangesTooltipText onClicked: root.saveChangesClicked() } } Separator { id: separator Layout.fillWidth: true visible: additionalTextComponent.visible } StatusBaseText { id: additionalTextComponent Layout.alignment: Qt.AlignHCenter font.pixelSize: Theme.tertiaryTextFontSize visible: false } } }