forked from Shinonome/dots-hyprland
right sidebar: cleaner notification implementation
This commit is contained in:
@@ -21,7 +21,6 @@ Item {
|
|||||||
property bool expanded: false
|
property bool expanded: false
|
||||||
property bool enableAnimation: true
|
property bool enableAnimation: true
|
||||||
property int notificationListSpacing: 5
|
property int notificationListSpacing: 5
|
||||||
property bool ready: false
|
|
||||||
property int defaultTimeoutValue: 5000
|
property int defaultTimeoutValue: 5000
|
||||||
|
|
||||||
property var notificationXAnimation: Appearance.animation.elementMoveEnter
|
property var notificationXAnimation: Appearance.animation.elementMoveEnter
|
||||||
@@ -29,18 +28,9 @@ Item {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
clip: !popup
|
clip: !popup
|
||||||
|
|
||||||
implicitHeight: ready ? notificationColumnLayout.implicitHeight + notificationListSpacing : 0
|
implicitHeight: notificationColumnLayout.implicitHeight + notificationListSpacing
|
||||||
Behavior on implicitHeight {
|
|
||||||
enabled: enableAnimation
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Appearance.animation.elementMoveFast.duration
|
|
||||||
easing.type: Appearance.animation.elementMoveFast.type
|
|
||||||
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
root.ready = true
|
|
||||||
if (popup) timeoutTimer.start()
|
if (popup) timeoutTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +79,6 @@ Item {
|
|||||||
onTriggered: {
|
onTriggered: {
|
||||||
notificationRowWrapper.anchors.top = undefined
|
notificationRowWrapper.anchors.top = undefined
|
||||||
notificationRowWrapper.anchors.bottom = root.bottom
|
notificationRowWrapper.anchors.bottom = root.bottom
|
||||||
implicitHeight = 0
|
|
||||||
destroyTimer2.start()
|
destroyTimer2.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +88,7 @@ Item {
|
|||||||
interval: Appearance.animation.elementMoveFast.duration
|
interval: Appearance.animation.elementMoveFast.duration
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.destroy()
|
Notifications.discardNotification(notificationObject.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +98,7 @@ Item {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
if (mouse.button == Qt.MiddleButton)
|
if (mouse.button == Qt.MiddleButton)
|
||||||
Notifications.discardNotification(notificationObject.id);
|
root.destroyWithAnimation()
|
||||||
else if (mouse.button == Qt.RightButton)
|
else if (mouse.button == Qt.RightButton)
|
||||||
root.toggleExpanded()
|
root.toggleExpanded()
|
||||||
}
|
}
|
||||||
@@ -141,7 +130,7 @@ Item {
|
|||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
if (notificationRowWrapper.x > dragConfirmThreshold) {
|
if (notificationRowWrapper.x > dragConfirmThreshold) {
|
||||||
root.notificationXAnimation = Appearance.animation.elementMoveEnter
|
root.notificationXAnimation = Appearance.animation.elementMoveEnter
|
||||||
Notifications.discardNotification(notificationObject.id);
|
root.destroyWithAnimation()
|
||||||
} else {
|
} else {
|
||||||
// Animate back if not far enough
|
// Animate back if not far enough
|
||||||
root.notificationXAnimation = Appearance.animation.elementMoveFast
|
root.notificationXAnimation = Appearance.animation.elementMoveFast
|
||||||
@@ -583,7 +572,7 @@ Item {
|
|||||||
(contentItem.implicitWidth + leftPadding + rightPadding)
|
(contentItem.implicitWidth + leftPadding + rightPadding)
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Notifications.discardNotification(notificationObject.id);
|
root.destroyWithAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: MaterialSymbol {
|
contentItem: MaterialSymbol {
|
||||||
|
|||||||
@@ -5,67 +5,14 @@ import Qt5Compat.GraphicalEffects
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property Component notifComponent: NotificationWidget {}
|
|
||||||
property list<NotificationWidget> notificationWidgetList: []
|
|
||||||
|
|
||||||
// Signal handlers to add/remove notifications
|
ListView { // Scrollable window
|
||||||
Connections {
|
id: listview
|
||||||
target: Notifications
|
|
||||||
function onInitDone() {
|
|
||||||
// notificationRepeater.model = Notifications.list.slice().reverse()
|
|
||||||
Notifications.list.slice().reverse().forEach((notification) => {
|
|
||||||
const notif = root.notifComponent.createObject(columnLayout, { notificationObject: notification });
|
|
||||||
notificationWidgetList.push(notif)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function onNotify(notification) {
|
|
||||||
// notificationRepeater.model = [notification, ...notificationRepeater.model]
|
|
||||||
const notif = root.notifComponent.createObject(columnLayout, { notificationObject: notification });
|
|
||||||
notificationWidgetList.unshift(notif)
|
|
||||||
|
|
||||||
// Remove stuff from t he column, add back
|
|
||||||
for (let i = 0; i < notificationWidgetList.length; i++) {
|
|
||||||
if (notificationWidgetList[i].parent === columnLayout) {
|
|
||||||
notificationWidgetList[i].parent = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add notification widgets to the column
|
|
||||||
for (let i = 0; i < notificationWidgetList.length; i++) {
|
|
||||||
if (notificationWidgetList[i].parent === null) {
|
|
||||||
notificationWidgetList[i].parent = columnLayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDiscard(id) {
|
|
||||||
for (let i = notificationWidgetList.length - 1; i >= 0; i--) {
|
|
||||||
const widget = notificationWidgetList[i];
|
|
||||||
if (widget && widget.notificationObject && widget.notificationObject.id === id) {
|
|
||||||
widget.destroyWithAnimation();
|
|
||||||
notificationWidgetList.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDiscardAll() {
|
|
||||||
for (let i = notificationWidgetList.length - 1; i >= 0; i--) {
|
|
||||||
const widget = notificationWidgetList[i];
|
|
||||||
if (widget && widget.notificationObject) {
|
|
||||||
widget.destroyWithAnimation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notificationWidgetList = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Flickable { // Scrollable window
|
|
||||||
id: flickable
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -76,28 +23,82 @@ Item {
|
|||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.effect: OpacityMask {
|
layer.effect: OpacityMask {
|
||||||
maskSource: Rectangle {
|
maskSource: Rectangle {
|
||||||
width: flickable.width
|
width: listview.width
|
||||||
height: flickable.height
|
height: listview.height
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout { // Scrollable window content
|
add: Transition {
|
||||||
id: columnLayout
|
animations: [
|
||||||
anchors.left: parent.left
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
anchors.right: parent.right
|
properties: "opacity,scale",
|
||||||
spacing: 0 // The widgets themselves have margins for spacing
|
from: 0,
|
||||||
|
to: 1,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
// Notifications are added by the above signal handlers
|
addDisplaced: Transition {
|
||||||
|
animations: [
|
||||||
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
|
property: "y",
|
||||||
|
}),
|
||||||
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
|
properties: "opacity,scale",
|
||||||
|
to: 1,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
displaced: Transition {
|
||||||
|
animations: [
|
||||||
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
|
property: "y",
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
move: Transition {
|
||||||
|
animations: [
|
||||||
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
|
property: "y",
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
remove: Transition {
|
||||||
|
animations: [
|
||||||
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
|
property: "x",
|
||||||
|
to: listview.width,
|
||||||
|
}),
|
||||||
|
Appearance.animation.elementMove.numberAnimation.createObject(this, {
|
||||||
|
property: "opacity",
|
||||||
|
to: 0,
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
model: ScriptModel {
|
||||||
|
values: Notifications.list.slice().reverse()
|
||||||
|
}
|
||||||
|
delegate: NotificationWidget {
|
||||||
|
required property var modelData
|
||||||
|
id: notificationWidget
|
||||||
|
// anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.left: parent?.left
|
||||||
|
anchors.right: parent?.right
|
||||||
|
Layout.fillWidth: true
|
||||||
|
notificationObject: modelData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placeholder when list is empty
|
// Placeholder when list is empty
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: flickable
|
anchors.fill: listview
|
||||||
|
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
opacity: (root.notificationWidgetList.length === 0) ? 1 : 0
|
opacity: (Notifications.list.length === 0) ? 1 : 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -137,9 +138,9 @@ Item {
|
|||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
text: `${notificationWidgetList.length} notification${notificationWidgetList.length > 1 ? "s" : ""}`
|
text: `${Notifications.list.length} notifications`
|
||||||
|
|
||||||
opacity: notificationWidgetList.length > 0 ? 1 : 0
|
opacity: Notifications.list.length > 0 ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||||
|
|||||||
Reference in New Issue
Block a user