264 lines
7.5 KiB
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
|
|
}
|
|
}
|