1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00
Files
DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml
2025-12-14 13:40:21 -05:00

210 lines
7.0 KiB
QML

import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
DankListView {
id: listView
property var keyboardController: null
property bool keyboardActive: false
property bool autoScrollDisabled: false
property bool isAnimatingExpansion: false
property alias count: listView.count
property alias listContentHeight: listView.contentHeight
clip: true
model: NotificationService.groupedNotifications
spacing: Theme.spacingL
onIsUserScrollingChanged: {
if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) {
autoScrollDisabled = true;
}
}
function enableAutoScroll() {
autoScrollDisabled = false;
}
Timer {
id: positionPreservationTimer
interval: 200
running: keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled && !isAnimatingExpansion
repeat: true
onTriggered: {
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled && !isAnimatingExpansion) {
keyboardController.ensureVisible();
}
}
}
Timer {
id: expansionEnsureVisibleTimer
interval: Theme.mediumDuration + 50
repeat: false
onTriggered: {
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
keyboardController.ensureVisible();
}
}
}
NotificationEmptyState {
visible: listView.count === 0
y: 20
anchors.horizontalCenter: parent.horizontalCenter
}
onModelChanged: {
if (!keyboardController || !keyboardController.keyboardNavigationActive) {
return;
}
keyboardController.rebuildFlatNavigation();
Qt.callLater(() => {
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
keyboardController.ensureVisible();
}
});
}
delegate: Item {
id: delegateRoot
required property var modelData
required property int index
readonly property bool isExpanded: (NotificationService.expandedGroups[modelData && modelData.key] || false)
property real swipeOffset: 0
property bool isDismissing: false
readonly property real dismissThreshold: width * 0.35
width: ListView.view.width
height: isDismissing ? 0 : notificationCard.height
clip: isDismissing
NotificationCard {
id: notificationCard
width: parent.width
x: delegateRoot.swipeOffset
notificationGroup: modelData
keyboardNavigationActive: listView.keyboardActive
opacity: 1 - Math.abs(delegateRoot.swipeOffset) / (delegateRoot.width * 0.5)
onIsAnimatingChanged: {
if (isAnimating) {
listView.isAnimatingExpansion = true;
} else {
Qt.callLater(() => {
let anyAnimating = false;
for (let i = 0; i < listView.count; i++) {
const item = listView.itemAtIndex(i);
if (item && item.children[0] && item.children[0].isAnimating) {
anyAnimating = true;
break;
}
}
listView.isAnimatingExpansion = anyAnimating;
});
}
}
isGroupSelected: {
if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive)
return false;
keyboardController.selectionVersion;
const selection = keyboardController.getCurrentSelection();
return selection.type === "group" && selection.groupIndex === index;
}
selectedNotificationIndex: {
if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive)
return -1;
keyboardController.selectionVersion;
const selection = keyboardController.getCurrentSelection();
return (selection.type === "notification" && selection.groupIndex === index) ? selection.notificationIndex : -1;
}
Behavior on x {
enabled: !swipeDragHandler.active
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
}
}
}
DragHandler {
id: swipeDragHandler
target: null
yAxis.enabled: false
xAxis.enabled: true
onActiveChanged: {
if (active || delegateRoot.isDismissing)
return;
if (Math.abs(delegateRoot.swipeOffset) > delegateRoot.dismissThreshold) {
delegateRoot.isDismissing = true;
delegateRoot.swipeOffset = delegateRoot.swipeOffset > 0 ? delegateRoot.width : -delegateRoot.width;
dismissTimer.start();
} else {
delegateRoot.swipeOffset = 0;
}
}
onTranslationChanged: {
if (delegateRoot.isDismissing)
return;
delegateRoot.swipeOffset = translation.x;
}
}
Timer {
id: dismissTimer
interval: Theme.shortDuration
onTriggered: NotificationService.dismissGroup(delegateRoot.modelData?.key || "")
}
}
Connections {
target: NotificationService
function onGroupedNotificationsChanged() {
if (!keyboardController) {
return;
}
if (keyboardController.isTogglingGroup) {
keyboardController.rebuildFlatNavigation();
return;
}
keyboardController.rebuildFlatNavigation();
if (keyboardController.keyboardNavigationActive) {
Qt.callLater(() => {
if (!autoScrollDisabled) {
keyboardController.ensureVisible();
}
});
}
}
function onExpandedGroupsChanged() {
if (!keyboardController || !keyboardController.keyboardNavigationActive)
return;
expansionEnsureVisibleTimer.restart();
}
function onExpandedMessagesChanged() {
if (!keyboardController || !keyboardController.keyboardNavigationActive)
return;
expansionEnsureVisibleTimer.restart();
}
}
}