From 510cbb0cec2c50c8d8327b9cb6472d610e91fe32 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 2 Sep 2026 00:34:14 +0200 Subject: [PATCH] feat: refactor NotificationHistory.qml to improve hover tracking and auto-closing behavior --- modules/notification/NotificationHistory.qml | 67 ++++---------------- 1 file changed, 12 insertions(+), 55 deletions(-) diff --git a/modules/notification/NotificationHistory.qml b/modules/notification/NotificationHistory.qml index 9a4fc95..df43165 100644 --- a/modules/notification/NotificationHistory.qml +++ b/modules/notification/NotificationHistory.qml @@ -65,23 +65,13 @@ PanelWindow { } function closeNHistory() { - // Centralized close via singleton signal – fixes previous ReferenceError - // where this file tried to access notifificationHistoryLoader.id directly - // (that id lives in NotificationHistoryLoader.qml and is not in scope here). console.log("[NotificationHistory] closeNHistory() requested") NotificationS.historyHovered = false NotificationS.closeHistoryRequested() } - // ── Hover tracking via NotificationServer ── - // History reports its hover state via background HoverHandler (non-exclusive) - // so hovering over inner buttons (closeArea, clearGroupArea, NotificationBody) - // does NOT clear historyHovered. Timer auto-closes when neither history nor - // bar button is hovered for historyAutoCloseDelay ms. property bool _allowAutoClose: false - // Grace timer: don't allow auto-close immediately after opening, - // giving keyboard users time to move mouse to history. Timer { id: graceTimer interval: 500 @@ -93,7 +83,6 @@ PanelWindow { Timer { id: hoverCloseTimer interval: NotificationS.historyAutoCloseDelay - // Only run when panel is visible, grace passed, and neither element is hovered running: root.visible && _allowAutoClose && !NotificationS.historyHovered && !NotificationS.buttonHovered repeat: false onTriggered: { @@ -104,7 +93,6 @@ PanelWindow { } } - // Ensure hover state is cleared when window hides/destroys onVisibleChanged: { if (!visible) { NotificationS.historyHovered = false @@ -124,12 +112,6 @@ PanelWindow { root.closeNHistory() } } - - Rectangle { - anchors.fill: parent - color: "lightblue" - visible: false // debug helper, keep hidden in normal use - } } Rectangle { @@ -141,13 +123,7 @@ PanelWindow { border.color: textColor radius: Config.screen_big_radius_fun(screen.height) - // HoverHandler on background (parent of all history UI) stays hovered - // when pointer is over any descendant (topBar buttons, NotificationBody etc.) - // because HoverHandler is non-blocking PointerHandler and tracks parent - // bounds rather than exclusive MouseArea containsMouse. This fixes bug - // where hovering over inner buttons made historyHovered false and triggered - // auto-close. Using CanTakeOverFromAnything ensures it isn't blocked by - // child MouseAreas. + HoverHandler { id: backgroundHoverHandler blocking: false @@ -158,15 +134,6 @@ PanelWindow { } } - // Component.onCompleted: { - // for (var notification in NotificationS.trackedNotifications.values) { - // console.log("[NotificationHistory]: " + notification.appName + " Notifications") - // } - // for (var i =0; i < NotificationS.notificationNum; i++) { - // console.log("[NotificationHistory]: " + NotificationS.trackedNotifications.values[i].appName + " Notifications") - // } - // } - Column{ id: bgColumn anchors.fill: parent @@ -197,12 +164,6 @@ PanelWindow { } } - // Row{ - // id: backgroundCenter - // anchors.centerIn: parent - // spacing: Config.screen_small_bar_spacing_fun(screen.height) - // } - Row{ id: backgroundRight anchors.verticalCenter: parent.verticalCenter @@ -224,6 +185,15 @@ PanelWindow { implicitHeight: topBar.height*0.75 anchors.verticalCenter: parent.verticalCenter checked: NotificationS.notificationPopupEnabled + hoverEnabled: true + + HoverHandler { + id: switchHoverHandler + cursorShape: Qt.PointingHandCursor + blocking: false + grabPermissions: PointerHandler.CanTakeOverFromAnything + onHoveredChanged: if (hovered) NotificationS.historyHovered = true + } indicator: Rectangle { implicitWidth: notificationVolumeSwitch.width @@ -272,8 +242,7 @@ PanelWindow { anchors.verticalCenter: parent.verticalCenter hoverEnabled: true cursorShape: Qt.PointingHandCursor - // Safety: hovering over button should keep history considered hovered - // even if background HoverHandler is blocked (exclusive hover) + onContainsMouseChanged: if (containsMouse) NotificationS.historyHovered = true Rectangle{ anchors.fill: parent @@ -291,7 +260,6 @@ PanelWindow { } onClicked: { root.clearAll() - // closeNHistory() } } } @@ -299,7 +267,7 @@ PanelWindow { Rectangle { width: parent.width - height: parent.height - topBar.height - bgColumn.spacing //- bgColumn.anchors.margins*2 + height: parent.height - topBar.height - bgColumn.spacing color: textBGColor radius: Config.screen_big_radius_fun(screen.height) border.width: Config.border_width @@ -330,12 +298,6 @@ PanelWindow { width: flick.width spacing: Config.spacing - // ── Grouped view (only groups with >1 notification are grouped) ── - // Uses root.grouped (sorted by appName). Each app group with - // more than one notification is rendered as a collapsible - // card with a header (appName + count + expand/collapse + - // clear-group). Singletons are rendered directly as a - // NotificationBody without a header. Repeater { id: groupedRepeater model: root.grouped @@ -348,19 +310,15 @@ PanelWindow { property bool isExpanded: root.expandedGroups[group.appName] === true width: contentColumn.width - // height adapts to which component is visible implicitHeight: isGrouped ? groupedCard.implicitHeight : singleBody.implicitHeight height: implicitHeight - // Keep history hovered when pointer is over this delegate - // (covers NotificationBody and its inner buttons). HoverHandler { blocking: false grabPermissions: PointerHandler.CanTakeOverFromAnything onHoveredChanged: if (hovered) NotificationS.historyHovered = true } - // ── Singleton: plain NotificationBody ── NotificationBody { id: singleBody visible: !delegateRoot.isGrouped @@ -374,7 +332,6 @@ PanelWindow { } } - // ── Grouped card (count > 1) ── Rectangle { id: groupedCard visible: delegateRoot.isGrouped