quickshell-toki-night/modules/dashboard/dash/Notifs.qml

264 lines
7.5 KiB
QML

pragma ComponentBehavior: Bound
import qs.config
import qs.custom
import qs.services
import qs.util
import Quickshell
import Quickshell.Services.Notifications
import QtQuick
import QtQuick.Layouts
import qs.modules.notifications as N
ColumnLayout {
id: root
anchors.fill: parent
spacing: 7
readonly property int notifCount:
(Notifs.list && Notifs.list.length !== undefined) ? Notifs.list.length :
((Notifs.list && Notifs.list.count !== undefined) ? Notifs.list.count : 0)
function notifAt(i) {
if (!Notifs.list)
return undefined;
if (typeof Notifs.list.get === 'function')
return Notifs.list.get(i);
return Notifs.list[i];
}
function scrollToTop(): void {
if (notifScroll && notifScroll.contentItem && notifScroll.contentItem.contentY !== undefined) {
notifScroll.contentItem.contentY = 0;
}
}
RowLayout {
Layout.alignment: Qt.AlignTop
Layout.margins: 10
Layout.fillWidth: true
spacing: 7
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
id: icon
text: {
if (Notifs.dnd)
return "notifications_off";
if (notifCount > 0)
return "notifications_active";
return "notifications";
}
fill: {
if (Notifs.dnd)
return 0;
if (notifCount > 0)
return 1;
return 0;
}
color: Notifs.dnd ? Config.colors.error : Config.colors.notification
font.pointSize: Config.font.size.larger
animate: true
Behavior on color {
SequentialAnimation {
PauseAnimation {
duration: icon.animateDuration / 2
}
PropertyAction {}
}
}
}
CustomText {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
text: notifCount > 0 ? qsTr("%1 notifications").arg(notifCount) : qsTr("No notifications")
font.weight: 600
font.pointSize: Config.font.size.normal
animate: true
}
CustomText {
Layout.alignment: Qt.AlignVCenter
text: qsTr("Do Not Disturb")
}
CustomSwitch {
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 5
Layout.rightMargin: 5
bg: Config.colors.containerAlt
accent: Color.mute(Config.colors.notification)
checked: Notifs.dnd
onToggled: Notifs.toggleDnd()
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 10
Layout.rightMargin: 10
Layout.bottomMargin: 10
CustomListView {
id: notifScroll
anchors.fill: parent
anchors.margins: 10
anchors.rightMargin: 5
spacing: 12
clip: true
CustomScrollBar.vertical: CustomScrollBar {
flickable: notifScroll
}
model: ScriptModel {
values: [...Notifs.list].reverse()
}
delegate: Item {
id: wrapper
required property int index
required property var modelData
readonly property alias nonAnimHeight: notif.nonAnimHeight
width: 405
height: notif.implicitHeight
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
}
}
N.Notification {
id: notif
width: parent.width
notif: wrapper.modelData
color: wrapper.modelData.urgency === NotificationUrgency.Critical ? Config.colors.errorBg : Config.colors.containerAlt
inPopup: false
}
}
add: Transition {
Anim {
property: "x"
from: Config.notifs.width
to: 0
easing.bezierCurve: Config.anim.curves.emphasizedDecel
}
}
move: Transition {
NotifAnim {
property: "y"
}
}
displaced: Transition {
NotifAnim {
property: "y"
}
}
}
}
Item {
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
height: 0
CustomRect {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: bottomMargin
property real bottomMargin: notifCount > 0 ? 12 : -4
opacity: notifCount > 0 ? 1 : 0
visible: opacity > 0
implicitWidth: clearBtn.implicitWidth + 32
implicitHeight: clearBtn.implicitHeight + 20
radius: 25
color: Config.colors.inactive
Behavior on opacity {
Anim {}
}
Behavior on bottomMargin {
Anim {}
}
StateLayer {
anchors.fill: parent
function onClicked(): void {
for (let i = root.notifCount - 1; i >= 0; i--) {
const n = root.notifAt(i);
n?.notification?.dismiss();
}
}
}
RowLayout {
id: clearBtn
anchors.centerIn: parent
spacing: 7
MaterialIcon {
id: clearIcon
text: "clear_all"
color: Config.colors.secondary
}
CustomText {
text: qsTr("Clear all")
color: Config.colors.secondary
}
}
}
}
component NotifAnim: Anim {
duration: Config.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Config.anim.curves.expressiveDefaultSpatial
}
}