1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-04 12:52:06 -04:00

notifications: fix compact spacing, reveal header bar, add bottom center

position, pointing hand cursor fix
This commit is contained in:
bbedward
2026-02-13 21:44:27 -05:00
parent ed495d4396
commit 62bc25782c
4 changed files with 268 additions and 266 deletions

View File

@@ -124,7 +124,7 @@ Rectangle {
anchors.right: parent.right
anchors.topMargin: cardPadding
anchors.leftMargin: Theme.spacingL
anchors.rightMargin: Theme.spacingL + ((cardHoverHandler.hovered || (keyboardNavigationActive && (isGroupSelected || (expanded && selectedNotificationIndex >= 0)))) ? Theme.notificationHoverRevealMargin : 0)
anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin
height: collapsedContentHeight + extraHeight
visible: !expanded
@@ -146,9 +146,7 @@ Rectangle {
height: iconSize
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: descriptionExpanded
? Math.max(0, (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 3)) / 2 - iconSize / 2)
: Math.max(0, textContainer.height / 2 - iconSize / 2)
anchors.topMargin: descriptionExpanded ? Math.max(0, (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 3)) / 2 - iconSize / 2) : Math.max(0, textContainer.height / 2 - iconSize / 2)
imageSource: {
if (hasNotificationImage)
@@ -327,7 +325,7 @@ Rectangle {
Row {
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: Theme.spacingL + ((cardHoverHandler.hovered || (keyboardNavigationActive && (isGroupSelected || (expanded && selectedNotificationIndex >= 0)))) ? Theme.notificationHoverRevealMargin : 0)
anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
@@ -375,7 +373,7 @@ Rectangle {
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: expandedDelegateHoverHandler.hovered || (root.keyboardNavigationActive && isSelected)
readonly property bool actionsVisible: true
readonly property real expandedIconSize: compactMode ? Theme.notificationExpandedIconSizeCompact : Theme.notificationExpandedIconSizeNormal
HoverHandler {
@@ -437,196 +435,240 @@ Rectangle {
}
Item {
anchors.fill: parent
anchors.margins: compactMode ? Theme.spacingS : Theme.spacingM
anchors.bottomMargin: contentSpacing
anchors.fill: parent
anchors.margins: compactMode ? Theme.spacingS : Theme.spacingM
anchors.bottomMargin: contentSpacing
DankCircularImage {
id: messageIcon
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: compactMode ? Theme.spacingM : Theme.spacingXL
imageSource: {
if (hasNotificationImage)
return modelData.cleanImage;
if (imageHasSpecialPrefix)
readonly property string rawImage: modelData?.image || ""
readonly property string iconFromImage: {
if (rawImage.startsWith("image://icon/"))
return rawImage.substring(13);
return "";
const appIcon = modelData?.appIcon;
if (!appIcon)
return iconFromImage ? "image://icon/" + 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 Quickshell.iconPath(appIcon, true);
}
}
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/")
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 {
width: expandedIconSize
height: expandedIconSize
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: buttonArea.top
anchors.bottomMargin: contentSpacing
spacing: Theme.notificationContentSpacing
anchors.topMargin: compactMode ? Theme.spacingM : Theme.spacingXL
Row {
width: parent.width
spacing: Theme.spacingXS
readonly property real reservedTrailingWidth: expandedDelegateSeparator.implicitWidth + Math.max(expandedDelegateTimeText.implicitWidth, 72) + spacing
StyledText {
id: expandedDelegateTitleText
width: Math.min(implicitWidth, Math.max(0, parent.width - parent.reservedTrailingWidth))
text: {
let title = modelData?.summary || "";
const appName = modelData?.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: expandedDelegateSeparator
text: (expandedDelegateTitleText.text.length > 0 && expandedDelegateTimeText.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: expandedDelegateTimeText
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
visible: text.length > 0
}
imageSource: {
if (hasNotificationImage)
return modelData.cleanImage;
if (imageHasSpecialPrefix)
return "";
const appIcon = modelData?.appIcon;
if (!appIcon)
return iconFromImage ? "image://icon/" + 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 Quickshell.iconPath(appIcon, true);
}
StyledText {
id: bodyText
property bool hasMoreText: truncated
fallbackIcon: {
if (imageHasSpecialPrefix)
return iconFromImage;
return modelData?.appIcon || iconFromImage || "";
}
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.WordWrap
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)) {
NotificationService.toggleMessageExpansion(modelData?.notification?.id || "");
}
}
propagateComposedEvents: true
onPressed: mouse => {
if (parent.hoveredLink) {
mouse.accepted = false;
}
}
onReleased: mouse => {
if (parent.hoveredLink) {
mouse.accepted = false;
}
}
}
fallbackText: {
const appName = modelData?.appName || "?";
return appName.charAt(0).toUpperCase();
}
}
Item {
id: buttonArea
anchors.left: parent.left
anchors.left: messageIcon.right
anchors.leftMargin: Theme.spacingM
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.top: parent.top
anchors.bottom: parent.bottom
height: actionButtonHeight + contentSpacing
Row {
visible: expandedDelegateWrapper.actionsVisible
opacity: visible ? 1 : 0
Column {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
spacing: contentSpacing
anchors.top: parent.top
anchors.bottom: buttonArea.top
anchors.bottomMargin: contentSpacing
spacing: Theme.notificationContentSpacing
Behavior on opacity {
NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing }
Row {
width: parent.width
spacing: Theme.spacingXS
readonly property real reservedTrailingWidth: expandedDelegateSeparator.implicitWidth + Math.max(expandedDelegateTimeText.implicitWidth, 72) + spacing
StyledText {
id: expandedDelegateTitleText
width: Math.min(implicitWidth, Math.max(0, parent.width - parent.reservedTrailingWidth))
text: {
let title = modelData?.summary || "";
const appName = modelData?.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: expandedDelegateSeparator
text: (expandedDelegateTitleText.text.length > 0 && expandedDelegateTimeText.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: expandedDelegateTimeText
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
visible: text.length > 0
}
}
Repeater {
model: modelData?.actions || []
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.WordWrap
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)) {
NotificationService.toggleMessageExpansion(modelData?.notification?.id || "");
}
}
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 || "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
width: Math.max(expandedActionText.implicitWidth + Theme.spacingM, Theme.notificationActionMinWidth)
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"
StyledText {
id: expandedActionText
text: {
const baseText = modelData.text || "Open";
if (keyboardNavigationActive && (isGroupSelected || selectedNotificationIndex >= 0))
return `${baseText} (${index + 1})`;
return baseText;
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
elide: Text.ElideRight
}
MouseArea {
@@ -635,53 +677,15 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onEntered: parent.isHovered = true
onExited: parent.isHovered = false
onClicked: {
if (modelData && modelData.invoke)
modelData.invoke();
}
onClicked: NotificationService.dismissNotification(modelData)
}
}
}
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 {
@@ -722,18 +726,13 @@ Rectangle {
}
Row {
visible: !expanded && (cardHoverHandler.hovered || (keyboardNavigationActive && isGroupSelected))
opacity: visible ? 1 : 0
visible: !expanded
anchors.right: clearButton.visible ? clearButton.left : parent.right
anchors.rightMargin: clearButton.visible ? contentSpacing : Theme.spacingL
anchors.top: collapsedContent.bottom
anchors.topMargin: contentSpacing
spacing: contentSpacing
Behavior on opacity {
NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing }
}
Repeater {
model: notificationGroup?.latestNotification?.actions || []
@@ -783,11 +782,7 @@ Rectangle {
property bool isHovered: false
readonly property int actionCount: (notificationGroup?.latestNotification?.actions || []).length
visible: !expanded && actionCount < 3 && (cardHoverHandler.hovered || (keyboardNavigationActive && isGroupSelected))
opacity: visible ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing }
}
visible: !expanded && actionCount < 3
anchors.right: parent.right
anchors.rightMargin: Theme.spacingL
anchors.top: collapsedContent.bottom
@@ -819,6 +814,7 @@ Rectangle {
MouseArea {
anchors.fill: parent
visible: !expanded && (notificationGroup?.count || 0) > 1 && !descriptionExpanded
cursorShape: Qt.PointingHandCursor
onClicked: {
root.userInitiatedExpansion = true;
NotificationService.toggleGroupExpansion(notificationGroup?.key || "");
@@ -834,15 +830,6 @@ Rectangle {
anchors.rightMargin: Theme.spacingL
width: compactMode ? 52 : 60
height: compactMode ? 24 : 28
opacity: (cardHoverHandler.hovered || (keyboardNavigationActive && (isGroupSelected || (expanded && selectedNotificationIndex >= 0)))) ? 1 : 0
visible: opacity > 0
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
DankActionButton {
anchors.left: parent.left
@@ -949,7 +936,7 @@ Rectangle {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
z: 10
z: -2
onClicked: mouse => {
if (mouse.button === Qt.RightButton && notificationGroup) {
notificationCardContextMenu.popup();

View File

@@ -141,9 +141,11 @@ PanelWindow {
}
property bool isTopCenter: SettingsData.notificationPopupPosition === -1
property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter
property bool isCenterPosition: isTopCenter || isBottomCenter
anchors.top: isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left
anchors.bottom: SettingsData.notificationPopupPosition === SettingsData.Position.Bottom || SettingsData.notificationPopupPosition === SettingsData.Position.Right
anchors.bottom: isBottomCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom || SettingsData.notificationPopupPosition === SettingsData.Position.Right
anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
anchors.right: SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Right
@@ -182,7 +184,7 @@ PanelWindow {
function getBottomMargin() {
const popupPos = SettingsData.notificationPopupPosition;
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right;
const isBottom = isBottomCenter || popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right;
if (!isBottom)
return 0;
@@ -192,7 +194,7 @@ PanelWindow {
}
function getLeftMargin() {
if (isTopCenter)
if (isCenterPosition)
return screen ? (screen.width - implicitWidth) / 2 : 0;
const popupPos = SettingsData.notificationPopupPosition;
@@ -205,7 +207,7 @@ PanelWindow {
}
function getRightMargin() {
if (isTopCenter)
if (isCenterPosition)
return 0;
const popupPos = SettingsData.notificationPopupPosition;
@@ -232,7 +234,7 @@ PanelWindow {
visible: !win._finalized
property real swipeOffset: 0
readonly property real dismissThreshold: isTopCenter ? height * 0.4 : width * 0.35
readonly property real dismissThreshold: isCenterPosition ? height * 0.4 : width * 0.35
readonly property bool swipeActive: swipeDragHandler.active
property bool swipeDismissing: false
@@ -329,7 +331,7 @@ PanelWindow {
anchors.right: parent.right
anchors.topMargin: cardPadding
anchors.leftMargin: Theme.spacingL
anchors.rightMargin: Theme.spacingL + (cardHoverHandler.hovered ? Theme.notificationHoverRevealMargin : 0)
anchors.rightMargin: Theme.spacingL + Theme.notificationHoverRevealMargin
height: collapsedContentHeight + extraHeight
DankCircularImage {
@@ -352,9 +354,7 @@ PanelWindow {
height: popupIconSize
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: descriptionExpanded
? Math.max(0, (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 3)) / 2 - popupIconSize / 2)
: Math.max(0, textContainer.height / 2 - popupIconSize / 2)
anchors.topMargin: descriptionExpanded ? Math.max(0, (Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 3)) / 2 - popupIconSize / 2) : Math.max(0, textContainer.height / 2 - popupIconSize / 2)
imageSource: {
if (!notificationData)
@@ -469,19 +469,9 @@ PanelWindow {
anchors.topMargin: cardPadding
anchors.rightMargin: Theme.spacingL
iconName: "close"
iconSize: compactMode ? 16 : 18
buttonSize: compactMode ? 24 : 28
iconSize: compactMode ? 14 : 16
buttonSize: compactMode ? 20 : 24
z: 15
opacity: cardHoverHandler.hovered ? 1 : 0
visible: opacity > 0
enabled: cardHoverHandler.hovered
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
onClicked: {
if (notificationData && !win.exiting)
@@ -500,7 +490,10 @@ PanelWindow {
z: 20
Behavior on opacity {
NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing }
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Repeater {
@@ -552,7 +545,10 @@ PanelWindow {
visible: actionCount < 3 && cardHoverHandler.hovered
opacity: visible ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing }
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
anchors.right: parent.right
anchors.rightMargin: Theme.spacingL
@@ -594,6 +590,7 @@ PanelWindow {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor
propagateComposedEvents: true
z: -1
onEntered: {
@@ -624,8 +621,8 @@ PanelWindow {
DragHandler {
id: swipeDragHandler
target: null
xAxis.enabled: !isTopCenter
yAxis.enabled: isTopCenter
xAxis.enabled: !isCenterPosition
yAxis.enabled: isCenterPosition
onActiveChanged: {
if (active || win.exiting || content.swipeDismissing)
@@ -643,9 +640,11 @@ PanelWindow {
if (win.exiting)
return;
const raw = isTopCenter ? translation.y : translation.x;
const raw = isCenterPosition ? translation.y : translation.x;
if (isTopCenter) {
content.swipeOffset = Math.min(0, raw);
} else if (isBottomCenter) {
content.swipeOffset = Math.max(0, raw);
} else {
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
content.swipeOffset = isLeft ? Math.min(0, raw) : Math.max(0, raw);
@@ -653,7 +652,7 @@ PanelWindow {
}
}
opacity: 1 - Math.abs(content.swipeOffset) / (isTopCenter ? content.height : content.width * 0.6)
opacity: 1 - Math.abs(content.swipeOffset) / (isCenterPosition ? content.height : content.width * 0.6)
Behavior on opacity {
enabled: !content.swipeActive
@@ -674,7 +673,7 @@ PanelWindow {
id: swipeDismissAnim
target: content
property: "swipeOffset"
to: isTopCenter ? -content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width)
to: isTopCenter ? -content.height : isBottomCenter ? content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width)
duration: Theme.shortDuration
easing.type: Easing.OutCubic
onStopped: {
@@ -686,18 +685,18 @@ PanelWindow {
transform: [
Translate {
id: swipeTx
x: isTopCenter ? 0 : content.swipeOffset
y: isTopCenter ? content.swipeOffset : 0
x: isCenterPosition ? 0 : content.swipeOffset
y: isCenterPosition ? content.swipeOffset : 0
},
Translate {
id: tx
x: {
if (isTopCenter)
if (isCenterPosition)
return 0;
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
return isLeft ? -Anims.slidePx : Anims.slidePx;
}
y: isTopCenter ? -Anims.slidePx : 0
y: isTopCenter ? -Anims.slidePx : isBottomCenter ? Anims.slidePx : 0
}
]
}
@@ -706,20 +705,22 @@ PanelWindow {
id: enterX
target: tx
property: isTopCenter ? "y" : "x"
property: isCenterPosition ? "y" : "x"
from: {
if (isTopCenter)
return -Anims.slidePx;
if (isBottomCenter)
return Anims.slidePx;
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
return isLeft ? -Anims.slidePx : Anims.slidePx;
}
to: 0
duration: Theme.notificationEnterDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: isTopCenter ? Theme.expressiveCurves.standardDecel : Theme.expressiveCurves.emphasizedDecel
easing.bezierCurve: isCenterPosition ? Theme.expressiveCurves.standardDecel : Theme.expressiveCurves.emphasizedDecel
onStopped: {
if (!win.exiting && !win._isDestroying) {
if (isTopCenter) {
if (isCenterPosition) {
if (Math.abs(tx.y) < 0.5)
win.entered();
} else {
@@ -737,11 +738,13 @@ PanelWindow {
PropertyAnimation {
target: tx
property: isTopCenter ? "y" : "x"
property: isCenterPosition ? "y" : "x"
from: 0
to: {
if (isTopCenter)
return -Anims.slidePx;
if (isBottomCenter)
return Anims.slidePx;
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
return isLeft ? -Anims.slidePx : Anims.slidePx;
}

View File

@@ -11,8 +11,9 @@ QtObject {
readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding
readonly property real popupIconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal
readonly property real actionButtonHeight: compactMode ? 20 : 24
readonly property real popupSpacing: Theme.spacingXS
readonly property int baseNotificationHeight: cardPadding * 2 + popupIconSize + actionButtonHeight + Theme.spacingS + popupSpacing
readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS
readonly property real popupSpacing: compactMode ? 0 : Theme.spacingXS
readonly property int baseNotificationHeight: cardPadding * 2 + popupIconSize + actionButtonHeight + contentSpacing + popupSpacing
property int maxTargetNotifications: 4
property var popupWindows: [] // strong refs to windows (live until exitFinished)
property var destroyingWindows: new Set()