1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-03 20:18:31 -04:00

fix(Hover): refactor & update hover tracking w/context menus

Fixes #2737
This commit is contained in:
purian23
2026-07-04 00:08:58 -04:00
parent 2861cc89c6
commit c554d973ef
30 changed files with 297 additions and 27 deletions
@@ -17,6 +17,7 @@ DankListView {
property int swipingCardIndex: -1
property real swipingCardOffset: 0
property bool _stableHeightUpdatePending: false
property var transientSurfaceTracker: null
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)
@@ -173,6 +174,7 @@ DankListView {
notificationGroup: modelData
keyboardNavigationActive: listView.keyboardActive
animateExpansion: listView.cardAnimateExpansion && listView.listInitialized
transientSurfaceTracker: listView.transientSurfaceTracker
opacity: {
const swipeAmount = Math.abs(delegateRoot.swipeOffset);
if (swipeAmount <= delegateRoot.swipeFadeStartOffset)
@@ -30,6 +30,7 @@ Rectangle {
property real swipingNotificationOffset: 0
property real listLevelAdjacentScaleInfluence: 1.0
property bool listLevelScaleAnimationsEnabled: true
property var transientSurfaceTracker: null
readonly property bool compactMode: SettingsData.notificationCompactMode
readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding
@@ -63,6 +64,20 @@ Rectangle {
});
}
Component.onDestruction: {
transientSurfaceTracker?.unregister(root);
notificationCardContextMenu.close();
}
Connections {
target: root.transientSurfaceTracker
ignoreUnknownSignals: true
function onCloseRequested() {
notificationCardContextMenu.close();
}
}
function expansionMotionDuration() {
if (isDescriptionToggleAnimation)
return descriptionExpanded ? Theme.notificationInlineExpandDuration : Theme.notificationInlineCollapseDuration;
@@ -1059,6 +1074,8 @@ Rectangle {
width: 220
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
onVisibleChanged: root.transientSurfaceTracker?.setActive(root, visible, null)
background: Rectangle {
color: BlurService.enabled ? Theme.surfaceContainer : Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
@@ -283,11 +283,13 @@ DankPopout {
NotificationHeader {
id: notificationHeader
objectName: "notificationHeader"
transientSurfaceTracker: root.transientSurfaceTracker
onHeightChanged: notificationContent.cachedHeaderHeight = height
}
NotificationSettings {
id: notificationSettings
transientSurfaceTracker: root.transientSurfaceTracker
expanded: notificationHeader.showSettings
maxAllowedHeight: notificationContent.settingsMaxHeight
}
@@ -306,6 +308,7 @@ DankPopout {
anchors.topMargin: -(shadowVerticalGutter + delegateShadowGutter / 2)
anchors.bottomMargin: -(shadowVerticalGutter + delegateShadowGutter / 2)
cardAnimateExpansion: true
transientSurfaceTracker: root.transientSurfaceTracker
}
}
@@ -10,6 +10,19 @@ Item {
property bool showSettings: false
property int currentTab: 0
property bool showDndMenu: false
property var transientSurfaceTracker: null
onShowDndMenuChanged: transientSurfaceTracker?.setActive(root, showDndMenu, null)
Component.onDestruction: transientSurfaceTracker?.unregister(root)
Connections {
target: root.transientSurfaceTracker
ignoreUnknownSignals: true
function onCloseRequested() {
root.showDndMenu = false;
}
}
onCurrentTabChanged: {
if (currentTab === 1 && !SettingsData.notificationHistoryEnabled)
@@ -7,6 +7,7 @@ Rectangle {
property bool expanded: false
property real maxAllowedHeight: 0
property var transientSurfaceTracker: null
readonly property real naturalContentHeight: contentColumn.height + Theme.spacingL * 2
width: parent.width
@@ -178,6 +179,8 @@ Rectangle {
}
DankDropdown {
id: lowTimeoutDropdown
transientSurfaceTracker: root.transientSurfaceTracker
text: I18n.tr("Low Priority")
description: I18n.tr("Timeout for low priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
@@ -193,6 +196,8 @@ Rectangle {
}
DankDropdown {
id: normalTimeoutDropdown
transientSurfaceTracker: root.transientSurfaceTracker
text: I18n.tr("Normal Priority")
description: I18n.tr("Timeout for normal priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
@@ -208,6 +213,8 @@ Rectangle {
}
DankDropdown {
id: criticalTimeoutDropdown
transientSurfaceTracker: root.transientSurfaceTracker
text: I18n.tr("Critical Priority")
description: I18n.tr("Timeout for critical priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
@@ -11,12 +11,25 @@ PanelWindow {
property string appName: ""
property string desktopEntry: ""
property point anchorPos: Qt.point(0, 0)
property var transientSurfaceTracker: null
signal muted
signal dismissRequested
readonly property bool isMuted: SettingsData.isAppMuted(appName, desktopEntry)
onVisibleChanged: transientSurfaceTracker?.setActive(root, visible, root)
Component.onDestruction: transientSurfaceTracker?.unregister(root)
Connections {
target: root.transientSurfaceTracker
ignoreUnknownSignals: true
function onCloseRequested() {
root.closeMenu();
}
}
function showAt(x, y, targetScreen) {
if (targetScreen)
screen = targetScreen;
@@ -70,6 +70,11 @@ PanelWindow {
property real _storedTopMargin: 0
property real _storedBottomMargin: 0
property bool _inlineGeometryReady: false
readonly property bool contextMenuActive: transientSurfaces.active
TransientSurfaceTracker {
id: transientSurfaces
}
readonly property bool directionalEffect: Theme.isDirectionalEffect
readonly property bool depthEffect: Theme.isDepthEffect
readonly property real entryTravel: {
@@ -122,6 +127,7 @@ PanelWindow {
if (exiting || _isDestroying) {
return;
}
closeTransientUi();
exiting = true;
exitStarted();
popupChromeGeometryChanged();
@@ -135,6 +141,7 @@ PanelWindow {
if (_isDestroying) {
return;
}
closeTransientUi();
_isDestroying = true;
exiting = true;
visible = false;
@@ -147,6 +154,7 @@ PanelWindow {
return;
}
closeTransientUi();
_finalized = true;
_isDestroying = true;
exitWatchdog.stop();
@@ -155,6 +163,11 @@ PanelWindow {
win.exitFinished();
}
function closeTransientUi() {
transientSurfaces.closeAll();
popupContextMenuLoader.active = false;
}
visible: !_finalized
WlrLayershell.layer: {
const shouldUseOverlay = notificationData && (SettingsData.notificationOverlayEnabled || notificationData.urgency === NotificationUrgency.Critical);
@@ -274,6 +287,7 @@ PanelWindow {
}
onNotificationDataChanged: {
if (!_isDestroying) {
closeTransientUi();
if (SettingsData.notificationPopupPrivacyMode)
descriptionExpanded = false;
wrapperConn.target = win.notificationData || null;
@@ -286,6 +300,7 @@ PanelWindow {
}
}
Component.onDestruction: {
closeTransientUi();
_isDestroying = true;
exitWatchdog.stop();
if (notificationData && notificationData.timer) {
@@ -716,7 +731,7 @@ PanelWindow {
if (cardHoverHandler.hovered) {
if (notificationData.timer)
notificationData.timer.stop();
} else if (notificationData.popup && notificationData.timer) {
} else if (!win.contextMenuActive && notificationData.popup && notificationData.timer) {
notificationData.timer.restart();
}
}
@@ -1357,11 +1372,26 @@ PanelWindow {
interval: 160
repeat: false
onTriggered: {
if (notificationData && notificationData.timer && !exiting && !_isDestroying)
if (notificationData && notificationData.timer && !contextMenuActive && !exiting && !_isDestroying)
notificationData.timer.start();
}
}
Connections {
target: popupContextMenuLoader.item
ignoreUnknownSignals: true
function onVisibleChanged() {
if (!notificationData?.timer || exiting || _isDestroying)
return;
if (win.contextMenuActive) {
notificationData.timer.stop();
} else if (!cardHoverHandler.hovered && notificationData.popup) {
notificationData.timer.restart();
}
}
}
Timer {
id: exitWatchdog
@@ -1387,6 +1417,7 @@ PanelWindow {
active: false
sourceComponent: NotificationContextMenu {
transientSurfaceTracker: transientSurfaces
appName: notificationData?.appName ?? ""
desktopEntry: notificationData?.desktopEntry ?? ""
onMuted: {