Files
2025-10-31 19:06:16 -04:00

175 lines
3.5 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
Rectangle {
id: root
property string message: ""
property string description: ""
property string icon: ""
property string type: "notice"
property int duration: 3000
readonly property real initialScale: 0.7
signal hidden
width: parent.width
height: Math.round(contentLayout.implicitHeight + Style.marginL * 2)
radius: Style.radiusL
visible: false
opacity: 0
scale: initialScale
color: Color.mSurface
// Colored border based on type
border.color: {
switch (type) {
case "warning":
return Color.mPrimary
case "error":
return Color.mError
default:
return Color.mOutline
}
}
border.width: Math.max(2, Style.borderM)
Behavior on opacity {
NumberAnimation {
duration: Style.animationNormal
easing.type: Easing.OutCubic
}
}
Behavior on scale {
NumberAnimation {
duration: Style.animationNormal
easing.type: Easing.OutCubic
}
}
Timer {
id: hideTimer
interval: root.duration
onTriggered: root.hide()
}
Timer {
id: hideAnimation
interval: Style.animationFast
onTriggered: {
root.visible = false
root.hidden()
}
}
// Cleanup on destruction
Component.onDestruction: {
hideTimer.stop()
hideAnimation.stop()
}
RowLayout {
id: contentLayout
anchors.fill: parent
anchors.margins: Style.marginL
spacing: Style.marginL
// Icon
NIcon {
icon: if (root.icon !== "") {
return root.icon
} else if (type === "warning") {
return "toast-warning"
} else if (type === "error") {
return "toast-error"
} else {
return "toast-notice"
}
color: {
switch (type) {
case "warning":
return Color.mPrimary
case "error":
return Color.mError
default:
return Color.mOnSurface
}
}
pointSize: Style.fontSizeXXL * 1.5
Layout.alignment: Qt.AlignVCenter
}
// Label and description
ColumnLayout {
spacing: Style.marginXXS
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
NText {
Layout.fillWidth: true
text: root.message
color: Color.mOnSurface
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
wrapMode: Text.WordWrap
visible: text.length > 0
}
NText {
Layout.fillWidth: true
text: root.description
color: Color.mOnSurface
pointSize: Style.fontSizeM
wrapMode: Text.WordWrap
visible: text.length > 0
}
}
}
// Click anywhere dismiss the toast
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: root.hide()
cursorShape: Qt.PointingHandCursor
}
function show(msg, desc, msgIcon, msgType, msgDuration) {
// Stop all timers first
hideTimer.stop()
hideAnimation.stop()
message = msg
description = desc || ""
icon = msgIcon || ""
type = msgType || "notice"
duration = msgDuration || 3000
visible = true
opacity = 1
scale = 1.0
hideTimer.restart()
}
function hide() {
hideTimer.stop()
opacity = 0
scale = initialScale
hideAnimation.restart()
}
function hideImmediately() {
hideTimer.stop()
hideAnimation.stop()
opacity = 0
scale = initialScale
root.visible = false
root.hidden()
}
}