quickshell-toki-night/modules/notifications/Content.qml

195 lines
5.6 KiB
QML

import qs.config
import qs.custom
import qs.services
import Quickshell
import Quickshell.Widgets
import QtQuick
Item {
id: root
required property PersistentProperties uiState
required property Item panels
readonly property int padding: 15
readonly property var monitor: Hypr.monitorFor(QsWindow.window.screen)
readonly property var notifs: Notifs.list.filter(n => n.popup === monitor)
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
implicitWidth: implicitHeight > 0 ? Config.notifs.width + padding * 2 : 0
implicitHeight: {
const count = list.count;
if (count === 0)
return 0;
let height = (count - 1) * 10 + padding * 2;
for (let i = 0; i < count; i++)
height += list.itemAtIndex(i)?.nonAnimHeight ?? 0;
if (uiState.osd) {
const h = panels.osd.y - Config.border.rounding * 2;
if (height > h)
height = h;
}
return Math.min((QsWindow.window?.screen?.height ?? 0) - Config.bar.height - Config.border.thickness - padding, height);
}
ClippingWrapperRectangle {
anchors.fill: parent
anchors.margins: root.padding
color: "transparent"
radius: 17
CustomListView {
id: list
model: ScriptModel {
values: root.notifs
}
anchors.fill: parent
orientation: Qt.Vertical
spacing: 0
cacheBuffer: QsWindow.window?.screen.height ?? 0
delegate: Item {
id: wrapper
required property Notifs.Notif modelData
required property int index
readonly property alias nonAnimHeight: notif.nonAnimHeight
property int idx
onIndexChanged: {
if (index !== -1)
idx = index;
}
implicitWidth: notif.implicitWidth
implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 10)
ListView.onRemove: removeAnim.start()
SequentialAnimation {
id: removeAnim
PropertyAction {
target: wrapper
property: "ListView.delayRemove"
value: true
}
PropertyAction {
target: wrapper
property: "enabled"
value: false
}
PropertyAction {
target: wrapper
property: "implicitHeight"
value: 0
}
PropertyAction {
target: wrapper
property: "z"
value: 1
}
Anim {
target: notif
property: "x"
to: (notif.x >= 0 ? Config.notifs.width : -Config.notifs.width) * 2
easing.bezierCurve: Config.anim.curves.emphasized
}
PropertyAction {
target: wrapper
property: "ListView.delayRemove"
value: false
}
}
ClippingRectangle {
anchors.top: parent.top
anchors.topMargin: wrapper.idx === 0 ? 0 : 10
color: "transparent"
radius: notif.radius
implicitWidth: notif.implicitWidth
implicitHeight: notif.implicitHeight
Notification {
id: notif
notif: wrapper.modelData
}
}
}
move: Transition {
NotifAnim {
property: "y"
}
}
displaced: Transition {
NotifAnim {
property: "y"
}
}
ExtraIndicator {
anchors.top: parent.top
extra: {
const count = list.count;
if (count === 0)
return 0;
const scrollY = list.contentY;
let height = 0;
for (let i = 0; i < count; i++) {
height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 10;
if (height - 10 >= scrollY)
return i;
}
return count;
}
}
ExtraIndicator {
anchors.bottom: parent.bottom
extra: {
const count = list.count;
if (count === 0)
return 0;
const scrollY = list.contentHeight - (list.contentY + list.height);
let height = 0;
for (let i = count - 1; i >= 0; i--) {
height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 10;
if (height - 10 >= scrollY)
return count - i - 1;
}
return 0;
}
}
}
}
Behavior on implicitHeight {
NotifAnim {}
}
component NotifAnim: Anim {
duration: Config.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Config.anim.curves.expressiveDefaultSpatial
}
}