summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/lock/NotifDock.qml5
-rw-r--r--modules/lock/NotifGroup.qml4
-rw-r--r--modules/notifications/Content.qml2
-rw-r--r--modules/sidebar/NotifDock.qml134
-rw-r--r--modules/sidebar/NotifDockList.qml150
-rw-r--r--modules/sidebar/NotifGroup.qml19
-rw-r--r--modules/sidebar/NotifGroupList.qml22
7 files changed, 207 insertions, 129 deletions
diff --git a/modules/lock/NotifDock.qml b/modules/lock/NotifDock.qml
index ac40319..7551e68 100644
--- a/modules/lock/NotifDock.qml
+++ b/modules/lock/NotifDock.qml
@@ -84,7 +84,10 @@ ColumnLayout {
clip: true
model: ScriptModel {
- values: [...new Set(Notifs.list.map(notif => notif.appName))].reverse()
+ values: {
+ const list = Notifs.notClosed.map(n => [n.appName, null]);
+ return [...new Map(list).keys()];
+ }
}
delegate: NotifGroup {}
diff --git a/modules/lock/NotifGroup.qml b/modules/lock/NotifGroup.qml
index 15342d4..2a08c26 100644
--- a/modules/lock/NotifGroup.qml
+++ b/modules/lock/NotifGroup.qml
@@ -16,7 +16,7 @@ StyledRect {
required property string modelData
- readonly property list<var> notifs: Notifs.list.filter(notif => notif.appName === modelData).reverse()
+ readonly property list<var> notifs: Notifs.list.filter(notif => notif.appName === modelData)
readonly property string image: notifs.find(n => n.image.length > 0)?.image ?? ""
readonly property string appIcon: notifs.find(n => n.appIcon.length > 0)?.appIcon ?? ""
readonly property string urgency: notifs.some(n => n.urgency === NotificationUrgency.Critical) ? "critical" : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? "normal" : "low"
@@ -227,7 +227,7 @@ StyledRect {
ParallelAnimation {
running: notif.modelData.closed
- onFinished: notif.modelData.lock(notif)
+ onFinished: notif.modelData.unlock(notif)
Anim {
target: notif
diff --git a/modules/notifications/Content.qml b/modules/notifications/Content.qml
index 019e922..2d4590e 100644
--- a/modules/notifications/Content.qml
+++ b/modules/notifications/Content.qml
@@ -55,7 +55,7 @@ Item {
id: list
model: ScriptModel {
- values: Notifs.popups.filter(n => !n.closed).reverse()
+ values: Notifs.popups.filter(n => !n.closed)
}
anchors.fill: parent
diff --git a/modules/sidebar/NotifDock.qml b/modules/sidebar/NotifDock.qml
index 0a6eeaa..e3267c3 100644
--- a/modules/sidebar/NotifDock.qml
+++ b/modules/sidebar/NotifDock.qml
@@ -89,133 +89,23 @@ Item {
}
}
- StyledListView {
+ StyledFlickable {
id: view
anchors.fill: parent
- spacing: Appearance.spacing.small
-
- model: ScriptModel {
- values: {
- const list = Notifs.list.filter(n => !n.closed).sort((a, b) => b.time - a.time).map(n => [n.appName, null]);
- return [...new Map(list).keys()];
- }
- }
+ flickableDirection: Flickable.VerticalFlick
+ contentWidth: width
+ contentHeight: notifList.implicitHeight
StyledScrollBar.vertical: StyledScrollBar {
flickable: view
}
- delegate: MouseArea {
- id: notif
-
- required property int index
- required property string modelData
-
- property int startY
-
- function closeAll(): void {
- for (const n of Notifs.list.filter(n => !n.closed && n.appName === modelData))
- n.close();
- }
-
- implicitWidth: root.width
- implicitHeight: notifInner.implicitHeight
-
- hoverEnabled: true
- cursorShape: pressed ? Qt.ClosedHandCursor : undefined
- acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
- preventStealing: true
+ NotifDockList {
+ id: notifList
- drag.target: this
- drag.axis: Drag.XAxis
-
- onPressed: event => {
- if (event.button === Qt.LeftButton)
- startY = event.y;
- else if (event.button === Qt.RightButton)
- notifInner.toggleExpand();
- else if (event.button === Qt.MiddleButton)
- closeAll();
- }
- onPositionChanged: event => {
- if (pressed) {
- const diffY = event.y - startY;
- if (Math.abs(diffY) > Config.notifs.expandThreshold)
- notifInner.toggleExpand(diffY > 0);
- }
- }
- onReleased: event => {
- if (Math.abs(x) < width * Config.notifs.clearThreshold)
- x = 0;
- else
- closeAll();
- }
-
- NotifGroup {
- id: notifInner
-
- modelData: notif.modelData
- props: root.props
- }
-
- Behavior on x {
- Anim {
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
- }
-
- add: Transition {
- Anim {
- property: "opacity"
- from: 0
- to: 1
- }
- Anim {
- property: "scale"
- from: 0
- to: 1
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
-
- remove: Transition {
- Anim {
- property: "opacity"
- to: 0
- }
- Anim {
- property: "scale"
- to: 0.6
- }
- }
-
- move: Transition {
- Anim {
- properties: "opacity,scale"
- to: 1
- }
- Anim {
- property: "y"
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
-
- displaced: Transition {
- Anim {
- properties: "opacity,scale"
- to: 1
- }
- Anim {
- property: "y"
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
+ props: root.props
}
}
}
@@ -226,8 +116,14 @@ Item {
repeat: true
interval: 50
onTriggered: {
- if (root.notifCount > 0)
- Notifs.list.find(n => !n.closed).close();
+ let next = null;
+ for (let i = 0; i < notifList.repeater.count; i++) {
+ next = notifList.repeater.itemAt(i);
+ if (!next?.closed)
+ break;
+ }
+ if (next)
+ next.closeAll();
else
stop();
}
diff --git a/modules/sidebar/NotifDockList.qml b/modules/sidebar/NotifDockList.qml
new file mode 100644
index 0000000..0fd3464
--- /dev/null
+++ b/modules/sidebar/NotifDockList.qml
@@ -0,0 +1,150 @@
+pragma ComponentBehavior: Bound
+
+import qs.components
+import qs.services
+import qs.config
+import Quickshell
+import QtQuick
+
+Item {
+ id: root
+
+ required property Props props
+
+ readonly property alias repeater: repeater
+ readonly property int spacing: Appearance.spacing.small
+ property bool flag
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ implicitHeight: {
+ const item = repeater.itemAt(repeater.count - 1);
+ return item ? item.y + item.implicitHeight : 0;
+ }
+
+ Repeater {
+ id: repeater
+
+ model: ScriptModel {
+ values: {
+ const list = Notifs.list.map(n => [n.appName, null]);
+ return [...new Map(list).keys()];
+ }
+ onValuesChanged: root.flagChanged()
+ }
+
+ MouseArea {
+ id: notif
+
+ required property int index
+ required property string modelData
+
+ readonly property bool closed: notifInner.notifCount === 0
+ readonly property alias nonAnimHeight: notifInner.nonAnimHeight
+ property int startY
+
+ function closeAll(): void {
+ for (const n of Notifs.notClosed.filter(n => n.appName === modelData))
+ n.close();
+ }
+
+ y: {
+ root.flag; // Force update
+ let y = 0;
+ for (let i = 0; i < index; i++) {
+ const item = repeater.itemAt(i);
+ if (!item.closed)
+ y += item.nonAnimHeight + root.spacing;
+ }
+ return y;
+ }
+
+ implicitWidth: root.width
+ implicitHeight: notifInner.implicitHeight
+
+ hoverEnabled: true
+ cursorShape: pressed ? Qt.ClosedHandCursor : undefined
+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
+ preventStealing: true
+
+ drag.target: this
+ drag.axis: Drag.XAxis
+
+ onPressed: event => {
+ startY = event.y;
+ if (event.button === Qt.RightButton)
+ notifInner.toggleExpand(!notifInner.expanded);
+ else if (event.button === Qt.MiddleButton)
+ closeAll();
+ }
+ onPositionChanged: event => {
+ if (pressed) {
+ const diffY = event.y - startY;
+ if (Math.abs(diffY) > Config.notifs.expandThreshold)
+ notifInner.toggleExpand(diffY > 0);
+ }
+ }
+ onReleased: event => {
+ if (Math.abs(x) < width * Config.notifs.clearThreshold)
+ x = 0;
+ else
+ closeAll();
+ }
+
+ ParallelAnimation {
+ running: true
+
+ Anim {
+ target: notif
+ property: "opacity"
+ from: 0
+ to: 1
+ }
+ Anim {
+ target: notif
+ property: "scale"
+ from: 0
+ to: 1
+ duration: Appearance.anim.durations.expressiveDefaultSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
+ }
+ }
+
+ ParallelAnimation {
+ running: notif.closed
+
+ Anim {
+ target: notif
+ property: "opacity"
+ to: 0
+ }
+ Anim {
+ target: notif
+ property: "scale"
+ to: 0.6
+ }
+ }
+
+ NotifGroup {
+ id: notifInner
+
+ modelData: notif.modelData
+ props: root.props
+ }
+
+ Behavior on x {
+ Anim {
+ duration: Appearance.anim.durations.expressiveDefaultSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
+ }
+ }
+
+ Behavior on y {
+ Anim {
+ duration: Appearance.anim.durations.expressiveDefaultSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
+ }
+ }
+ }
+ }
+}
diff --git a/modules/sidebar/NotifGroup.qml b/modules/sidebar/NotifGroup.qml
index a87deb6..f0b168d 100644
--- a/modules/sidebar/NotifGroup.qml
+++ b/modules/sidebar/NotifGroup.qml
@@ -16,11 +16,17 @@ StyledRect {
required property string modelData
required property Props props
- readonly property list<var> notifs: Notifs.list.filter(notif => notif.appName === modelData).reverse()
+ readonly property list<var> notifs: Notifs.list.filter(n => n.appName === modelData)
+ readonly property int notifCount: notifs.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
readonly property string image: notifs.find(n => n.image.length > 0)?.image ?? ""
readonly property string appIcon: notifs.find(n => n.appIcon.length > 0)?.appIcon ?? ""
readonly property int urgency: notifs.some(n => n.urgency === NotificationUrgency.Critical) ? NotificationUrgency.Critical : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? NotificationUrgency.Normal : NotificationUrgency.Low
+ readonly property int nonAnimHeight: {
+ const headerHeight = header.implicitHeight + (root.expanded ? Math.round(Appearance.spacing.small / 2) : 0);
+ const columnHeight = headerHeight + notifList.nonAnimHeight + column.Layout.topMargin + column.Layout.bottomMargin;
+ return Math.round(Math.max(Config.notifs.sizes.image, columnHeight) + Appearance.padding.normal * 2);
+ }
readonly property bool expanded: props.expandedNotifs.includes(modelData)
function toggleExpand(expand: bool): void {
@@ -32,6 +38,11 @@ StyledRect {
}
}
+ Component.onDestruction: {
+ if (notifCount === 0 && expanded)
+ props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
+ }
+
anchors.left: parent?.left
anchors.right: parent?.right
implicitHeight: content.implicitHeight + Appearance.padding.normal * 2
@@ -133,6 +144,8 @@ StyledRect {
spacing: 0
RowLayout {
+ id: header
+
Layout.bottomMargin: root.expanded ? Math.round(Appearance.spacing.small / 2) : 0
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
@@ -178,7 +191,7 @@ StyledRect {
Layout.leftMargin: Appearance.padding.small / 2
animate: true
- text: root.notifs.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
+ text: root.notifCount
color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : Colours.palette.m3onSurface
font.pointSize: Appearance.font.size.small
}
@@ -198,6 +211,8 @@ StyledRect {
}
NotifGroupList {
+ id: notifList
+
props: root.props
notifs: root.notifs
expanded: root.expanded
diff --git a/modules/sidebar/NotifGroupList.qml b/modules/sidebar/NotifGroupList.qml
index 3c45b0b..162c343 100644
--- a/modules/sidebar/NotifGroupList.qml
+++ b/modules/sidebar/NotifGroupList.qml
@@ -14,16 +14,23 @@ Item {
required property list<var> notifs
required property bool expanded
+ readonly property real nonAnimHeight: {
+ let h = -root.spacing;
+ for (let i = 0; i < repeater.count; i++) {
+ const item = repeater.itemAt(i);
+ if (!item.modelData.closed)
+ h += item.nonAnimHeight + root.spacing;
+ }
+ return h;
+ }
+
readonly property int spacing: Math.round(Appearance.spacing.small / 2)
property bool flag
signal requestToggleExpand(expand: bool)
Layout.fillWidth: true
- implicitHeight: {
- const item = repeater.itemAt(repeater.count - 1);
- return item ? item.y + item.implicitHeight : 0;
- }
+ implicitHeight: nonAnimHeight
Repeater {
id: repeater
@@ -145,4 +152,11 @@ Item {
}
}
}
+
+ Behavior on implicitHeight {
+ Anim {
+ duration: Appearance.anim.durations.expressiveDefaultSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
+ }
+ }
}