186 lines
5.1 KiB
QML
186 lines
5.1 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import qs.components
|
|
import qs.config
|
|
import qs.services
|
|
import Quickshell
|
|
import Quickshell.Widgets
|
|
import QtQuick
|
|
|
|
Item {
|
|
id: root
|
|
|
|
required property Item panels
|
|
|
|
readonly property int spacing: Appearance.spacing.small
|
|
readonly property int maxToasts: 5
|
|
readonly property bool listVisible: panels.notifications.content.shouldShow
|
|
|
|
property bool flag
|
|
property var activeToasts: new Set()
|
|
|
|
anchors.top: parent.top
|
|
anchors.right: parent.right
|
|
anchors.margins: Appearance.padding.normal
|
|
|
|
implicitWidth: Config.notifs.sizes.width
|
|
implicitHeight: {
|
|
if (listVisible)
|
|
return 0;
|
|
|
|
let height = -spacing;
|
|
for (let i = 0; i < repeater.count; i++) {
|
|
const item = repeater.itemAt(i) as ToastWrapper;
|
|
if (item && !item.modelData.closed && !item.previewHidden)
|
|
height += item.implicitHeight + spacing;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
opacity: listVisible ? 0 : 1
|
|
visible: opacity > 0
|
|
|
|
Behavior on opacity {
|
|
Anim {
|
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: repeater
|
|
|
|
model: ScriptModel {
|
|
values: {
|
|
const toasts = [];
|
|
let visibleCount = 0;
|
|
|
|
for (const notif of Notifs.list) {
|
|
if (notif.showAsToast) {
|
|
root.activeToasts.add(notif);
|
|
}
|
|
if (notif.closed) {
|
|
root.activeToasts.delete(notif);
|
|
}
|
|
}
|
|
|
|
for (const notif of Notifs.list) {
|
|
if (root.activeToasts.has(notif)) {
|
|
toasts.push(notif);
|
|
if (notif.showAsToast && !notif.closed) {
|
|
visibleCount++;
|
|
if (visibleCount > root.maxToasts)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return toasts;
|
|
}
|
|
onValuesChanged: root.flagChanged()
|
|
}
|
|
|
|
ToastWrapper {}
|
|
}
|
|
|
|
component ToastWrapper: MouseArea {
|
|
id: toast
|
|
|
|
required property int index
|
|
required property Notifs.Notif modelData
|
|
|
|
readonly property bool previewHidden: {
|
|
let extraHidden = 0;
|
|
for (let i = 0; i < index; i++) {
|
|
const item = repeater.itemAt(i);
|
|
if (item && item.modelData.closed)
|
|
extraHidden++;
|
|
}
|
|
return index >= root.maxToasts + extraHidden;
|
|
}
|
|
|
|
opacity: modelData.closed || previewHidden || !modelData.showAsToast ? 0 : 1
|
|
scale: modelData.closed || previewHidden || !modelData.showAsToast ? 0.7 : 1
|
|
|
|
anchors.topMargin: {
|
|
root.flag;
|
|
let margin = 0;
|
|
for (let i = 0; i < index; i++) {
|
|
const item = repeater.itemAt(i) as ToastWrapper;
|
|
if (item && !item.modelData.closed && !item.previewHidden)
|
|
margin += item.implicitHeight + root.spacing;
|
|
}
|
|
return margin;
|
|
}
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
implicitHeight: toastInner.implicitHeight
|
|
|
|
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
|
onClicked: {
|
|
modelData.showAsToast = false;
|
|
modelData.close();
|
|
}
|
|
|
|
Component.onCompleted: modelData.lock(this)
|
|
|
|
onPreviewHiddenChanged: {
|
|
if (initAnim.running && previewHidden)
|
|
initAnim.stop();
|
|
}
|
|
|
|
Anim {
|
|
id: initAnim
|
|
|
|
Component.onCompleted: running = !toast.previewHidden
|
|
|
|
target: toast
|
|
properties: "opacity,scale"
|
|
from: 0
|
|
to: 1
|
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
|
}
|
|
|
|
ParallelAnimation {
|
|
running: toast.modelData.closed || (!toast.modelData.showAsToast && !toast.modelData.closed)
|
|
onStarted: toast.anchors.topMargin = toast.anchors.topMargin
|
|
onFinished: {
|
|
if (toast.modelData.closed)
|
|
toast.modelData.unlock(toast);
|
|
}
|
|
|
|
Anim {
|
|
target: toast
|
|
property: "opacity"
|
|
to: 0
|
|
}
|
|
Anim {
|
|
target: toast
|
|
property: "scale"
|
|
to: 0.7
|
|
}
|
|
}
|
|
|
|
NotificationToast {
|
|
id: toastInner
|
|
|
|
modelData: toast.modelData
|
|
}
|
|
|
|
Behavior on opacity {
|
|
Anim {}
|
|
}
|
|
|
|
Behavior on scale {
|
|
Anim {}
|
|
}
|
|
|
|
Behavior on anchors.topMargin {
|
|
Anim {
|
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
|
}
|
|
}
|
|
}
|
|
}
|