1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-14 01:32:29 -04:00

(frame): Update Connected blur Arcs & Enable shadow modes

This commit is contained in:
purian23
2026-04-13 14:58:05 -04:00
parent 0c4f0e65bb
commit f545337295
6 changed files with 380 additions and 51 deletions

View File

@@ -712,7 +712,7 @@ Variants {
Rectangle {
anchors.fill: parent
visible: !SettingsData.connectedFrameModeActive
visible: !SettingsData.connectedFrameModeActive && !(Theme.isConnectedEffect && dock.reveal)
color: dock.surfaceColor
topLeftRadius: dock.surfaceTopLeftRadius
topRightRadius: dock.surfaceTopRightRadius
@@ -722,7 +722,7 @@ Variants {
Rectangle {
anchors.fill: parent
visible: !SettingsData.connectedFrameModeActive
visible: !SettingsData.connectedFrameModeActive && !(Theme.isConnectedEffect && dock.reveal)
color: "transparent"
topLeftRadius: dock.surfaceTopLeftRadius
topRightRadius: dock.surfaceTopRightRadius
@@ -740,28 +740,16 @@ Variants {
onHeightChanged: dock._syncDockChromeState()
}
ConnectedCorner {
ConnectedShape {
visible: Theme.isConnectedEffect && dock.reveal && !SettingsData.connectedFrameModeActive
barSide: dock.connectedBarSide
placement: "left"
spacing: 0
bodyWidth: dockBackground.width
bodyHeight: dockBackground.height
connectorRadius: Theme.connectedCornerRadius
color: dock.surfaceColor
dpr: dock._dpr
x: Theme.snap(dock.connectorX(dockBackground.x, dockBackground.width, placement, spacing), dock._dpr)
y: Theme.snap(dock.connectorY(dockBackground.y, dockBackground.height, placement, spacing), dock._dpr)
}
ConnectedCorner {
visible: Theme.isConnectedEffect && dock.reveal && !SettingsData.connectedFrameModeActive
barSide: dock.connectedBarSide
placement: "right"
spacing: 0
connectorRadius: Theme.connectedCornerRadius
color: dock.surfaceColor
dpr: dock._dpr
x: Theme.snap(dock.connectorX(dockBackground.x, dockBackground.width, placement, spacing), dock._dpr)
y: Theme.snap(dock.connectorY(dockBackground.y, dockBackground.height, placement, spacing), dock._dpr)
surfaceRadius: dock.surfaceRadius
fillColor: dock.surfaceColor
x: dockBackground.x - bodyX
y: dockBackground.y - bodyY
}
Shape {

View File

@@ -1,6 +1,7 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import qs.Common
@@ -65,6 +66,12 @@ PanelWindow {
const crossSize = isHoriz ? _popoutBodyBlurAnchor.width : _popoutBodyBlurAnchor.height;
return Math.max(0, Math.min(win._ccr, extent, crossSize / 2));
}
readonly property real _effectiveNotifCcr: {
const isHoriz = win._notifState.barSide === "top" || win._notifState.barSide === "bottom";
const crossSize = isHoriz ? _notifBodyBlurAnchor.width : _notifBodyBlurAnchor.height;
const extent = isHoriz ? _notifBodyBlurAnchor.height : _notifBodyBlurAnchor.width;
return Theme.snap(Math.max(0, Math.min(win._ccr, win._surfaceRadius, extent, crossSize / 2)), win._dpr);
}
readonly property color _surfaceColor: Theme.connectedSurfaceColor
readonly property real _surfaceOpacity: _surfaceColor.a
readonly property color _opaqueSurfaceColor: Qt.rgba(_surfaceColor.r, _surfaceColor.g, _surfaceColor.b, 1)
@@ -165,6 +172,60 @@ PanelWindow {
height: _active ? _capHeight : 0
}
Item {
id: _popoutLeftConnectorBlurAnchor
opacity: 0
readonly property bool _active: _popoutBodyBlurAnchor._active && win._effectivePopoutCcr > 0
readonly property real _w: win._popoutConnectorWidth(0)
readonly property real _h: win._popoutConnectorHeight(0)
x: _active ? Theme.snap(win._popoutConnectorX(_popoutBodyBlurAnchor.x, _popoutBodyBlurAnchor.width, "left", 0), win._dpr) : 0
y: _active ? Theme.snap(win._popoutConnectorY(_popoutBodyBlurAnchor.y, _popoutBodyBlurAnchor.height, "left", 0), win._dpr) : 0
width: _active ? _w : 0
height: _active ? _h : 0
}
Item {
id: _popoutRightConnectorBlurAnchor
opacity: 0
readonly property bool _active: _popoutBodyBlurAnchor._active && win._effectivePopoutCcr > 0
readonly property real _w: win._popoutConnectorWidth(0)
readonly property real _h: win._popoutConnectorHeight(0)
x: _active ? Theme.snap(win._popoutConnectorX(_popoutBodyBlurAnchor.x, _popoutBodyBlurAnchor.width, "right", 0), win._dpr) : 0
y: _active ? Theme.snap(win._popoutConnectorY(_popoutBodyBlurAnchor.y, _popoutBodyBlurAnchor.height, "right", 0), win._dpr) : 0
width: _active ? _w : 0
height: _active ? _h : 0
}
Item {
id: _popoutLeftConnectorCutout
opacity: 0
readonly property bool _active: _popoutLeftConnectorBlurAnchor.width > 0 && _popoutLeftConnectorBlurAnchor.height > 0
readonly property string _arcCorner: win._connectorArcCorner(ConnectedModeState.popoutBarSide, "left")
x: _active ? win._connectorCutoutX(_popoutLeftConnectorBlurAnchor.x, _popoutLeftConnectorBlurAnchor.width, _arcCorner, win._effectivePopoutCcr) : 0
y: _active ? win._connectorCutoutY(_popoutLeftConnectorBlurAnchor.y, _popoutLeftConnectorBlurAnchor.height, _arcCorner, win._effectivePopoutCcr) : 0
width: _active ? win._effectivePopoutCcr * 2 : 0
height: _active ? win._effectivePopoutCcr * 2 : 0
}
Item {
id: _popoutRightConnectorCutout
opacity: 0
readonly property bool _active: _popoutRightConnectorBlurAnchor.width > 0 && _popoutRightConnectorBlurAnchor.height > 0
readonly property string _arcCorner: win._connectorArcCorner(ConnectedModeState.popoutBarSide, "right")
x: _active ? win._connectorCutoutX(_popoutRightConnectorBlurAnchor.x, _popoutRightConnectorBlurAnchor.width, _arcCorner, win._effectivePopoutCcr) : 0
y: _active ? win._connectorCutoutY(_popoutRightConnectorBlurAnchor.y, _popoutRightConnectorBlurAnchor.height, _arcCorner, win._effectivePopoutCcr) : 0
width: _active ? win._effectivePopoutCcr * 2 : 0
height: _active ? win._effectivePopoutCcr * 2 : 0
}
Item {
id: _dockLeftConnectorBlurAnchor
opacity: 0
@@ -231,6 +292,75 @@ PanelWindow {
height: _active ? Theme.snap(win._notifState.bodyH, win._dpr) : 0
}
Item {
id: _notifBodyBlurCap
opacity: 0
readonly property string _side: win._notifState.barSide
readonly property bool _active: _notifBodyBlurAnchor._active && _notifBodyBlurAnchor.width > 0 && _notifBodyBlurAnchor.height > 0 && win._notifConnectorRadius() > 0
readonly property real _capWidth: (_side === "left" || _side === "right") ? Math.min(win._notifConnectorRadius(), _notifBodyBlurAnchor.width) : _notifBodyBlurAnchor.width
readonly property real _capHeight: (_side === "top" || _side === "bottom") ? Math.min(win._notifConnectorRadius(), _notifBodyBlurAnchor.height) : _notifBodyBlurAnchor.height
x: !_active ? 0 : (_side === "right" ? _notifBodyBlurAnchor.x + _notifBodyBlurAnchor.width - _capWidth : _notifBodyBlurAnchor.x)
y: !_active ? 0 : (_side === "bottom" ? _notifBodyBlurAnchor.y + _notifBodyBlurAnchor.height - _capHeight : _notifBodyBlurAnchor.y)
width: _active ? _capWidth : 0
height: _active ? _capHeight : 0
}
Item {
id: _notifLeftConnectorBlurAnchor
opacity: 0
readonly property bool _active: _notifBodyBlurAnchor._active && win._notifConnectorRadius() > 0
readonly property real _w: win._notifConnectorWidth(0)
readonly property real _h: win._notifConnectorHeight(0)
x: _active ? Theme.snap(win._notifConnectorX(_notifBodyBlurAnchor.x, _notifBodyBlurAnchor.width, "left", 0), win._dpr) : 0
y: _active ? Theme.snap(win._notifConnectorY(_notifBodyBlurAnchor.y, _notifBodyBlurAnchor.height, "left", 0), win._dpr) : 0
width: _active ? _w : 0
height: _active ? _h : 0
}
Item {
id: _notifRightConnectorBlurAnchor
opacity: 0
readonly property bool _active: _notifBodyBlurAnchor._active && win._notifConnectorRadius() > 0
readonly property real _w: win._notifConnectorWidth(0)
readonly property real _h: win._notifConnectorHeight(0)
x: _active ? Theme.snap(win._notifConnectorX(_notifBodyBlurAnchor.x, _notifBodyBlurAnchor.width, "right", 0), win._dpr) : 0
y: _active ? Theme.snap(win._notifConnectorY(_notifBodyBlurAnchor.y, _notifBodyBlurAnchor.height, "right", 0), win._dpr) : 0
width: _active ? _w : 0
height: _active ? _h : 0
}
Item {
id: _notifLeftConnectorCutout
opacity: 0
readonly property bool _active: _notifLeftConnectorBlurAnchor.width > 0 && _notifLeftConnectorBlurAnchor.height > 0
readonly property string _arcCorner: win._connectorArcCorner(win._notifState.barSide, "left")
x: _active ? win._connectorCutoutX(_notifLeftConnectorBlurAnchor.x, _notifLeftConnectorBlurAnchor.width, _arcCorner, win._notifConnectorRadius()) : 0
y: _active ? win._connectorCutoutY(_notifLeftConnectorBlurAnchor.y, _notifLeftConnectorBlurAnchor.height, _arcCorner, win._notifConnectorRadius()) : 0
width: _active ? win._notifConnectorRadius() * 2 : 0
height: _active ? win._notifConnectorRadius() * 2 : 0
}
Item {
id: _notifRightConnectorCutout
opacity: 0
readonly property bool _active: _notifRightConnectorBlurAnchor.width > 0 && _notifRightConnectorBlurAnchor.height > 0
readonly property string _arcCorner: win._connectorArcCorner(win._notifState.barSide, "right")
x: _active ? win._connectorCutoutX(_notifRightConnectorBlurAnchor.x, _notifRightConnectorBlurAnchor.width, _arcCorner, win._notifConnectorRadius()) : 0
y: _active ? win._connectorCutoutY(_notifRightConnectorBlurAnchor.y, _notifRightConnectorBlurAnchor.height, _arcCorner, win._notifConnectorRadius()) : 0
width: _active ? win._notifConnectorRadius() * 2 : 0
height: _active ? win._notifConnectorRadius() * 2 : 0
}
Region {
id: _staticBlurRegion
x: 0
@@ -253,6 +383,22 @@ PanelWindow {
Region {
item: _popoutBodyBlurCap
}
Region {
item: _popoutLeftConnectorBlurAnchor
Region {
item: _popoutLeftConnectorCutout
intersection: Intersection.Subtract
radius: win._effectivePopoutCcr
}
}
Region {
item: _popoutRightConnectorBlurAnchor
Region {
item: _popoutRightConnectorCutout
intersection: Intersection.Subtract
radius: win._effectivePopoutCcr
}
}
// ── Connected dock blur regions ──
Region {
@@ -264,7 +410,6 @@ PanelWindow {
}
Region {
item: _dockLeftConnectorBlurAnchor
radius: win._dockConnectorRadius()
Region {
item: _dockLeftConnectorCutout
intersection: Intersection.Subtract
@@ -273,7 +418,6 @@ PanelWindow {
}
Region {
item: _dockRightConnectorBlurAnchor
radius: win._dockConnectorRadius()
Region {
item: _dockRightConnectorCutout
intersection: Intersection.Subtract
@@ -285,9 +429,28 @@ PanelWindow {
item: _notifBodyBlurAnchor
radius: win._surfaceRadius
}
Region {
item: _notifBodyBlurCap
}
Region {
item: _notifLeftConnectorBlurAnchor
Region {
item: _notifLeftConnectorCutout
intersection: Intersection.Subtract
radius: win._notifConnectorRadius()
}
}
Region {
item: _notifRightConnectorBlurAnchor
Region {
item: _notifRightConnectorCutout
intersection: Intersection.Subtract
radius: win._notifConnectorRadius()
}
}
}
// ─── Connector position helpers (dock) ─────────────────────────────────
// ─── Connector position helpers ────────────────────────────────────────
function _dockBodyBlurRadius() {
return _dockBodyBlurAnchor._active ? Math.max(0, Math.min(win._surfaceRadius, _dockBodyBlurAnchor.width / 2, _dockBodyBlurAnchor.height / 2)) : win._surfaceRadius;
@@ -336,6 +499,76 @@ PanelWindow {
return placement === "left" ? seamY - h : seamY;
}
function _notifConnectorRadius() {
return win._effectiveNotifCcr;
}
function _notifConnectorWidth(spacing) {
const isVert = win._notifState.barSide === "left" || win._notifState.barSide === "right";
const radius = win._notifConnectorRadius();
return isVert ? (spacing + radius) : radius;
}
function _notifConnectorHeight(spacing) {
const isVert = win._notifState.barSide === "left" || win._notifState.barSide === "right";
const radius = win._notifConnectorRadius();
return isVert ? radius : (spacing + radius);
}
function _notifConnectorX(baseX, bodyWidth, placement, spacing) {
const notifSide = win._notifState.barSide;
const isVert = notifSide === "left" || notifSide === "right";
const seamX = !isVert ? (placement === "left" ? baseX : baseX + bodyWidth) : (notifSide === "left" ? baseX : baseX + bodyWidth);
const w = _notifConnectorWidth(spacing);
if (!isVert)
return placement === "left" ? seamX - w : seamX;
return notifSide === "left" ? seamX : seamX - w;
}
function _notifConnectorY(baseY, bodyHeight, placement, spacing) {
const notifSide = win._notifState.barSide;
const seamY = notifSide === "top" ? baseY : notifSide === "bottom" ? baseY + bodyHeight : (placement === "left" ? baseY : baseY + bodyHeight);
const h = _notifConnectorHeight(spacing);
if (notifSide === "top")
return seamY;
if (notifSide === "bottom")
return seamY - h;
return placement === "left" ? seamY - h : seamY;
}
function _popoutConnectorWidth(spacing) {
const isVert = ConnectedModeState.popoutBarSide === "left" || ConnectedModeState.popoutBarSide === "right";
const radius = win._effectivePopoutCcr;
return isVert ? (spacing + radius) : radius;
}
function _popoutConnectorHeight(spacing) {
const isVert = ConnectedModeState.popoutBarSide === "left" || ConnectedModeState.popoutBarSide === "right";
const radius = win._effectivePopoutCcr;
return isVert ? radius : (spacing + radius);
}
function _popoutConnectorX(baseX, bodyWidth, placement, spacing) {
const popoutSide = ConnectedModeState.popoutBarSide;
const isVert = popoutSide === "left" || popoutSide === "right";
const seamX = !isVert ? (placement === "left" ? baseX : baseX + bodyWidth) : (popoutSide === "left" ? baseX : baseX + bodyWidth);
const w = _popoutConnectorWidth(spacing);
if (!isVert)
return placement === "left" ? seamX - w : seamX;
return popoutSide === "left" ? seamX : seamX - w;
}
function _popoutConnectorY(baseY, bodyHeight, placement, spacing) {
const popoutSide = ConnectedModeState.popoutBarSide;
const seamY = popoutSide === "top" ? baseY : popoutSide === "bottom" ? baseY + bodyHeight : (placement === "left" ? baseY : baseY + bodyHeight);
const h = _popoutConnectorHeight(spacing);
if (popoutSide === "top")
return seamY;
if (popoutSide === "bottom")
return seamY - h;
return placement === "left" ? seamY - h : seamY;
}
function _popoutFillOverlapX() {
return (ConnectedModeState.popoutBarSide === "top" || ConnectedModeState.popoutBarSide === "bottom") ? win._seamOverlap : 0;
}
@@ -561,9 +794,27 @@ PanelWindow {
anchors.fill: parent
visible: win._connectedActive
opacity: win._surfaceOpacity
layer.enabled: opacity < 1
layer.enabled: true // Always need a layer to apply Shadow or Opacity in MultiEffect, or at least if elevationEnabled/opacity < 1
layer.smooth: false
layer.effect: MultiEffect {
readonly property var level: Theme.elevationLevel2
readonly property real _shadowBlur: Theme.elevationEnabled ? (level && level.blurPx !== undefined ? level.blurPx : 0) : 0
readonly property real _shadowSpread: Theme.elevationEnabled ? (level && level.spreadPx !== undefined ? level.spreadPx : 0) : 0
autoPaddingEnabled: true
blurEnabled: false
maskEnabled: false
shadowEnabled: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
shadowBlur: Math.max(0, Math.min(1, _shadowBlur / Math.max(1, Theme.elevationBlurMax)))
shadowScale: 1 + (2 * _shadowSpread) / Math.max(1, Math.min(_connectedSurfaceLayer.width, _connectedSurfaceLayer.height))
shadowHorizontalOffset: Theme.elevationOffsetXFor(level, Theme.elevationLightDirection, 4)
shadowVerticalOffset: Theme.elevationOffsetYFor(level, Theme.elevationLightDirection, 4)
shadowColor: Theme.elevationShadowColor(level)
shadowOpacity: 1
}
FrameBorder {
anchors.fill: parent
borderColor: win._opaqueSurfaceColor
@@ -671,7 +922,7 @@ PanelWindow {
readonly property string _notifSide: win._notifState.barSide
readonly property bool _isHoriz: _notifSide === "top" || _notifSide === "bottom"
readonly property real _notifCcr: Theme.snap(Math.max(0, Math.min(win._ccr, win._surfaceRadius, (_isHoriz ? _notifBodyBlurAnchor.width : _notifBodyBlurAnchor.height) / 2)), win._dpr)
readonly property real _notifCcr: win._effectiveNotifCcr
readonly property real _sideUnderlap: _isHoriz ? 0 : win._seamOverlap
readonly property real _bodyW: Theme.snap(_notifBodyBlurAnchor.width + _sideUnderlap, win._dpr)
readonly property real _bodyH: Theme.snap(_notifBodyBlurAnchor.height, win._dpr)

View File

@@ -41,6 +41,7 @@ PanelWindow {
required property string notificationId
readonly property bool hasValidData: notificationData && notificationData.notification
readonly property alias hovered: cardHoverHandler.hovered
readonly property alias swipeActive: content.swipeActive
property int screenY: 0
property bool exiting: false
property bool _isDestroying: false
@@ -64,8 +65,8 @@ PanelWindow {
readonly property real exitTravel: {
if (directionalEffect) {
if (isCenterPosition)
return content.height + entryTravel;
return content.width + entryTravel;
return Math.max(1, content.height);
return Math.max(1, content.width);
}
if (depthEffect)
return Math.round(entryTravel * 1.35);
@@ -186,7 +187,7 @@ PanelWindow {
enabled: !exiting && !_isDestroying
NumberAnimation {
id: implicitHeightAnim
duration: Theme.variantDuration(descriptionExpanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration, descriptionExpanded)
duration: descriptionExpanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: descriptionExpanded ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
onFinished: win.popupHeightChanged()
@@ -237,7 +238,8 @@ PanelWindow {
readonly property real maxPopupShadowBlurPx: Math.max((Theme.elevationLevel3 && Theme.elevationLevel3.blurPx !== undefined) ? Theme.elevationLevel3.blurPx : 12, (Theme.elevationLevel4 && Theme.elevationLevel4.blurPx !== undefined) ? Theme.elevationLevel4.blurPx : 16)
readonly property real maxPopupShadowOffsetXPx: Math.max(Math.abs(Theme.elevationOffsetX(Theme.elevationLevel3)), Math.abs(Theme.elevationOffsetX(Theme.elevationLevel4)))
readonly property real maxPopupShadowOffsetYPx: Math.max(Math.abs(Theme.elevationOffsetY(Theme.elevationLevel3, 6)), Math.abs(Theme.elevationOffsetY(Theme.elevationLevel4, 8)))
readonly property real windowShadowPad: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled ? Theme.snap(Math.max(16, maxPopupShadowBlurPx + Math.max(maxPopupShadowOffsetXPx, maxPopupShadowOffsetYPx) + 8), dpr) : 0
readonly property bool popupWindowShadowActive: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled && !connectedFrameMode
readonly property real windowShadowPad: popupWindowShadowActive ? Theme.snap(Math.max(16, maxPopupShadowBlurPx + Math.max(maxPopupShadowOffsetXPx, maxPopupShadowOffsetYPx) + 8), dpr) : 0
anchors.top: true
anchors.left: true
@@ -404,7 +406,7 @@ PanelWindow {
}
function popupChromeMotionActive() {
return exiting || content.swipeActive || content.swipeDismissing || Math.abs(content.swipeOffset) > 0.5;
return popupChromeOpenProgress() < 1 || exiting || content.swipeActive || content.swipeDismissing || Math.abs(content.swipeOffset) > 0.5;
}
function popupLayoutReservesSlot() {
@@ -415,13 +417,30 @@ PanelWindow {
return !content.swipeDismissing;
}
function _chromeMotionOffset() {
return isCenterPosition ? tx.y : tx.x;
}
function _chromeCardTravel() {
return Math.max(1, isCenterPosition ? alignedHeight : alignedWidth);
}
function popupChromeOpenProgress() {
if (exiting || content.swipeDismissing)
return 1;
return Math.max(0, Math.min(1, 1 - Math.abs(_chromeMotionOffset()) / _chromeCardTravel()));
}
function popupChromeReleaseProgress() {
if (exiting)
return Math.max(0, Math.min(1, Math.abs(_chromeMotionOffset()) / _chromeCardTravel()));
if (content.swipeDismissing)
return Math.max(0, Math.min(1, Math.abs(content.swipeOffset) / Math.max(1, content.swipeTravelDistance)));
if (!exiting)
return 0;
const exitOffset = isCenterPosition ? tx.y : tx.x;
return Math.max(0, Math.min(1, Math.abs(exitOffset) / Math.max(1, exitTravel)));
return 0;
}
function popupChromeFollowsCardMotion() {
return content.swipeActive || (content.swipeDismissing && !exiting);
}
function popupChromeMotionX() {
@@ -488,7 +507,7 @@ PanelWindow {
win.popupChromeGeometryChanged();
}
readonly property bool shadowsAllowed: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled
readonly property bool shadowsAllowed: win.popupWindowShadowActive
readonly property var elevLevel: cardHoverHandler.hovered ? Theme.elevationLevel4 : Theme.elevationLevel3
readonly property real cardInset: Theme.snap(4, win.dpr)
readonly property real shadowRenderPadding: shadowsAllowed ? Theme.snap(Math.max(16, shadowBlurPx + Math.max(Math.abs(shadowOffsetX), Math.abs(shadowOffsetY)) + 8), win.dpr) : 0
@@ -527,7 +546,7 @@ PanelWindow {
shadowOffsetX: content.shadowOffsetX
shadowOffsetY: content.shadowOffsetY
shadowColor: content.shadowsAllowed && content.elevLevel ? Theme.elevationShadowColor(content.elevLevel) : "transparent"
shadowEnabled: !win._isDestroying && win.screenValid && content.shadowsAllowed && !win.connectedFrameMode
shadowEnabled: !win._isDestroying && win.screenValid && content.shadowsAllowed
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
@@ -1091,7 +1110,7 @@ PanelWindow {
return isLeft ? -entryTravel : entryTravel;
}
to: 0
duration: Theme.variantDuration(Theme.notificationEnterDuration, true)
duration: Theme.notificationEnterDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.variantPopoutEnterCurve
onStopped: {
@@ -1124,7 +1143,7 @@ PanelWindow {
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
return isLeft ? -exitTravel : exitTravel;
}
duration: Theme.variantDuration(Theme.notificationExitDuration, false)
duration: Theme.notificationExitDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.variantPopoutExitCurve
}
@@ -1134,7 +1153,7 @@ PanelWindow {
property: "opacity"
from: 1
to: Theme.isDirectionalEffect ? 1 : 0
duration: Theme.variantDuration(Theme.notificationExitDuration, false)
duration: Theme.notificationExitDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.variantPopoutExitCurve
}
@@ -1144,7 +1163,7 @@ PanelWindow {
property: "scale"
from: 1
to: Theme.isDirectionalEffect ? 1 : Theme.effectScaleCollapsed
duration: Theme.variantDuration(Theme.notificationExitDuration, false)
duration: Theme.notificationExitDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.variantPopoutExitCurve
}

View File

@@ -35,6 +35,9 @@ QtObject {
property var pendingDestroys: []
property int destroyDelayMs: 100
property bool _chromeSyncPending: false
readonly property real chromeOpenProgressThreshold: 0.10
readonly property real chromeReleaseTailStart: 0.90
readonly property real chromeReleaseDropProgress: 0.995
property Component popupComponent
popupComponent: Component {
@@ -130,7 +133,20 @@ QtObject {
}
function _chromeWindows() {
return popupWindows.filter(p => p && p.status !== Component.Null && p.visible && !p._finalized && p.hasValidData && (p.notificationData?.popup || p.exiting));
return popupWindows.filter(p => {
if (!p || p.status === Component.Null || !p.visible || p._finalized || !p.hasValidData)
return false;
if (!p.notificationData?.popup && !p.exiting)
return false;
if (!p.exiting && p.popupChromeOpenProgress && p.popupChromeOpenProgress() < chromeOpenProgressThreshold)
return false;
// Keep the connected shell until the card is almost fully closed.
if (p.exiting && !p.swipeActive && p.popupChromeReleaseProgress) {
if (p.popupChromeReleaseProgress() > chromeReleaseDropProgress)
return false;
}
return true;
});
}
function _isFocusedScreen() {
@@ -225,23 +241,72 @@ QtObject {
});
}
function _clamp01(value) {
return Math.max(0, Math.min(1, value));
}
function _clipRectFromBarSide(rect, visibleFraction) {
const fraction = _clamp01(visibleFraction);
const w = Math.max(0, rect.right - rect.x);
const h = Math.max(0, rect.bottom - rect.y);
if (notifBarSide === "right") {
rect.x = rect.right - w * fraction;
} else if (notifBarSide === "left") {
rect.right = rect.x + w * fraction;
} else if (notifBarSide === "bottom") {
rect.y = rect.bottom - h * fraction;
} else {
rect.bottom = rect.y + h * fraction;
}
return rect;
}
function _popupChromeVisibleFraction(p) {
if (p.exiting && p.popupChromeReleaseProgress)
return 1 - _chromeReleaseTailProgress(p.popupChromeReleaseProgress());
if (!p.exiting && p.popupChromeOpenProgress)
return _clamp01(p.popupChromeOpenProgress());
return 1;
}
function _popupChromeRect(p, useMotionOffset) {
if (!p || !p.screen)
return null;
const motionX = useMotionOffset && p.popupChromeMotionX ? p.popupChromeMotionX() : 0;
const motionY = useMotionOffset && p.popupChromeMotionY ? p.popupChromeMotionY() : 0;
const x = (p.getContentX ? p.getContentX() : 0) + motionX;
const y = (p.getContentY ? p.getContentY() : 0) + motionY;
const x = p.getContentX ? p.getContentX() : 0;
const y = p.getContentY ? p.getContentY() : 0;
const w = p.alignedWidth || 0;
const h = Math.max(p.alignedHeight || 0, baseNotificationHeight);
if (w <= 0 || h <= 0)
return null;
return {
const rect = {
x: x,
y: y,
right: x + w,
bottom: y + h
};
if (!useMotionOffset)
return rect;
if (p.popupChromeFollowsCardMotion && p.popupChromeFollowsCardMotion()) {
const motionX = p.popupChromeMotionX ? p.popupChromeMotionX() : 0;
const motionY = p.popupChromeMotionY ? p.popupChromeMotionY() : 0;
rect.x += motionX;
rect.y += motionY;
rect.right += motionX;
rect.bottom += motionY;
return rect;
}
return _clipRectFromBarSide(rect, _popupChromeVisibleFraction(p));
}
function _chromeReleaseTailProgress(rawProgress) {
const progress = Math.max(0, Math.min(1, rawProgress));
if (progress <= chromeReleaseTailStart)
return 0;
return Math.max(0, Math.min(1, (progress - chromeReleaseTailStart) / Math.max(0.001, 1 - chromeReleaseTailStart)));
}
function _popupChromeBoundsRect(p, trailing, useMotionOffset) {
@@ -249,7 +314,7 @@ QtObject {
if (!rect || p !== trailing || !p.popupChromeReleaseProgress)
return rect;
const progress = Math.max(0, Math.min(1, p.popupChromeReleaseProgress()));
const progress = _chromeReleaseTailProgress(p.popupChromeReleaseProgress());
if (progress <= 0)
return rect;