feat: checkpoint QML view migration
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qEmby 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property int defaultDuration: 4000
|
||||
property int maximumVisible: 5
|
||||
property int nextToastId: 1
|
||||
|
||||
function show(message, kind, duration) {
|
||||
const normalizedKind = ["info", "success", "warning", "error"].indexOf(kind) >= 0 ? kind : "info";
|
||||
const timeout = duration === undefined ? defaultDuration : Math.max(0, duration);
|
||||
const toastId = nextToastId++;
|
||||
toastModel.append({
|
||||
"toastId": toastId,
|
||||
"message": String(message),
|
||||
"kind": normalizedKind,
|
||||
"timeoutMs": timeout
|
||||
});
|
||||
while (toastModel.count > maximumVisible)toastModel.remove(0)
|
||||
return toastId;
|
||||
}
|
||||
|
||||
function info(message, duration) {
|
||||
return show(message, "info", duration);
|
||||
}
|
||||
|
||||
function success(message, duration) {
|
||||
return show(message, "success", duration);
|
||||
}
|
||||
|
||||
function warning(message, duration) {
|
||||
return show(message, "warning", duration);
|
||||
}
|
||||
|
||||
function error(message, duration) {
|
||||
return show(message, "error", duration);
|
||||
}
|
||||
|
||||
function dismiss(toastId) {
|
||||
for (let i = 0; i < toastModel.count; ++i) {
|
||||
if (toastModel.get(i).toastId === toastId) {
|
||||
toastModel.remove(i);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
toastModel.clear();
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: toastModel
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: toastView
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: Theme.spacingLg
|
||||
anchors.rightMargin: Theme.spacingLg
|
||||
width: Math.min(360, Math.max(240, root.width - Theme.spacingXl * 2))
|
||||
height: Math.min(contentHeight, Math.max(0, root.height - Theme.spacingXl * 2))
|
||||
spacing: Theme.spacingSm
|
||||
interactive: contentHeight > height
|
||||
clip: true
|
||||
model: toastModel
|
||||
z: 1000
|
||||
|
||||
add: Transition {
|
||||
NumberAnimation {
|
||||
properties: "opacity,x"
|
||||
from: 0
|
||||
duration: Theme.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: Theme.animationFast
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
duration: Theme.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
id: toast
|
||||
|
||||
required property int toastId
|
||||
required property string message
|
||||
required property string kind
|
||||
required property int timeoutMs
|
||||
readonly property color statusColor: kind === "success" ? Theme.success : kind === "warning" ? Theme.warning : kind === "error" ? Theme.danger : Theme.accent
|
||||
readonly property string statusIcon: kind === "success" ? "✓" : kind === "warning" ? "!" : kind === "error" ? "×" : "i"
|
||||
readonly property string statusLabel: kind === "success" ? qsTr("Success") : kind === "warning" ? qsTr("Warning") : kind === "error" ? qsTr("Error") : qsTr("Information")
|
||||
|
||||
width: toastView.width
|
||||
implicitHeight: toastLayout.implicitHeight + Theme.spacingMd * 2
|
||||
radius: Theme.radiusLg
|
||||
color: Theme.bgSurface
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(statusColor, 0.72)
|
||||
Accessible.role: Accessible.AlertMessage
|
||||
Accessible.name: qsTr("%1: %2").arg(statusLabel).arg(message)
|
||||
|
||||
RowLayout {
|
||||
id: toastLayout
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingMd
|
||||
spacing: Theme.spacingMd
|
||||
|
||||
Rectangle {
|
||||
color: toast.statusColor
|
||||
radius: width / 2
|
||||
Layout.preferredWidth: 24
|
||||
Layout.preferredHeight: 24
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: toast.statusIcon
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: Theme.fontBody
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text {
|
||||
text: toast.message
|
||||
color: Theme.textBody
|
||||
font.pixelSize: Theme.fontBody
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
ThemedButton {
|
||||
text: "×"
|
||||
implicitWidth: 28
|
||||
implicitHeight: 28
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
Accessible.name: qsTr("Dismiss notification")
|
||||
Layout.alignment: Qt.AlignTop
|
||||
onClicked: root.dismiss(toast.toastId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: toast.timeoutMs
|
||||
running: toast.timeoutMs > 0
|
||||
repeat: false
|
||||
onTriggered: root.dismiss(toast.toastId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user