From 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 Mon Sep 17 00:00:00 2001 From: AlexanderCurl Date: Sat, 18 Apr 2026 17:46:06 +0100 Subject: Replaced file structures for themes in the correct format --- .../Center/HistoryNotificationCard.qml | 277 ----- .../Center/HistoryNotificationList.qml | 387 ------- .../Center/KeyboardNavigatedNotificationList.qml | 311 ------ .../Notifications/Center/NotificationCard.qml | 1073 -------------------- .../Center/NotificationCenterPopout.qml | 321 ------ .../Center/NotificationEmptyState.qml | 34 - .../Notifications/Center/NotificationHeader.qml | 158 --- .../Center/NotificationKeyboardController.qml | 556 ---------- .../Center/NotificationKeyboardHints.qml | 50 - .../Notifications/Center/NotificationSettings.qml | 449 -------- 10 files changed, 3616 deletions(-) delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center') diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml deleted file mode 100644 index 5e033e5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml +++ /dev/null @@ -1,277 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - required property var historyItem - property bool isSelected: false - property bool keyboardNavigationActive: false - property bool descriptionExpanded: NotificationService.expandedMessages[historyItem?.id ? (historyItem.id + "_hist") : ""] || false - property bool __initialized: false - - Component.onCompleted: { - Qt.callLater(() => { - if (root) - root.__initialized = true; - }); - } - - readonly property bool compactMode: SettingsData.notificationCompactMode - readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding - readonly property real iconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal - readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS - readonly property real collapsedContentHeight: iconSize + cardPadding - readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight - - width: parent ? parent.width : 400 - height: baseCardHeight + contentItem.extraHeight - radius: Theme.cornerRadius - clip: false - readonly property bool shadowsAllowed: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - - ElevationShadow { - id: shadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: root.radius - targetColor: root.color - borderColor: root.border.color - borderWidth: root.border.width - shadowEnabled: root.shadowsAllowed - } - - color: { - if (isSelected && keyboardNavigationActive) - return Theme.primaryPressed; - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (isSelected && keyboardNavigationActive) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5); - if (historyItem.urgency === 2) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05); - } - border.width: { - if (isSelected && keyboardNavigationActive) - return 1.5; - if (historyItem.urgency === 2) - return 2; - return 0; - } - - Behavior on border.color { - enabled: root.__initialized - ColorAnimation { - duration: root.__initialized ? Theme.shortDuration : 0 - easing.type: Theme.standardEasing - } - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - visible: historyItem.urgency === 2 - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { - position: 0.0 - color: Theme.primary - } - GradientStop { - position: 0.02 - color: Theme.primary - } - GradientStop { - position: 0.021 - color: "transparent" - } - } - } - - Item { - id: contentItem - - readonly property real expandedTextHeight: descriptionText.contentHeight - readonly property real twoLineHeight: descriptionText.font.pixelSize * 1.2 * 2 - readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > twoLineHeight + 2) ? (expandedTextHeight - twoLineHeight) : 0 - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - height: collapsedContentHeight + extraHeight - - DankCircularImage { - id: iconContainer - readonly property string rawImage: historyItem.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - - width: iconSize - height: iconSize - anchors.left: parent.left - anchors.top: parent.top - - imageSource: { - if (hasNotificationImage) - return historyItem.image; - if (imageHasSpecialPrefix) - return ""; - const appIcon = historyItem.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - hasImage: hasNotificationImage - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return historyItem.appIcon || iconFromImage || ""; - } - fallbackText: { - const appName = historyItem.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - - Rectangle { - anchors.fill: parent - anchors.margins: -2 - radius: width / 2 - color: "transparent" - border.color: root.color - border.width: 5 - visible: parent.hasImage - antialiasing: true - } - } - - Rectangle { - anchors.left: iconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.bottomMargin: contentSpacing - color: "transparent" - - Column { - width: parent.width - anchors.top: parent.top - spacing: Theme.notificationContentSpacing - - Row { - width: parent.width - spacing: Theme.spacingXS - readonly property real reservedTrailingWidth: historySeparator.implicitWidth + Math.max(historyTimeText.implicitWidth, 72) + spacing - - StyledText { - id: historyTitleText - width: Math.min(implicitWidth, Math.max(0, parent.width - parent.reservedTrailingWidth)) - text: { - let title = historyItem.summary || ""; - const appName = historyItem.appName || ""; - const prefix = appName + " • "; - if (appName && title.toLowerCase().startsWith(prefix.toLowerCase())) { - title = title.substring(prefix.length); - } - return title; - } - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - StyledText { - id: historySeparator - text: (historyTitleText.text.length > 0 && historyTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - StyledText { - id: historyTimeText - text: NotificationService.formatHistoryTime(historyItem.timestamp) - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - visible: text.length > 0 - } - } - - StyledText { - id: descriptionText - property bool hasMoreText: truncated - - text: historyItem.htmlBody || historyItem.body || "" - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: descriptionExpanded ? Text.ElideNone : Text.ElideRight - maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2) - wrapMode: Text.WordWrap - visible: text.length > 0 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) { - const messageId = historyItem?.id ? (historyItem.id + "_hist") : ""; - NotificationService.toggleMessageExpansion(messageId); - } - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - onReleased: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - } - } - } - } - } - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.rightMargin: Theme.spacingL - iconName: "close" - iconSize: compactMode ? 16 : 18 - buttonSize: compactMode ? 24 : 28 - onClicked: NotificationService.removeFromHistory(historyItem.id) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml deleted file mode 100644 index 69fea41..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml +++ /dev/null @@ -1,387 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string selectedFilterKey: "all" - property var keyboardController: null - property bool keyboardActive: false - property int selectedIndex: -1 - property bool showKeyboardHints: false - - function getStartOfDay(date) { - const d = new Date(date); - d.setHours(0, 0, 0, 0); - return d; - } - - function getFilterRange(key) { - const now = new Date(); - const startOfToday = getStartOfDay(now); - const startOfYesterday = new Date(startOfToday.getTime() - 86400000); - - switch (key) { - case "all": - return { - start: null, - end: null - }; - case "1h": - return { - start: new Date(now.getTime() - 3600000), - end: null - }; - case "today": - return { - start: startOfToday, - end: null - }; - case "yesterday": - return { - start: startOfYesterday, - end: startOfToday - }; - case "older": - return { - start: null, - end: getOlderCutoff() - }; - case "7d": - return { - start: new Date(now.getTime() - 7 * 86400000), - end: null - }; - case "30d": - return { - start: new Date(now.getTime() - 30 * 86400000), - end: null - }; - default: - return { - start: null, - end: null - }; - } - } - - function countForFilter(key) { - const range = getFilterRange(key); - if (!range.start && !range.end) - return NotificationService.historyList.length; - return NotificationService.historyList.filter(n => { - const ts = n.timestamp; - if (range.start && ts < range.start.getTime()) - return false; - if (range.end && ts >= range.end.getTime()) - return false; - return true; - }).length; - } - - readonly property var allFilters: [ - { - label: I18n.tr("All", "notification history filter"), - key: "all", - maxDays: 0 - }, - { - label: I18n.tr("Last hour", "notification history filter"), - key: "1h", - maxDays: 1 - }, - { - label: I18n.tr("Today", "notification history filter"), - key: "today", - maxDays: 1 - }, - { - label: I18n.tr("Yesterday", "notification history filter"), - key: "yesterday", - maxDays: 2 - }, - { - label: I18n.tr("7 days", "notification history filter"), - key: "7d", - maxDays: 7 - }, - { - label: I18n.tr("30 days", "notification history filter"), - key: "30d", - maxDays: 30 - }, - { - label: I18n.tr("Older", "notification history filter for content older than other filters"), - key: "older", - maxDays: 0 - } - ] - - function filterRelevantForRetention(filter) { - const retention = SettingsData.notificationHistoryMaxAgeDays; - if (filter.key === "older") { - if (retention === 0) - return true; - return retention > 2 && retention < 7 || retention > 30; - } - if (retention === 0) - return true; - if (filter.maxDays === 0) - return true; - return filter.maxDays <= retention; - } - - function getOlderCutoff() { - const retention = SettingsData.notificationHistoryMaxAgeDays; - const now = new Date(); - if (retention === 0 || retention > 30) - return new Date(now.getTime() - 30 * 86400000); - if (retention >= 7) - return new Date(now.getTime() - 7 * 86400000); - const startOfToday = getStartOfDay(now); - return new Date(startOfToday.getTime() - 86400000); - } - - readonly property var visibleFilters: { - const result = []; - const retention = SettingsData.notificationHistoryMaxAgeDays; - for (let i = 0; i < allFilters.length; i++) { - const f = allFilters[i]; - if (!filterRelevantForRetention(f)) - continue; - const count = countForFilter(f.key); - if (f.key === "all" || count > 0) { - result.push({ - label: f.label, - key: f.key, - count: count - }); - } - } - return result; - } - - onVisibleFiltersChanged: { - let found = false; - for (let i = 0; i < visibleFilters.length; i++) { - if (visibleFilters[i].key === selectedFilterKey) { - found = true; - break; - } - } - if (!found) - selectedFilterKey = "all"; - } - - function getFilteredHistory() { - const range = getFilterRange(selectedFilterKey); - if (!range.start && !range.end) - return NotificationService.historyList; - return NotificationService.historyList.filter(n => { - const ts = n.timestamp; - if (range.start && ts < range.start.getTime()) - return false; - if (range.end && ts >= range.end.getTime()) - return false; - return true; - }); - } - - function getChipIndex() { - for (let i = 0; i < visibleFilters.length; i++) { - if (visibleFilters[i].key === selectedFilterKey) - return i; - } - return 0; - } - - function enableAutoScroll() { - } - - function removeWithScrollPreserve(itemId) { - historyListView.savedY = historyListView.contentY; - NotificationService.removeFromHistory(itemId); - Qt.callLater(() => { - historyListView.forceLayout(); - }); - } - - Column { - anchors.fill: parent - spacing: Theme.spacingS - - DankFilterChips { - id: filterChips - width: parent.width - currentIndex: root.getChipIndex() - showCounts: true - model: root.visibleFilters - onSelectionChanged: index => { - if (index >= 0 && index < root.visibleFilters.length) { - root.selectedFilterKey = root.visibleFilters[index].key; - } - } - } - - DankListView { - id: historyListView - width: parent.width - height: parent.height - filterChips.height - Theme.spacingS - clip: true - spacing: Theme.spacingS - readonly property real horizontalShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1) - readonly property real verticalShadowGutter: Theme.snap(Math.max(Theme.spacingS, 8), 1) - readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1) - topMargin: verticalShadowGutter - bottomMargin: verticalShadowGutter - - model: ScriptModel { - id: historyModel - values: root.getFilteredHistory() - objectProp: "id" - } - - NotificationEmptyState { - visible: historyListView.count === 0 - y: Theme.spacingL - anchors.horizontalCenter: parent.horizontalCenter - } - - delegate: Item { - id: delegateRoot - required property var modelData - required property int index - - property real swipeOffset: 0 - property bool isDismissing: false - readonly property real dismissThreshold: width * 0.35 - property bool __delegateInitialized: false - - Component.onCompleted: { - Qt.callLater(() => { - if (delegateRoot) - delegateRoot.__delegateInitialized = true; - }); - } - - width: ListView.view.width - height: historyCard.height + historyListView.delegateShadowGutter - clip: false - - HistoryNotificationCard { - id: historyCard - width: Math.max(0, parent.width - (historyListView.horizontalShadowGutter * 2)) - y: historyListView.delegateShadowGutter / 2 - x: historyListView.horizontalShadowGutter + delegateRoot.swipeOffset - historyItem: modelData - isSelected: root.keyboardActive && root.selectedIndex === index - keyboardNavigationActive: root.keyboardActive - opacity: 1 - Math.abs(delegateRoot.swipeOffset) / (delegateRoot.width * 0.5) - - Behavior on x { - enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized - NumberAnimation { - duration: Theme.notificationExitDuration - easing.type: Theme.standardEasing - } - } - - Behavior on opacity { - enabled: delegateRoot.__delegateInitialized - NumberAnimation { - duration: delegateRoot.__delegateInitialized ? Theme.notificationExitDuration : 0 - } - } - } - - 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; - root.removeWithScrollPreserve(delegateRoot.modelData?.id || ""); - } else { - delegateRoot.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (delegateRoot.isDismissing) - return; - delegateRoot.swipeOffset = translation.x; - } - } - } - } - } - - function selectNext() { - if (historyModel.values.length === 0) - return; - keyboardActive = true; - selectedIndex = Math.min(selectedIndex + 1, historyModel.values.length - 1); - historyListView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function selectPrevious() { - if (historyModel.values.length === 0) - return; - if (selectedIndex <= 0) { - keyboardActive = false; - selectedIndex = -1; - return; - } - selectedIndex = Math.max(selectedIndex - 1, 0); - historyListView.positionViewAtIndex(selectedIndex, ListView.Contain); - } - - function clearSelected() { - if (selectedIndex < 0 || selectedIndex >= historyModel.values.length) - return; - const item = historyModel.values[selectedIndex]; - NotificationService.removeFromHistory(item.id); - if (historyModel.values.length === 0) { - keyboardActive = false; - selectedIndex = -1; - } else { - selectedIndex = Math.min(selectedIndex, historyModel.values.length - 1); - } - } - - function handleKey(event) { - if (event.key === Qt.Key_Down || event.key === 16777237) { - if (!keyboardActive) { - keyboardActive = true; - selectedIndex = 0; - } else { - selectNext(); - } - event.accepted = true; - } else if (event.key === Qt.Key_Up || event.key === 16777235) { - if (keyboardActive) { - selectPrevious(); - } - event.accepted = true; - } else if (keyboardActive && (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace)) { - clearSelected(); - event.accepted = true; - } else if ((event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) && (event.modifiers & Qt.ShiftModifier)) { - NotificationService.clearHistory(); - keyboardActive = false; - selectedIndex = -1; - event.accepted = true; - } else if (event.key === Qt.Key_F10) { - showKeyboardHints = !showKeyboardHints; - event.accepted = true; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml deleted file mode 100644 index 855163d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml +++ /dev/null @@ -1,311 +0,0 @@ -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 listContentHeight: listView.contentHeight - property real stableContentHeight: 0 - property bool cardAnimateExpansion: true - property bool listInitialized: false - property int swipingCardIndex: -1 - property real swipingCardOffset: 0 - property real __pendingStableHeight: 0 - property real __heightUpdateThreshold: 20 - readonly property real shadowBlurPx: Theme.elevationEnabled ? ((Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined) ? Theme.elevationLevel1.blurPx : 4) : 0 - readonly property real shadowHorizontalGutter: Theme.snap(Math.max(Theme.spacingS, Math.min(32, shadowBlurPx * 1.5 + 6)), 1) - readonly property real shadowVerticalGutter: Theme.snap(Math.max(Theme.spacingXS, 6), 1) - readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1) - - Component.onCompleted: { - Qt.callLater(() => { - if (listView) { - listView.listInitialized = true; - listView.stableContentHeight = listView.contentHeight; - } - }); - } - - Timer { - id: heightUpdateDebounce - interval: Theme.mediumDuration + 20 - repeat: false - onTriggered: { - if (!listView.isAnimatingExpansion && Math.abs(listView.__pendingStableHeight - listView.stableContentHeight) > listView.__heightUpdateThreshold) { - listView.stableContentHeight = listView.__pendingStableHeight; - } - } - } - - onContentHeightChanged: { - if (!isAnimatingExpansion) { - __pendingStableHeight = contentHeight; - if (Math.abs(contentHeight - stableContentHeight) > __heightUpdateThreshold) { - heightUpdateDebounce.restart(); - } else { - stableContentHeight = contentHeight; - } - } - } - - onIsAnimatingExpansionChanged: { - if (isAnimatingExpansion) { - heightUpdateDebounce.stop(); - let delta = 0; - for (let i = 0; i < count; i++) { - const item = itemAtIndex(i); - if (item && item.children[0] && item.children[0].isAnimating) { - const targetDelegateHeight = item.children[0].targetHeight + listView.delegateShadowGutter; - delta += targetDelegateHeight - item.height; - } - } - const targetHeight = contentHeight + delta; - // During expansion, always update immediately without threshold check - stableContentHeight = targetHeight; - } else { - __pendingStableHeight = contentHeight; - heightUpdateDebounce.stop(); - stableContentHeight = __pendingStableHeight; - } - } - - clip: true - model: NotificationService.groupedNotifications - spacing: Theme.spacingL - topMargin: shadowVerticalGutter - bottomMargin: shadowVerticalGutter - - 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 - property bool __delegateInitialized: false - - readonly property bool isAdjacentToSwipe: listView.count >= 2 && listView.swipingCardIndex !== -1 && (index === listView.swipingCardIndex - 1 || index === listView.swipingCardIndex + 1) - readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? listView.swipingCardOffset * 0.10 : 0 - readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(listView.swipingCardOffset) / width * 0.02 : 1.0 - readonly property real swipeFadeStartOffset: width * 0.75 - readonly property real swipeFadeDistance: Math.max(1, width - swipeFadeStartOffset) - - Component.onCompleted: { - Qt.callLater(() => { - if (delegateRoot) - delegateRoot.__delegateInitialized = true; - }); - } - - width: ListView.view.width - height: notificationCard.height + listView.delegateShadowGutter - clip: false - - NotificationCard { - id: notificationCard - width: Math.max(0, parent.width - (listView.shadowHorizontalGutter * 2)) - y: listView.delegateShadowGutter / 2 - x: listView.shadowHorizontalGutter + delegateRoot.swipeOffset + delegateRoot.adjacentSwipeInfluence - listLevelAdjacentScaleInfluence: delegateRoot.adjacentScaleInfluence - listLevelScaleAnimationsEnabled: listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe - notificationGroup: modelData - keyboardNavigationActive: listView.keyboardActive - animateExpansion: listView.cardAnimateExpansion && listView.listInitialized - opacity: { - const swipeAmount = Math.abs(delegateRoot.swipeOffset); - if (swipeAmount <= delegateRoot.swipeFadeStartOffset) - return 1; - const fadeProgress = (swipeAmount - delegateRoot.swipeFadeStartOffset) / delegateRoot.swipeFadeDistance; - return Math.max(0, 1 - fadeProgress); - } - onIsAnimatingChanged: { - if (isAnimating) { - listView.isAnimatingExpansion = true; - } else { - Qt.callLater(() => { - if (!notificationCard || !listView) - return; - 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 && !delegateRoot.isDismissing && (listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe) && listView.listInitialized - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on opacity { - enabled: listView.listInitialized - NumberAnimation { - duration: listView.listInitialized ? Theme.shortDuration : 0 - } - } - } - - DragHandler { - id: swipeDragHandler - target: null - yAxis.enabled: false - xAxis.enabled: true - - onActiveChanged: { - if (active) { - listView.swipingCardIndex = index; - return; - } - listView.swipingCardIndex = -1; - listView.swipingCardOffset = 0; - if (delegateRoot.isDismissing) - return; - if (Math.abs(delegateRoot.swipeOffset) > delegateRoot.dismissThreshold) { - delegateRoot.isDismissing = true; - swipeDismissAnim.to = delegateRoot.swipeOffset > 0 ? delegateRoot.width : -delegateRoot.width; - swipeDismissAnim.start(); - } else { - delegateRoot.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (delegateRoot.isDismissing) - return; - delegateRoot.swipeOffset = translation.x; - listView.swipingCardOffset = translation.x; - } - } - - NumberAnimation { - id: swipeDismissAnim - target: delegateRoot - property: "swipeOffset" - to: 0 - duration: Theme.notificationExitDuration - easing.type: Easing.OutCubic - onStopped: 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(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml deleted file mode 100644 index 7e404df..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml +++ /dev/null @@ -1,1073 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Effects -import Quickshell -import Quickshell.Services.Notifications -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var notificationGroup - property bool expanded: (NotificationService.expandedGroups[notificationGroup && notificationGroup.key] || false) - property bool descriptionExpanded: (NotificationService.expandedMessages[(notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : ""] || false) - property bool userInitiatedExpansion: false - property bool isAnimating: false - property bool animateExpansion: true - - property bool isGroupSelected: false - property int selectedNotificationIndex: -1 - property bool keyboardNavigationActive: false - property int swipingNotificationIndex: -1 - property real swipingNotificationOffset: 0 - property real listLevelAdjacentScaleInfluence: 1.0 - property bool listLevelScaleAnimationsEnabled: true - - readonly property bool compactMode: SettingsData.notificationCompactMode - readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding - readonly property real iconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal - readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS - readonly property real collapsedDismissOffset: 5 - readonly property real badgeSize: compactMode ? 16 : 18 - readonly property real actionButtonHeight: compactMode ? 20 : 24 - readonly property real collapsedContentHeight: Math.max(iconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) - readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing - - width: parent ? parent.width : 400 - height: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight) - readonly property real targetHeight: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight) - radius: Theme.cornerRadius - scale: (cardHoverHandler.hovered ? 1.004 : 1.0) * listLevelAdjacentScaleInfluence - readonly property bool shadowsAllowed: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" - readonly property var shadowElevation: Theme.elevationLevel1 - readonly property real baseShadowBlurPx: (shadowElevation && shadowElevation.blurPx !== undefined) ? shadowElevation.blurPx : 4 - readonly property real hoverShadowBlurBoost: cardHoverHandler.hovered ? Math.min(2, baseShadowBlurPx * 0.25) : 0 - property real shadowBlurPx: shadowsAllowed ? (baseShadowBlurPx + hoverShadowBlurBoost) : 0 - property real shadowOffsetXPx: shadowsAllowed ? Theme.elevationOffsetX(shadowElevation) : 0 - property real shadowOffsetYPx: shadowsAllowed ? (Theme.elevationOffsetY(shadowElevation, 1) + (cardHoverHandler.hovered ? 0.35 : 0)) : 0 - property bool __initialized: false - - Component.onCompleted: { - Qt.callLater(() => { - if (root) - root.__initialized = true; - }); - } - - Behavior on scale { - enabled: listLevelScaleAnimationsEnabled - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowBlurPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowOffsetXPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on shadowOffsetYPx { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.color { - enabled: root.__initialized - ColorAnimation { - duration: root.__initialized ? Theme.shortDuration : 0 - easing.type: Theme.standardEasing - } - } - - color: { - if (isGroupSelected && keyboardNavigationActive) { - return Theme.primaryPressed; - } - if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) { - return Theme.primaryHoverLight; - } - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (isGroupSelected && keyboardNavigationActive) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5); - } - if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2); - } - if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05); - } - border.width: { - if (isGroupSelected && keyboardNavigationActive) { - return 1.5; - } - if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) { - return 1; - } - if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) { - return 2; - } - return 0; - } - clip: false - - HoverHandler { - id: cardHoverHandler - } - - ElevationShadow { - id: shadowLayer - anchors.fill: parent - z: -1 - level: root.shadowElevation - targetRadius: root.radius - targetColor: root.color - borderColor: root.border.color - borderWidth: root.border.width - shadowBlurPx: root.shadowBlurPx - shadowSpreadPx: 0 - shadowOffsetX: root.shadowOffsetXPx - shadowOffsetY: root.shadowOffsetYPx - shadowColor: root.shadowElevation ? Theme.elevationShadowColor(root.shadowElevation) : "transparent" - shadowEnabled: root.shadowsAllowed - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - visible: notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { - position: 0.0 - color: Theme.primary - } - GradientStop { - position: 0.02 - color: Theme.primary - } - GradientStop { - position: 0.021 - color: "transparent" - } - } - opacity: 1.0 - } - - Item { - id: collapsedContent - - readonly property real expandedTextHeight: descriptionText.contentHeight - readonly property real collapsedLineCount: compactMode ? 1 : 2 - readonly property real collapsedLineHeight: Theme.fontSizeSmall * 1.2 * collapsedLineCount - readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > collapsedLineHeight + 2) ? (expandedTextHeight - collapsedLineHeight) : 0 - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - height: collapsedContentHeight + extraHeight - visible: !expanded - - DankCircularImage { - id: iconContainer - readonly property string rawImage: notificationGroup?.latestNotification?.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - - width: iconSize - height: iconSize - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: descriptionExpanded ? Math.max(0, Theme.fontSizeSmall * 1.2 + (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2)) / 2 - iconSize / 2) : Math.max(0, Theme.fontSizeSmall * 1.2 + (textContainer.height - Theme.fontSizeSmall * 1.2) / 2 - iconSize / 2) - - imageSource: { - if (hasNotificationImage) - return notificationGroup.latestNotification.cleanImage; - if (imageHasSpecialPrefix) - return ""; - const appIcon = notificationGroup?.latestNotification?.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - hasImage: hasNotificationImage - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return notificationGroup?.latestNotification?.appIcon || iconFromImage || ""; - } - fallbackText: { - const appName = notificationGroup?.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - - Rectangle { - anchors.fill: parent - anchors.margins: -2 - radius: width / 2 - color: "transparent" - border.color: root.color - border.width: 5 - visible: parent.hasImage - antialiasing: true - } - - Rectangle { - width: badgeSize - height: badgeSize - radius: badgeSize / 2 - color: Theme.primary - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: -2 - anchors.rightMargin: -2 - visible: (notificationGroup?.count || 0) > 1 - - StyledText { - anchors.centerIn: parent - text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString() - color: Theme.primaryText - font.pixelSize: compactMode ? 8 : 9 - font.weight: Font.Bold - } - } - } - - Rectangle { - id: textContainer - - anchors.left: iconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.bottomMargin: contentSpacing - color: "transparent" - - Column { - width: parent.width - anchors.top: parent.top - spacing: Theme.notificationContentSpacing - - Row { - id: collapsedHeaderRow - width: parent.width - spacing: Theme.spacingXS - visible: (collapsedHeaderAppNameText.text.length > 0 || collapsedHeaderTimeText.text.length > 0) - - StyledText { - id: collapsedHeaderAppNameText - text: notificationGroup?.appName || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, parent.width - collapsedHeaderSeparator.implicitWidth - collapsedHeaderTimeText.implicitWidth - parent.spacing * 2) - } - - StyledText { - id: collapsedHeaderSeparator - text: (collapsedHeaderAppNameText.text.length > 0 && collapsedHeaderTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - - StyledText { - id: collapsedHeaderTimeText - text: notificationGroup?.latestNotification?.timeStr || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - } - - StyledText { - id: collapsedTitleText - width: parent.width - text: notificationGroup?.latestNotification?.summary || "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - id: descriptionText - property string fullText: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.htmlBody) || "" - property bool hasMoreText: truncated - - text: fullText - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: Text.ElideRight - maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2) - wrapMode: Text.WordWrap - visible: text.length > 0 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) { - root.userInitiatedExpansion = true; - const messageId = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : ""; - NotificationService.toggleMessageExpansion(messageId); - Qt.callLater(() => { - if (root && !root.isAnimating) - root.userInitiatedExpansion = false; - }); - } - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - onReleased: mouse => { - if (parent.hoveredLink) - mouse.accepted = false; - } - } - } - } - } - } - - Column { - id: expandedContent - objectName: "expandedContent" - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: compactMode ? Theme.spacingXS : Theme.spacingS - visible: expanded - - Item { - width: parent.width - height: compactMode ? 32 : 40 - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: notificationGroup?.appName || "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - } - - Rectangle { - width: badgeSize - height: badgeSize - radius: badgeSize / 2 - color: Theme.primary - visible: (notificationGroup?.count || 0) > 1 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - anchors.centerIn: parent - text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString() - color: Theme.primaryText - font.pixelSize: compactMode ? 8 : 9 - font.weight: Font.Bold - } - } - } - } - - Column { - width: parent.width - spacing: compactMode ? Theme.spacingS : Theme.spacingL - - Repeater { - id: notificationRepeater - objectName: "notificationRepeater" - model: notificationGroup?.notifications?.slice(0, 10) || [] - - delegate: Item { - id: expandedDelegateWrapper - required property var modelData - required property int index - readonly property bool messageExpanded: NotificationService.expandedMessages[modelData?.notification?.id] || false - readonly property bool isSelected: root.selectedNotificationIndex === index - readonly property bool actionsVisible: true - readonly property real expandedIconSize: compactMode ? Theme.notificationExpandedIconSizeCompact : Theme.notificationExpandedIconSizeNormal - - HoverHandler { - id: expandedDelegateHoverHandler - } - readonly property real expandedItemPadding: compactMode ? Theme.spacingS : Theme.spacingM - readonly property real expandedBaseHeight: expandedItemPadding * 2 + Math.max(expandedIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * 2) + actionButtonHeight + contentSpacing * 2 - property bool __delegateInitialized: false - property real swipeOffset: 0 - property bool isDismissing: false - readonly property real dismissThreshold: width * 0.35 - - Component.onCompleted: { - Qt.callLater(() => { - if (expandedDelegateWrapper) - expandedDelegateWrapper.__delegateInitialized = true; - }); - } - - width: parent.width - height: delegateRect.height - clip: true - - Rectangle { - id: delegateRect - width: parent.width - - readonly property bool isAdjacentToSwipe: root.swipingNotificationIndex !== -1 && (expandedDelegateWrapper.index === root.swipingNotificationIndex - 1 || expandedDelegateWrapper.index === root.swipingNotificationIndex + 1) - readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? root.swipingNotificationOffset * 0.10 : 0 - readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(root.swipingNotificationOffset) / width * 0.02 : 1.0 - - x: expandedDelegateWrapper.swipeOffset + adjacentSwipeInfluence - scale: adjacentScaleInfluence - transformOrigin: Item.Center - - Behavior on x { - enabled: !expandedSwipeHandler.active && !expandedDelegateWrapper.isDismissing - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on scale { - enabled: !expandedSwipeHandler.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - height: { - if (!messageExpanded) - return expandedBaseHeight; - const twoLineHeight = bodyText.font.pixelSize * 1.2 * 2; - if (bodyText.implicitHeight > twoLineHeight + 2) - return expandedBaseHeight + bodyText.implicitHeight - twoLineHeight; - return expandedBaseHeight; - } - radius: Theme.cornerRadius - color: isSelected ? Theme.primaryPressed : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 1 - - Behavior on border.color { - enabled: __delegateInitialized - ColorAnimation { - duration: __delegateInitialized ? Theme.shortDuration : 0 - easing.type: Theme.standardEasing - } - } - - Behavior on height { - enabled: false - } - - Item { - anchors.fill: parent - anchors.margins: compactMode ? Theme.spacingS : Theme.spacingM - anchors.bottomMargin: contentSpacing - - DankCircularImage { - id: messageIcon - - readonly property string rawImage: modelData?.image || "" - readonly property string iconFromImage: { - if (rawImage.startsWith("image://icon/")) - return rawImage.substring(13); - return ""; - } - readonly property bool imageHasSpecialPrefix: { - const icon = iconFromImage; - return icon.startsWith("material:") || icon.startsWith("svg:") || icon.startsWith("unicode:") || icon.startsWith("image:"); - } - readonly property bool hasNotificationImage: rawImage !== "" && !rawImage.startsWith("image://icon/") - - width: expandedIconSize - height: expandedIconSize - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: Theme.fontSizeSmall * 1.2 + (compactMode ? Theme.spacingXS : Theme.spacingS) - - imageSource: { - if (hasNotificationImage) - return modelData.cleanImage; - if (imageHasSpecialPrefix) - return ""; - const appIcon = modelData?.appIcon; - if (!appIcon) - return iconFromImage ? Paths.resolveIconUrl(iconFromImage) : ""; - if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://") || appIcon.includes("/")) - return appIcon; - if (appIcon.startsWith("material:") || appIcon.startsWith("svg:") || appIcon.startsWith("unicode:") || appIcon.startsWith("image:")) - return ""; - return Paths.resolveIconPath(appIcon); - } - - fallbackIcon: { - if (imageHasSpecialPrefix) - return iconFromImage; - return modelData?.appIcon || iconFromImage || ""; - } - - fallbackText: { - const appName = modelData?.appName || "?"; - return appName.charAt(0).toUpperCase(); - } - } - - Item { - anchors.left: messageIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.top: parent.top - anchors.bottom: parent.bottom - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: buttonArea.top - anchors.bottomMargin: contentSpacing - spacing: Theme.notificationContentSpacing - - Row { - id: expandedDelegateHeaderRow - width: parent.width - spacing: Theme.spacingXS - visible: (expandedDelegateHeaderAppNameText.text.length > 0 || expandedDelegateHeaderTimeText.text.length > 0) - - StyledText { - id: expandedDelegateHeaderAppNameText - text: modelData?.appName || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, parent.width - expandedDelegateHeaderSeparator.implicitWidth - expandedDelegateHeaderTimeText.implicitWidth - parent.spacing * 2) - } - - StyledText { - id: expandedDelegateHeaderSeparator - text: (expandedDelegateHeaderAppNameText.text.length > 0 && expandedDelegateHeaderTimeText.text.length > 0) ? " • " : "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - - StyledText { - id: expandedDelegateHeaderTimeText - text: modelData?.timeStr || "" - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Normal - } - } - - StyledText { - id: expandedDelegateTitleText - width: parent.width - text: modelData?.summary || "" - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - id: bodyText - property bool hasMoreText: truncated - - text: modelData?.htmlBody || "" - color: Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - width: parent.width - elide: messageExpanded ? Text.ElideNone : Text.ElideRight - maximumLineCount: messageExpanded ? -1 : 2 - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - visible: text.length > 0 - linkColor: Theme.primary - onLinkActivated: link => Qt.openUrlExternally(link) - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || messageExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onClicked: mouse => { - if (!parent.hoveredLink && (bodyText.hasMoreText || messageExpanded)) { - root.userInitiatedExpansion = true; - NotificationService.toggleMessageExpansion(modelData?.notification?.id || ""); - Qt.callLater(() => { - if (root && !root.isAnimating) - root.userInitiatedExpansion = false; - }); - } - } - - propagateComposedEvents: true - onPressed: mouse => { - if (parent.hoveredLink) { - mouse.accepted = false; - } - } - onReleased: mouse => { - if (parent.hoveredLink) { - mouse.accepted = false; - } - } - } - } - } - - Item { - id: buttonArea - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: actionButtonHeight + contentSpacing - - Row { - visible: expandedDelegateWrapper.actionsVisible - opacity: visible ? 1 : 0 - anchors.right: parent.right - anchors.bottom: parent.bottom - spacing: contentSpacing - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Repeater { - model: modelData?.actions || [] - - Rectangle { - property bool isHovered: false - - width: Math.max(expandedActionText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: expandedActionText - text: { - const baseText = modelData.text || I18n.tr("Open"); - if (keyboardNavigationActive && (isGroupSelected || selectedNotificationIndex >= 0)) - return `${baseText} (${index + 1})`; - return baseText; - } - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - elide: Text.ElideRight - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: { - if (modelData && modelData.invoke) - modelData.invoke(); - } - } - } - } - - Rectangle { - id: expandedDelegateDismissBtn - property bool isHovered: false - - visible: expandedDelegateWrapper.actionsVisible - opacity: visible ? 1 : 0 - width: Math.max(expandedClearText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - StyledText { - id: expandedClearText - text: I18n.tr("Dismiss") - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: NotificationService.dismissNotification(modelData) - } - } - } - } - } - } - } - - DragHandler { - id: expandedSwipeHandler - target: null - xAxis.enabled: true - yAxis.enabled: false - grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType - - onActiveChanged: { - if (active) { - root.swipingNotificationIndex = expandedDelegateWrapper.index; - } else { - root.swipingNotificationIndex = -1; - root.swipingNotificationOffset = 0; - } - if (active || expandedDelegateWrapper.isDismissing) - return; - if (Math.abs(expandedDelegateWrapper.swipeOffset) > expandedDelegateWrapper.dismissThreshold) { - expandedDelegateWrapper.isDismissing = true; - expandedSwipeDismissAnim.start(); - } else { - expandedDelegateWrapper.swipeOffset = 0; - } - } - - onTranslationChanged: { - if (expandedDelegateWrapper.isDismissing) - return; - expandedDelegateWrapper.swipeOffset = translation.x; - root.swipingNotificationOffset = translation.x; - } - } - - NumberAnimation { - id: expandedSwipeDismissAnim - target: expandedDelegateWrapper - property: "swipeOffset" - to: expandedDelegateWrapper.swipeOffset > 0 ? expandedDelegateWrapper.width : -expandedDelegateWrapper.width - duration: Theme.notificationExitDuration - easing.type: Easing.OutCubic - onStopped: NotificationService.dismissNotification(modelData) - } - } - } - } - } - - Row { - visible: !expanded - anchors.right: clearButton.visible ? clearButton.left : parent.right - anchors.rightMargin: clearButton.visible ? contentSpacing : Theme.spacingL - anchors.top: collapsedContent.bottom - anchors.topMargin: contentSpacing + collapsedDismissOffset - spacing: contentSpacing - - Repeater { - model: notificationGroup?.latestNotification?.actions || [] - - Rectangle { - property bool isHovered: false - - width: Math.max(collapsedActionText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: collapsedActionText - text: { - const baseText = modelData.text || I18n.tr("Open"); - if (keyboardNavigationActive && isGroupSelected) { - return `${baseText} (${index + 1})`; - } - return baseText; - } - color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - elide: Text.ElideRight - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: parent.isHovered = true - onExited: parent.isHovered = false - onClicked: { - if (modelData && modelData.invoke) { - modelData.invoke(); - } - } - } - } - } - } - - Rectangle { - id: clearButton - - property bool isHovered: false - readonly property int actionCount: (notificationGroup?.latestNotification?.actions || []).length - - visible: !expanded && actionCount < 3 - anchors.right: parent.right - anchors.rightMargin: Theme.spacingL - anchors.top: collapsedContent.bottom - anchors.topMargin: contentSpacing + collapsedDismissOffset - width: Math.max(collapsedClearText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth) - height: actionButtonHeight - radius: Theme.notificationButtonCornerRadius - color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" - - StyledText { - id: collapsedClearText - text: I18n.tr("Dismiss") - color: clearButton.isHovered ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: clearButton.isHovered = true - onExited: clearButton.isHovered = false - onClicked: NotificationService.dismissGroup(notificationGroup?.key || "") - } - } - - MouseArea { - anchors.fill: parent - visible: !expanded && (notificationGroup?.count || 0) > 1 && !descriptionExpanded - cursorShape: Qt.PointingHandCursor - onClicked: { - root.userInitiatedExpansion = true; - NotificationService.toggleGroupExpansion(notificationGroup?.key || ""); - } - z: -1 - } - - Item { - id: fixedControls - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: cardPadding - anchors.rightMargin: Theme.spacingL - width: compactMode ? 52 : 60 - height: compactMode ? 24 : 28 - - DankActionButton { - anchors.left: parent.left - anchors.top: parent.top - visible: (notificationGroup?.count || 0) > 1 - iconName: expanded ? "expand_less" : "expand_more" - iconSize: compactMode ? 16 : 18 - buttonSize: compactMode ? 24 : 28 - onClicked: { - root.userInitiatedExpansion = true; - NotificationService.toggleGroupExpansion(notificationGroup?.key || ""); - } - } - - DankActionButton { - anchors.right: parent.right - anchors.top: parent.top - iconName: "close" - iconSize: compactMode ? 16 : 18 - buttonSize: compactMode ? 24 : 28 - onClicked: NotificationService.dismissGroup(notificationGroup?.key || "") - } - } - - Behavior on height { - enabled: root.__initialized && root.userInitiatedExpansion && root.animateExpansion - NumberAnimation { - duration: root.expanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasized - onRunningChanged: { - if (running) { - root.isAnimating = true; - } else { - root.isAnimating = false; - root.userInitiatedExpansion = false; - } - } - } - } - - Menu { - id: notificationCardContextMenu - width: 220 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - id: setNotificationRulesItem - text: I18n.tr("Set notification rules") - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const appName = notificationGroup?.appName || ""; - const desktopEntry = notificationGroup?.latestNotification?.desktopEntry || ""; - SettingsData.addNotificationRuleForNotification(appName, desktopEntry); - PopoutService.openSettingsWithTab("notifications"); - } - } - - MenuItem { - id: muteUnmuteItem - readonly property bool isMuted: SettingsData.isAppMuted(notificationGroup?.appName || "", notificationGroup?.latestNotification?.desktopEntry || "") - text: isMuted ? I18n.tr("Unmute popups for %1").arg(notificationGroup?.appName || I18n.tr("this app")) : I18n.tr("Mute popups for %1").arg(notificationGroup?.appName || I18n.tr("this app")) - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const appName = notificationGroup?.appName || ""; - const desktopEntry = notificationGroup?.latestNotification?.desktopEntry || ""; - if (isMuted) { - SettingsData.removeMuteRuleForApp(appName, desktopEntry); - } else { - SettingsData.addMuteRuleForApp(appName, desktopEntry); - NotificationService.dismissGroup(notificationGroup?.key || ""); - } - } - } - - MenuItem { - text: I18n.tr("Dismiss") - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: NotificationService.dismissGroup(notificationGroup?.key || "") - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - z: -2 - onClicked: mouse => { - if (mouse.button === Qt.RightButton && notificationGroup) { - notificationCardContextMenu.popup(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml deleted file mode 100644 index b7b616b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml +++ /dev/null @@ -1,321 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:notification-center-popout" - fullHeightSurface: true - - property bool notificationHistoryVisible: false - property var triggerScreen: null - property real stablePopupHeight: 400 - property real _lastAlignedContentHeight: -1 - property bool _pendingSizedOpen: false - - function updateStablePopupHeight() { - const item = contentLoader.item; - if (item && !root.shouldBeVisible) { - const notificationList = findChild(item, "notificationList"); - if (notificationList && typeof notificationList.forceLayout === "function") { - notificationList.forceLayout(); - } - } - const target = item ? Theme.px(item.implicitHeight, dpr) : 400; - if (Math.abs(target - _lastAlignedContentHeight) < 0.5) - return; - _lastAlignedContentHeight = target; - stablePopupHeight = target; - } - - NotificationKeyboardController { - id: keyboardController - listView: null - isOpen: root.shouldBeVisible - onClose: () => { - notificationHistoryVisible = false; - } - } - - popupWidth: triggerScreen ? Math.min(500, Math.max(380, triggerScreen.width - 48)) : 400 - popupHeight: stablePopupHeight - positioning: "" - animationScaleCollapsed: 0.94 - animationOffset: 0 - suspendShadowWhileResizing: false - - screen: triggerScreen - - function toggle() { - notificationHistoryVisible = !notificationHistoryVisible; - } - - function openSized() { - if (!notificationHistoryVisible) - return; - - primeContent(); - if (contentLoader.item) { - updateStablePopupHeight(); - _pendingSizedOpen = false; - Qt.callLater(() => { - if (!notificationHistoryVisible) - return; - updateStablePopupHeight(); - open(); - clearPrimedContent(); - }); - return; - } - - _pendingSizedOpen = true; - } - - onBackgroundClicked: { - notificationHistoryVisible = false; - } - - onNotificationHistoryVisibleChanged: { - if (notificationHistoryVisible) { - openSized(); - } else { - _pendingSizedOpen = false; - clearPrimedContent(); - close(); - } - } - - function setupKeyboardNavigation() { - if (!contentLoader.item) - return; - contentLoader.item.externalKeyboardController = keyboardController; - - const notificationList = findChild(contentLoader.item, "notificationList"); - const notificationHeader = findChild(contentLoader.item, "notificationHeader"); - - if (notificationList) { - keyboardController.listView = notificationList; - notificationList.keyboardController = keyboardController; - } - if (notificationHeader) { - notificationHeader.keyboardController = keyboardController; - } - - keyboardController.reset(); - keyboardController.rebuildFlatNavigation(); - } - - Connections { - target: contentLoader - function onLoaded() { - root.updateStablePopupHeight(); - if (root._pendingSizedOpen && root.notificationHistoryVisible) { - Qt.callLater(() => { - if (!root._pendingSizedOpen || !root.notificationHistoryVisible) - return; - root.updateStablePopupHeight(); - root._pendingSizedOpen = false; - root.open(); - root.clearPrimedContent(); - }); - return; - } - if (root.shouldBeVisible) - Qt.callLater(root.setupKeyboardNavigation); - } - } - - Connections { - target: contentLoader.item - function onImplicitHeightChanged() { - root.updateStablePopupHeight(); - } - } - - onDprChanged: updateStablePopupHeight() - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - NotificationService.onOverlayOpen(); - updateStablePopupHeight(); - if (contentLoader.item) - Qt.callLater(setupKeyboardNavigation); - } else { - NotificationService.onOverlayClose(); - keyboardController.keyboardNavigationActive = false; - NotificationService.expandedGroups = {}; - NotificationService.expandedMessages = {}; - } - } - - function findChild(parent, objectName) { - if (parent.objectName === objectName) { - return parent; - } - for (let i = 0; i < parent.children.length; i++) { - const child = parent.children[i]; - const result = findChild(child, objectName); - if (result) { - return result; - } - } - return null; - } - - content: Component { - Rectangle { - id: notificationContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var externalKeyboardController: null - property real cachedHeaderHeight: 32 - readonly property real settingsMaxHeight: { - const screenH = root.screen ? root.screen.height : 1080; - const maxPopupH = screenH * 0.8; - const overhead = cachedHeaderHeight + Theme.spacingL * 2 + Theme.spacingM * 2; - return Math.max(200, maxPopupH - overhead - 150); - } - implicitHeight: { - let baseHeight = Theme.spacingL * 2; - baseHeight += cachedHeaderHeight; - baseHeight += Theme.spacingM * 2; - - const settingsHeight = notificationSettings.expanded ? Math.min(notificationSettings.naturalContentHeight, settingsMaxHeight) : 0; - const currentListHeight = root.shouldBeVisible ? notificationList.stableContentHeight : notificationList.listContentHeight; - let listHeight = notificationHeader.currentTab === 0 ? currentListHeight : Math.max(200, NotificationService.historyList.length * 80); - if (notificationHeader.currentTab === 0 && NotificationService.groupedNotifications.length === 0) { - listHeight = 200; - } - if (notificationHeader.currentTab === 1 && NotificationService.historyList.length === 0) { - listHeight = 200; - } - - const maxContentArea = 600; - const availableListSpace = Math.max(200, maxContentArea - settingsHeight); - - baseHeight += settingsHeight; - baseHeight += Math.min(listHeight, availableListSpace); - - const maxHeight = root.screen ? root.screen.height * 0.8 : Screen.height * 0.8; - return Math.max(300, Math.min(baseHeight, maxHeight)); - } - - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - notificationHistoryVisible = false; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Left) { - if (notificationHeader.currentTab > 0) { - notificationHeader.currentTab = 0; - event.accepted = true; - } - return; - } - - if (event.key === Qt.Key_Right) { - if (notificationHeader.currentTab === 0 && SettingsData.notificationHistoryEnabled) { - notificationHeader.currentTab = 1; - event.accepted = true; - } - return; - } - if (notificationHeader.currentTab === 1) { - historyList.handleKey(event); - return; - } - if (externalKeyboardController) { - externalKeyboardController.handleKey(event); - } - } - - Connections { - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(() => { - notificationContent.forceActiveFocus(); - }); - } else { - notificationContent.focus = false; - } - } - target: root - } - - FocusScope { - id: contentColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - focus: true - - Column { - id: contentColumnInner - anchors.fill: parent - spacing: Theme.spacingM - - NotificationHeader { - id: notificationHeader - objectName: "notificationHeader" - onHeightChanged: notificationContent.cachedHeaderHeight = height - } - - NotificationSettings { - id: notificationSettings - expanded: notificationHeader.showSettings - maxAllowedHeight: notificationContent.settingsMaxHeight - } - - Item { - visible: notificationHeader.currentTab === 0 - width: parent.width - height: parent.height - notificationContent.cachedHeaderHeight - notificationSettings.height - contentColumnInner.spacing * 2 - - KeyboardNavigatedNotificationList { - id: notificationList - objectName: "notificationList" - anchors.fill: parent - anchors.leftMargin: -shadowHorizontalGutter - anchors.rightMargin: -shadowHorizontalGutter - anchors.topMargin: -(shadowVerticalGutter + delegateShadowGutter / 2) - anchors.bottomMargin: -(shadowVerticalGutter + delegateShadowGutter / 2) - cardAnimateExpansion: true - } - } - - HistoryNotificationList { - id: historyList - visible: notificationHeader.currentTab === 1 - width: parent.width - height: parent.height - notificationContent.cachedHeaderHeight - notificationSettings.height - contentColumnInner.spacing * 2 - } - } - } - - NotificationKeyboardHints { - id: keyboardHints - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - showHints: notificationHeader.currentTab === 0 ? (externalKeyboardController && externalKeyboardController.showKeyboardHints) || false : historyList.showKeyboardHints - z: 200 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml deleted file mode 100644 index da8746e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml +++ /dev/null @@ -1,34 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - width: parent.width - height: 200 - visible: NotificationService.notifications.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - width: parent.width * 0.8 - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: "notifications_none" - size: Theme.iconSizeLarge + 16 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3) - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: I18n.tr("Nothing to see here") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3) - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml deleted file mode 100644 index 201e716..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml +++ /dev/null @@ -1,158 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property var keyboardController: null - property bool showSettings: false - property int currentTab: 0 - - onCurrentTabChanged: { - if (currentTab === 1 && !SettingsData.notificationHistoryEnabled) - currentTab = 0; - } - - Connections { - target: SettingsData - function onNotificationHistoryEnabledChanged() { - if (!SettingsData.notificationHistoryEnabled) - root.currentTab = 0; - } - } - - width: parent.width - height: headerColumn.implicitHeight - - DankTooltipV2 { - id: sharedTooltip - } - - Column { - id: headerColumn - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: Math.max(titleRow.implicitHeight, actionsRow.implicitHeight) - - Row { - id: titleRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Notifications") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - DankActionButton { - id: doNotDisturbButton - iconName: SessionData.doNotDisturb ? "notifications_off" : "notifications" - iconColor: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText - buttonSize: Theme.iconSize + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - onClicked: SessionData.setDoNotDisturb(!SessionData.doNotDisturb) - onEntered: sharedTooltip.show(I18n.tr("Do Not Disturb"), doNotDisturbButton, 0, 0, "bottom") - onExited: sharedTooltip.hide() - } - } - - Row { - id: actionsRow - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - id: helpButton - iconName: "info" - iconColor: (keyboardController && keyboardController.showKeyboardHints) ? Theme.primary : Theme.surfaceText - buttonSize: Theme.iconSize + Theme.spacingS - visible: keyboardController !== null - anchors.verticalCenter: parent.verticalCenter - onClicked: { - if (keyboardController) - keyboardController.showKeyboardHints = !keyboardController.showKeyboardHints; - } - } - - DankActionButton { - id: settingsButton - iconName: "settings" - iconColor: root.showSettings ? Theme.primary : Theme.surfaceText - buttonSize: Theme.iconSize + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - onClicked: root.showSettings = !root.showSettings - } - - Rectangle { - id: clearAllButton - width: clearButtonContent.implicitWidth + Theme.spacingM * 2 - height: Theme.iconSize + Theme.spacingS - radius: Theme.cornerRadius - visible: root.currentTab === 0 ? NotificationService.notifications.length > 0 : NotificationService.historyList.length > 0 - color: clearArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Row { - id: clearButtonContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "delete_sweep" - size: Theme.iconSizeSmall - color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Clear") - font.pixelSize: Theme.fontSizeSmall - color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: clearArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.currentTab === 0) { - NotificationService.clearAllNotifications(); - } else { - NotificationService.clearHistory(); - } - } - } - } - } - } - - DankButtonGroup { - id: tabGroup - width: parent.width - currentIndex: root.currentTab - buttonHeight: 32 - buttonPadding: Theme.spacingM - checkEnabled: false - textSize: Theme.fontSizeSmall - visible: SettingsData.notificationHistoryEnabled - model: [I18n.tr("Current", "notification center tab") + " (" + NotificationService.notifications.length + ")", I18n.tr("History", "notification center tab") + " (" + NotificationService.historyList.length + ")"] - onSelectionChanged: (index, selected) => { - if (selected) - root.currentTab = index; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml deleted file mode 100644 index eda12c0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml +++ /dev/null @@ -1,556 +0,0 @@ -import QtQuick -import qs.Services - -QtObject { - id: controller - - property var listView: null - property bool isOpen: false - property var onClose: null - - property int selectionVersion: 0 - - property bool keyboardNavigationActive: false - property int selectedFlatIndex: 0 - property var flatNavigation: [] - property bool showKeyboardHints: false - - property string selectedNotificationId: "" - property string selectedGroupKey: "" - property string selectedItemType: "" - property bool isTogglingGroup: false - property bool isRebuilding: false - - function rebuildFlatNavigation() { - isRebuilding = true; - - const nav = []; - const groups = NotificationService.groupedNotifications; - - for (var i = 0; i < groups.length; i++) { - const group = groups[i]; - const isExpanded = NotificationService.expandedGroups[group.key] || false; - - nav.push({ - "type": "group", - "groupIndex": i, - "notificationIndex": -1, - "groupKey": group.key, - "notificationId": "" - }); - - if (isExpanded) { - const notifications = group.notifications || []; - const maxNotifications = Math.min(notifications.length, 10); - for (var j = 0; j < maxNotifications; j++) { - const notifId = String(notifications[j] && notifications[j].notification && notifications[j].notification.id ? notifications[j].notification.id : ""); - nav.push({ - "type": "notification", - "groupIndex": i, - "notificationIndex": j, - "groupKey": group.key, - "notificationId": notifId - }); - } - } - } - - flatNavigation = nav; - updateSelectedIndexFromId(); - isRebuilding = false; - } - - function updateSelectedIndexFromId() { - if (!keyboardNavigationActive) { - return; - } - - for (var i = 0; i < flatNavigation.length; i++) { - const item = flatNavigation[i]; - - if (selectedItemType === "group" && item.type === "group" && item.groupKey === selectedGroupKey) { - selectedFlatIndex = i; - selectionVersion++; // Trigger UI update - return; - } else if (selectedItemType === "notification" && item.type === "notification" && String(item.notificationId) === String(selectedNotificationId)) { - selectedFlatIndex = i; - selectionVersion++; // Trigger UI update - return; - } - } - - // If not found, try to find the same group but select the group header instead - if (selectedItemType === "notification") { - for (var j = 0; j < flatNavigation.length; j++) { - const groupItem = flatNavigation[j]; - if (groupItem.type === "group" && groupItem.groupKey === selectedGroupKey) { - selectedFlatIndex = j; - selectedItemType = "group"; - selectedNotificationId = ""; - selectionVersion++; // Trigger UI update - return; - } - } - } - - // If still not found, clamp to valid range and update - if (flatNavigation.length > 0) { - selectedFlatIndex = Math.min(selectedFlatIndex, flatNavigation.length - 1); - selectedFlatIndex = Math.max(selectedFlatIndex, 0); - updateSelectedIdFromIndex(); - selectionVersion++; // Trigger UI update - } - } - - function updateSelectedIdFromIndex() { - if (selectedFlatIndex >= 0 && selectedFlatIndex < flatNavigation.length) { - const item = flatNavigation[selectedFlatIndex]; - selectedItemType = item.type; - selectedGroupKey = item.groupKey; - selectedNotificationId = item.notificationId; - } - } - - function reset() { - selectedFlatIndex = 0; - keyboardNavigationActive = false; - showKeyboardHints = false; - // Reset keyboardActive when modal is reset - if (listView) { - listView.keyboardActive = false; - } - rebuildFlatNavigation(); - } - - function selectNext() { - keyboardNavigationActive = true; - if (flatNavigation.length === 0) - return; - - // Re-enable auto-scrolling when arrow keys are used - if (listView && listView.enableAutoScroll) { - listView.enableAutoScroll(); - } - - selectedFlatIndex = Math.min(selectedFlatIndex + 1, flatNavigation.length - 1); - updateSelectedIdFromIndex(); - selectionVersion++; - ensureVisible(); - } - - function selectNextWrapping() { - keyboardNavigationActive = true; - if (flatNavigation.length === 0) - return; - - // Re-enable auto-scrolling when arrow keys are used - if (listView && listView.enableAutoScroll) { - listView.enableAutoScroll(); - } - - selectedFlatIndex = (selectedFlatIndex + 1) % flatNavigation.length; - updateSelectedIdFromIndex(); - selectionVersion++; - ensureVisible(); - } - - function selectPrevious() { - keyboardNavigationActive = true; - if (flatNavigation.length === 0) - return; - - // Re-enable auto-scrolling when arrow keys are used - if (listView && listView.enableAutoScroll) { - listView.enableAutoScroll(); - } - - selectedFlatIndex = Math.max(selectedFlatIndex - 1, 0); - updateSelectedIdFromIndex(); - selectionVersion++; - ensureVisible(); - } - - function toggleGroupExpanded() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - - // Prevent expanding groups with < 2 notifications - const notificationCount = group.notifications ? group.notifications.length : 0; - if (notificationCount < 2) - return; - const wasExpanded = NotificationService.expandedGroups[group.key] || false; - const groupIndex = currentItem.groupIndex; - - isTogglingGroup = true; - NotificationService.toggleGroupExpansion(group.key); - rebuildFlatNavigation(); - - // Smart selection after toggle - if (!wasExpanded) { - // Just expanded - move to first notification in the group - for (var i = 0; i < flatNavigation.length; i++) { - if (flatNavigation[i].type === "notification" && flatNavigation[i].groupIndex === groupIndex) { - selectedFlatIndex = i; - break; - } - } - } else { - // Just collapsed - stay on the group header - for (var i = 0; i < flatNavigation.length; i++) { - if (flatNavigation[i].type === "group" && flatNavigation[i].groupIndex === groupIndex) { - selectedFlatIndex = i; - break; - } - } - } - - isTogglingGroup = false; - } - - function handleEnterKey() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - if (currentItem.type === "group") { - const notificationCount = group.notifications ? group.notifications.length : 0; - if (notificationCount >= 2) { - toggleGroupExpanded(); - } else { - executeAction(0); - } - } else if (currentItem.type === "notification") { - executeAction(0); - } - } - - function toggleTextExpanded() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - let messageId = ""; - - if (currentItem.type === "group") { - messageId = group.latestNotification?.notification?.id + "_desc"; - } else if (currentItem.type === "notification" && currentItem.notificationIndex >= 0 && currentItem.notificationIndex < group.notifications.length) { - messageId = group.notifications[currentItem.notificationIndex]?.notification?.id + "_desc"; - } - - if (messageId) { - NotificationService.toggleMessageExpansion(messageId); - } - } - - function executeAction(actionIndex) { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - let actions = []; - - if (currentItem.type === "group") { - actions = group.latestNotification?.actions || []; - } else if (currentItem.type === "notification" && currentItem.notificationIndex >= 0 && currentItem.notificationIndex < group.notifications.length) { - actions = group.notifications[currentItem.notificationIndex]?.actions || []; - } - - if (actionIndex >= 0 && actionIndex < actions.length) { - const action = actions[actionIndex]; - if (action.invoke) { - action.invoke(); - if (onClose) - onClose(); - } - } - } - - function clearSelected() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - const groups = NotificationService.groupedNotifications; - const group = groups[currentItem.groupIndex]; - if (!group) - return; - if (currentItem.type === "group") { - NotificationService.dismissGroup(group.key); - } else if (currentItem.type === "notification") { - const notification = group.notifications[currentItem.notificationIndex]; - NotificationService.dismissNotification(notification); - } - - rebuildFlatNavigation(); - - if (flatNavigation.length === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - } else { - selectedFlatIndex = Math.min(selectedFlatIndex, flatNavigation.length - 1); - updateSelectedIdFromIndex(); - ensureVisible(); - } - } - - function findRepeater(parent) { - if (!parent || !parent.children) { - return null; - } - for (var i = 0; i < parent.children.length; i++) { - const child = parent.children[i]; - if (child.objectName === "notificationRepeater") { - return child; - } - const found = findRepeater(child); - if (found) { - return found; - } - } - return null; - } - - function ensureVisible() { - if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length || !listView) - return; - const currentItem = flatNavigation[selectedFlatIndex]; - - if (keyboardNavigationActive && currentItem && currentItem.groupIndex >= 0) { - if (currentItem.type === "notification") { - const groupDelegate = listView.itemAtIndex(currentItem.groupIndex); - if (groupDelegate && groupDelegate.children && groupDelegate.children.length > 0) { - const notificationCard = groupDelegate.children[0]; - const repeater = findRepeater(notificationCard); - - if (repeater && currentItem.notificationIndex < repeater.count) { - const notificationItem = repeater.itemAt(currentItem.notificationIndex); - if (notificationItem) { - const itemPos = notificationItem.mapToItem(listView.contentItem, 0, 0); - const itemY = itemPos.y; - const itemHeight = notificationItem.height; - - const viewportTop = listView.contentY; - const viewportBottom = listView.contentY + listView.height; - - if (itemY < viewportTop) { - listView.contentY = itemY - 20; - } else if (itemY + itemHeight > viewportBottom) { - listView.contentY = itemY + itemHeight - listView.height + 20; - } - } - } - } - } else { - listView.positionViewAtIndex(currentItem.groupIndex, ListView.Contain); - } - - listView.forceLayout(); - } - } - - function handleKey(event) { - if ((event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) && (event.modifiers & Qt.ShiftModifier)) { - NotificationService.clearAllNotifications(); - rebuildFlatNavigation(); - if (flatNavigation.length === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - } else { - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - } - selectionVersion++; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Escape) { - if (keyboardNavigationActive) { - keyboardNavigationActive = false; - event.accepted = true; - } else { - if (onClose) - onClose(); - event.accepted = true; - } - } else if (event.key === Qt.Key_Down || event.key === 16777237) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); // Ensure we have fresh navigation data - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - // Set keyboardActive on listView to show highlight - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - event.accepted = true; - } else { - selectNext(); - event.accepted = true; - } - } else if (event.key === Qt.Key_Up || event.key === 16777235) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); // Ensure we have fresh navigation data - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - // Set keyboardActive on listView to show highlight - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - event.accepted = true; - } else if (selectedFlatIndex === 0) { - keyboardNavigationActive = false; - // Reset keyboardActive when navigation is disabled - if (listView) { - listView.keyboardActive = false; - } - selectionVersion++; - event.accepted = true; - return; - } else { - selectPrevious(); - event.accepted = true; - } - } else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else { - selectNext(); - } - event.accepted = true; - } else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else if (selectedFlatIndex === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - selectionVersion++; - } else { - selectPrevious(); - } - event.accepted = true; - } else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else { - selectNext(); - } - event.accepted = true; - } else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) { - if (!keyboardNavigationActive) { - keyboardNavigationActive = true; - rebuildFlatNavigation(); - selectedFlatIndex = 0; - updateSelectedIdFromIndex(); - if (listView) { - listView.keyboardActive = true; - } - selectionVersion++; - ensureVisible(); - } else if (selectedFlatIndex === 0) { - keyboardNavigationActive = false; - if (listView) { - listView.keyboardActive = false; - } - selectionVersion++; - } else { - selectPrevious(); - } - event.accepted = true; - } else if (keyboardNavigationActive) { - if (event.key === Qt.Key_Space) { - toggleGroupExpanded(); - event.accepted = true; - } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - handleEnterKey(); - event.accepted = true; - } else if (event.key === Qt.Key_E) { - toggleTextExpanded(); - event.accepted = true; - } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) { - clearSelected(); - event.accepted = true; - } else if (event.key === Qt.Key_Tab) { - selectNext(); - event.accepted = true; - } else if (event.key === Qt.Key_Backtab) { - selectPrevious(); - event.accepted = true; - } else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) { - const actionIndex = event.key - Qt.Key_1; - executeAction(actionIndex); - event.accepted = true; - } - } - - if (event.key === Qt.Key_F10) { - showKeyboardHints = !showKeyboardHints; - event.accepted = true; - } - } - - // Get current selection info for UI - function getCurrentSelection() { - if (!keyboardNavigationActive || selectedFlatIndex < 0 || selectedFlatIndex >= flatNavigation.length) { - return { - "type": "", - "groupIndex": -1, - "notificationIndex": -1 - }; - } - const result = flatNavigation[selectedFlatIndex] || { - "type": "", - "groupIndex": -1, - "notificationIndex": -1 - }; - return result; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml deleted file mode 100644 index 78ba2d5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml +++ /dev/null @@ -1,50 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property bool showHints: false - - height: 80 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Theme.primary - border.width: 2 - opacity: showHints ? 1 : 0 - z: 100 - - Column { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingS - spacing: 2 - - StyledText { - text: I18n.tr("↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml deleted file mode 100644 index 97364c7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml +++ /dev/null @@ -1,449 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property bool expanded: false - property real maxAllowedHeight: 0 - readonly property real naturalContentHeight: contentColumn.height + Theme.spacingL * 2 - - width: parent.width - height: expanded ? (maxAllowedHeight > 0 ? Math.min(naturalContentHeight, maxAllowedHeight) : naturalContentHeight) : 0 - visible: expanded - clip: true - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - border.width: 1 - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - opacity: expanded ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - readonly property var timeoutOptions: [ - { - "text": I18n.tr("Never"), - "value": 0 - }, - { - "text": I18n.tr("1 second"), - "value": 1000 - }, - { - "text": I18n.tr("3 seconds"), - "value": 3000 - }, - { - "text": I18n.tr("5 seconds"), - "value": 5000 - }, - { - "text": I18n.tr("8 seconds"), - "value": 8000 - }, - { - "text": I18n.tr("10 seconds"), - "value": 10000 - }, - { - "text": I18n.tr("15 seconds"), - "value": 15000 - }, - { - "text": I18n.tr("30 seconds"), - "value": 30000 - }, - { - "text": I18n.tr("1 minute"), - "value": 60000 - }, - { - "text": I18n.tr("2 minutes"), - "value": 120000 - }, - { - "text": I18n.tr("5 minutes"), - "value": 300000 - }, - { - "text": I18n.tr("10 minutes"), - "value": 600000 - } - ] - - function getTimeoutText(value) { - if (value === undefined || value === null || isNaN(value)) { - return I18n.tr("5 seconds"); - } - - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].value === value) { - return timeoutOptions[i].text; - } - } - if (value === 0) { - return I18n.tr("Never"); - } - if (value < 1000) { - return value + "ms"; - } - if (value < 60000) { - return Math.round(value / 1000) + " " + I18n.tr("seconds"); - } - return Math.round(value / 60000) + " " + I18n.tr("minutes"); - } - - Flickable { - id: settingsFlickable - anchors.fill: parent - contentHeight: contentColumn.height + Theme.spacingL * 2 - clip: true - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.DragAndOvershootBounds - interactive: root.naturalContentHeight > root.height - - Column { - id: contentColumn - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Notification Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - } - - Item { - width: parent.width - height: Math.max(dndRow.implicitHeight, dndToggle.implicitHeight) + Theme.spacingS - - Row { - id: dndRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: SessionData.doNotDisturb ? "notifications_off" : "notifications" - size: Theme.iconSizeSmall - color: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Do Not Disturb") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: dndToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SessionData.doNotDisturb - onToggled: SessionData.setDoNotDisturb(!SessionData.doNotDisturb) - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - StyledText { - text: I18n.tr("Notification Timeouts") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - DankDropdown { - text: I18n.tr("Low Priority") - description: I18n.tr("Timeout for low priority notifications") - currentValue: getTimeoutText(SettingsData.notificationTimeoutLow) - options: timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutLow", timeoutOptions[i].value); - break; - } - } - } - } - - DankDropdown { - text: I18n.tr("Normal Priority") - description: I18n.tr("Timeout for normal priority notifications") - currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal) - options: timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutNormal", timeoutOptions[i].value); - break; - } - } - } - } - - DankDropdown { - text: I18n.tr("Critical Priority") - description: I18n.tr("Timeout for critical priority notifications") - currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical) - options: timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutCritical", timeoutOptions[i].value); - break; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - Item { - width: parent.width - height: Math.max(overlayRow.implicitHeight, overlayToggle.implicitHeight) + Theme.spacingS - - Row { - id: overlayRow - anchors.left: parent.left - anchors.right: overlayToggle.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "notifications_active" - size: Theme.iconSizeSmall - color: SettingsData.notificationOverlayEnabled ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: overlayRow.width - Theme.iconSizeSmall - Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Notification Overlay") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.Wrap - } - - StyledText { - width: parent.width - text: I18n.tr("Display all priorities over fullscreen apps") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.Wrap - } - } - } - - DankToggle { - id: overlayToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationOverlayEnabled - onToggled: toggled => SettingsData.set("notificationOverlayEnabled", toggled) - } - } - - Item { - width: parent.width - height: Math.max(privacyRow.implicitHeight, privacyToggle.implicitHeight) + Theme.spacingS - - Row { - id: privacyRow - anchors.left: parent.left - anchors.right: privacyToggle.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "privacy_tip" - size: Theme.iconSizeSmall - color: SettingsData.notificationPopupPrivacyMode ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: privacyRow.width - Theme.iconSizeSmall - Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Privacy Mode") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.Wrap - } - - StyledText { - width: parent.width - text: I18n.tr("Hide notification content until expanded") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.Wrap - } - } - } - - DankToggle { - id: privacyToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationPopupPrivacyMode - onToggled: toggled => SettingsData.set("notificationPopupPrivacyMode", toggled) - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - StyledText { - text: I18n.tr("History Settings") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - Item { - width: parent.width - height: Math.max(lowRow.implicitHeight, lowToggle.implicitHeight) + Theme.spacingS - - Row { - id: lowRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "low_priority" - size: Theme.iconSizeSmall - color: SettingsData.notificationHistorySaveLow ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Low Priority") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: lowToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationHistorySaveLow - onToggled: toggled => SettingsData.set("notificationHistorySaveLow", toggled) - } - } - - Item { - width: parent.width - height: Math.max(normalRow.implicitHeight, normalToggle.implicitHeight) + Theme.spacingS - - Row { - id: normalRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "notifications" - size: Theme.iconSizeSmall - color: SettingsData.notificationHistorySaveNormal ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Normal Priority") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: normalToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationHistorySaveNormal - onToggled: toggled => SettingsData.set("notificationHistorySaveNormal", toggled) - } - } - - Item { - width: parent.width - height: Math.max(criticalRow.implicitHeight, criticalToggle.implicitHeight) + Theme.spacingS - - Row { - id: criticalRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "priority_high" - size: Theme.iconSizeSmall - color: SettingsData.notificationHistorySaveCritical ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Critical Priority") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: criticalToggle - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.notificationHistorySaveCritical - onToggled: toggled => SettingsData.set("notificationHistorySaveCritical", toggled) - } - } - } - } -} -- cgit v1.3