mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-13 17:22:08 -04:00
frame(ConnectedMode): Wire up Notifications
This commit is contained in:
@@ -14,27 +14,22 @@ Item {
|
|||||||
required property real cutoutLeftInset
|
required property real cutoutLeftInset
|
||||||
required property real cutoutRightInset
|
required property real cutoutRightInset
|
||||||
required property real cutoutRadius
|
required property real cutoutRadius
|
||||||
|
property color borderColor: Qt.rgba(SettingsData.effectiveFrameColor.r, SettingsData.effectiveFrameColor.g, SettingsData.effectiveFrameColor.b, SettingsData.frameOpacity)
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: borderRect
|
id: borderRect
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
// Bake frameOpacity into the color alpha rather than using the `opacity` property.
|
// Bake frameOpacity into the color alpha rather than using the `opacity` property
|
||||||
// Qt Quick can skip layer.effect processing on items with opacity < 1 as an
|
color: root.borderColor
|
||||||
// optimization, causing the MultiEffect inverted mask to stop working and the
|
|
||||||
// Rectangle to render as a plain square at low opacity values.
|
|
||||||
color: Qt.rgba(SettingsData.effectiveFrameColor.r,
|
|
||||||
SettingsData.effectiveFrameColor.g,
|
|
||||||
SettingsData.effectiveFrameColor.b,
|
|
||||||
SettingsData.frameOpacity)
|
|
||||||
|
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
maskSource: cutoutMask
|
maskSource: cutoutMask
|
||||||
maskEnabled: true
|
maskEnabled: true
|
||||||
maskInverted: true
|
maskInverted: true
|
||||||
maskThresholdMin: 0.5
|
maskThresholdMin: 0.5
|
||||||
maskSpreadAtMin: 1
|
maskSpreadAtMin: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +42,11 @@ Item {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors {
|
anchors {
|
||||||
fill: parent
|
fill: parent
|
||||||
topMargin: root.cutoutTopInset
|
topMargin: root.cutoutTopInset
|
||||||
bottomMargin: root.cutoutBottomInset
|
bottomMargin: root.cutoutBottomInset
|
||||||
leftMargin: root.cutoutLeftInset
|
leftMargin: root.cutoutLeftInset
|
||||||
rightMargin: root.cutoutRightInset
|
rightMargin: root.cutoutRightInset
|
||||||
}
|
}
|
||||||
radius: root.cutoutRadius
|
radius: root.cutoutRadius
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ PanelWindow {
|
|||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0
|
"y": 0
|
||||||
})
|
})
|
||||||
|
readonly property var _notifState: ConnectedModeState.notificationStates[win._screenName] || ConnectedModeState.emptyNotificationState
|
||||||
|
|
||||||
// ─── Connected chrome convenience properties ──────────────────────────────
|
// ─── Connected chrome convenience properties ──────────────────────────────
|
||||||
readonly property bool _connectedActive: win._frameActive && SettingsData.connectedFrameModeActive
|
readonly property bool _connectedActive: win._frameActive && SettingsData.connectedFrameModeActive
|
||||||
@@ -218,6 +219,18 @@ PanelWindow {
|
|||||||
height: _active ? win._dockConnectorRadius() * 2 : 0
|
height: _active ? win._dockConnectorRadius() * 2 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: _notifBodyBlurAnchor
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
readonly property bool _active: win._frameActive && win._notifState.visible && win._notifState.bodyW > 0 && win._notifState.bodyH > 0
|
||||||
|
|
||||||
|
x: _active ? Theme.snap(win._notifState.bodyX, win._dpr) : 0
|
||||||
|
y: _active ? Theme.snap(win._notifState.bodyY, win._dpr) : 0
|
||||||
|
width: _active ? Theme.snap(win._notifState.bodyW, win._dpr) : 0
|
||||||
|
height: _active ? Theme.snap(win._notifState.bodyH, win._dpr) : 0
|
||||||
|
}
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
id: _staticBlurRegion
|
id: _staticBlurRegion
|
||||||
x: 0
|
x: 0
|
||||||
@@ -267,6 +280,11 @@ PanelWindow {
|
|||||||
radius: win._dockConnectorRadius()
|
radius: win._dockConnectorRadius()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Region {
|
||||||
|
item: _notifBodyBlurAnchor
|
||||||
|
radius: win._surfaceRadius
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Connector position helpers (dock) ─────────────────────────────────
|
// ─── Connector position helpers (dock) ─────────────────────────────────
|
||||||
@@ -528,7 +546,7 @@ PanelWindow {
|
|||||||
|
|
||||||
FrameBorder {
|
FrameBorder {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: win._frameActive
|
visible: win._frameActive && !win._connectedActive
|
||||||
cutoutTopInset: win.cutoutTopInset
|
cutoutTopInset: win.cutoutTopInset
|
||||||
cutoutBottomInset: win.cutoutBottomInset
|
cutoutBottomInset: win.cutoutBottomInset
|
||||||
cutoutLeftInset: win.cutoutLeftInset
|
cutoutLeftInset: win.cutoutLeftInset
|
||||||
@@ -539,98 +557,141 @@ PanelWindow {
|
|||||||
// ─── Connected chrome fills ───────────────────────────────────────────────
|
// ─── Connected chrome fills ───────────────────────────────────────────────
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: _connectedChrome
|
id: _connectedSurfaceLayer
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: win._connectedActive
|
visible: win._connectedActive
|
||||||
|
opacity: win._surfaceOpacity
|
||||||
|
layer.enabled: opacity < 1
|
||||||
|
layer.smooth: false
|
||||||
|
|
||||||
|
FrameBorder {
|
||||||
|
anchors.fill: parent
|
||||||
|
borderColor: win._opaqueSurfaceColor
|
||||||
|
cutoutTopInset: win.cutoutTopInset
|
||||||
|
cutoutBottomInset: win.cutoutBottomInset
|
||||||
|
cutoutLeftInset: win.cutoutLeftInset
|
||||||
|
cutoutRightInset: win.cutoutRightInset
|
||||||
|
cutoutRadius: win.cutoutRadius
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: _popoutChrome
|
id: _connectedChrome
|
||||||
visible: ConnectedModeState.popoutVisible && ConnectedModeState.popoutScreen === win._screenName
|
anchors.fill: parent
|
||||||
x: win._popoutChromeX()
|
visible: true
|
||||||
y: win._popoutChromeY()
|
|
||||||
width: win._popoutChromeWidth()
|
|
||||||
height: win._popoutChromeHeight()
|
|
||||||
opacity: win._surfaceOpacity
|
|
||||||
layer.enabled: opacity < 1
|
|
||||||
layer.smooth: false
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: _popoutClip
|
id: _popoutChrome
|
||||||
readonly property bool _barHoriz: ConnectedModeState.popoutBarSide === "top" || ConnectedModeState.popoutBarSide === "bottom"
|
visible: ConnectedModeState.popoutVisible && ConnectedModeState.popoutScreen === win._screenName
|
||||||
// Expand clip by ccr on bar axis to include arc columns
|
x: win._popoutChromeX()
|
||||||
x: win._popoutClipX() - (_barHoriz ? win._effectivePopoutCcr : 0)
|
y: win._popoutChromeY()
|
||||||
y: win._popoutClipY() - (_barHoriz ? 0 : win._effectivePopoutCcr)
|
width: win._popoutChromeWidth()
|
||||||
width: win._popoutClipWidth() + (_barHoriz ? win._effectivePopoutCcr * 2 : 0)
|
height: win._popoutChromeHeight()
|
||||||
height: win._popoutClipHeight() + (_barHoriz ? 0 : win._effectivePopoutCcr * 2)
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
ConnectedShape {
|
Item {
|
||||||
id: _popoutShape
|
id: _popoutClip
|
||||||
visible: _popoutBodyBlurAnchor._active && _popoutBodyBlurAnchor.width > 0 && _popoutBodyBlurAnchor.height > 0
|
readonly property bool _barHoriz: ConnectedModeState.popoutBarSide === "top" || ConnectedModeState.popoutBarSide === "bottom"
|
||||||
barSide: ConnectedModeState.popoutBarSide
|
// Expand clip by ccr on bar axis to include arc columns
|
||||||
bodyWidth: win._popoutClipWidth()
|
x: win._popoutClipX() - (_barHoriz ? win._effectivePopoutCcr : 0)
|
||||||
bodyHeight: win._popoutClipHeight()
|
y: win._popoutClipY() - (_barHoriz ? 0 : win._effectivePopoutCcr)
|
||||||
connectorRadius: win._effectivePopoutCcr
|
width: win._popoutClipWidth() + (_barHoriz ? win._effectivePopoutCcr * 2 : 0)
|
||||||
surfaceRadius: win._surfaceRadius
|
height: win._popoutClipHeight() + (_barHoriz ? 0 : win._effectivePopoutCcr * 2)
|
||||||
fillColor: win._opaqueSurfaceColor
|
clip: true
|
||||||
x: 0
|
|
||||||
y: 0
|
ConnectedShape {
|
||||||
|
id: _popoutShape
|
||||||
|
visible: _popoutBodyBlurAnchor._active && _popoutBodyBlurAnchor.width > 0 && _popoutBodyBlurAnchor.height > 0
|
||||||
|
barSide: ConnectedModeState.popoutBarSide
|
||||||
|
bodyWidth: win._popoutClipWidth()
|
||||||
|
bodyHeight: win._popoutClipHeight()
|
||||||
|
connectorRadius: win._effectivePopoutCcr
|
||||||
|
surfaceRadius: win._surfaceRadius
|
||||||
|
fillColor: win._opaqueSurfaceColor
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: _dockChrome
|
||||||
|
visible: _dockBodyBlurAnchor._active
|
||||||
|
x: win._dockChromeX()
|
||||||
|
y: win._dockChromeY()
|
||||||
|
width: win._dockChromeWidth()
|
||||||
|
height: win._dockChromeHeight()
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: _dockFill
|
||||||
|
x: win._dockBodyXInChrome()
|
||||||
|
y: win._dockBodyYInChrome()
|
||||||
|
width: _dockBodyBlurAnchor.width + win._dockFillOverlapX() * 2
|
||||||
|
height: _dockBodyBlurAnchor.height + win._dockFillOverlapY() * 2
|
||||||
|
color: win._opaqueSurfaceColor
|
||||||
|
z: 1
|
||||||
|
|
||||||
|
readonly property string _dockSide: win._dockState.barSide
|
||||||
|
readonly property real _dockRadius: win._dockBodyBlurRadius()
|
||||||
|
topLeftRadius: (_dockSide === "top" || _dockSide === "left") ? 0 : _dockRadius
|
||||||
|
topRightRadius: (_dockSide === "top" || _dockSide === "right") ? 0 : _dockRadius
|
||||||
|
bottomLeftRadius: (_dockSide === "bottom" || _dockSide === "left") ? 0 : _dockRadius
|
||||||
|
bottomRightRadius: (_dockSide === "bottom" || _dockSide === "right") ? 0 : _dockRadius
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
id: _connDockLeft
|
||||||
|
visible: _dockBodyBlurAnchor._active
|
||||||
|
barSide: win._dockState.barSide
|
||||||
|
placement: "left"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: win._dockConnectorRadius()
|
||||||
|
color: win._opaqueSurfaceColor
|
||||||
|
dpr: win._dpr
|
||||||
|
x: Theme.snap(win._dockConnectorX(_dockBodyBlurAnchor.x, _dockBodyBlurAnchor.width, "left", 0) - _dockChrome.x, win._dpr)
|
||||||
|
y: Theme.snap(win._dockConnectorY(_dockBodyBlurAnchor.y, _dockBodyBlurAnchor.height, "left", 0) - _dockChrome.y, win._dpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
id: _connDockRight
|
||||||
|
visible: _dockBodyBlurAnchor._active
|
||||||
|
barSide: win._dockState.barSide
|
||||||
|
placement: "right"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: win._dockConnectorRadius()
|
||||||
|
color: win._opaqueSurfaceColor
|
||||||
|
dpr: win._dpr
|
||||||
|
x: Theme.snap(win._dockConnectorX(_dockBodyBlurAnchor.x, _dockBodyBlurAnchor.width, "right", 0) - _dockChrome.x, win._dpr)
|
||||||
|
y: Theme.snap(win._dockConnectorY(_dockBodyBlurAnchor.y, _dockBodyBlurAnchor.height, "right", 0) - _dockChrome.y, win._dpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: _dockChrome
|
id: _notifChrome
|
||||||
visible: _dockBodyBlurAnchor._active
|
visible: _notifBodyBlurAnchor._active
|
||||||
x: win._dockChromeX()
|
|
||||||
y: win._dockChromeY()
|
|
||||||
width: win._dockChromeWidth()
|
|
||||||
height: win._dockChromeHeight()
|
|
||||||
opacity: win._surfaceOpacity
|
|
||||||
layer.enabled: opacity < 1
|
|
||||||
layer.smooth: false
|
|
||||||
|
|
||||||
Rectangle {
|
readonly property string _notifSide: win._notifState.barSide
|
||||||
id: _dockFill
|
readonly property bool _isHoriz: _notifSide === "top" || _notifSide === "bottom"
|
||||||
x: win._dockBodyXInChrome()
|
readonly property real _notifCcr: Theme.snap(Math.max(0, Math.min(win._ccr, win._surfaceRadius, (_isHoriz ? _notifBodyBlurAnchor.width : _notifBodyBlurAnchor.height) / 2)), win._dpr)
|
||||||
y: win._dockBodyYInChrome()
|
readonly property real _sideUnderlap: _isHoriz ? 0 : win._seamOverlap
|
||||||
width: _dockBodyBlurAnchor.width + win._dockFillOverlapX() * 2
|
readonly property real _bodyW: Theme.snap(_notifBodyBlurAnchor.width + _sideUnderlap, win._dpr)
|
||||||
height: _dockBodyBlurAnchor.height + win._dockFillOverlapY() * 2
|
readonly property real _bodyH: Theme.snap(_notifBodyBlurAnchor.height, win._dpr)
|
||||||
color: win._opaqueSurfaceColor
|
|
||||||
z: 1
|
|
||||||
|
|
||||||
readonly property string _dockSide: win._dockState.barSide
|
z: _isHoriz ? 0 : -1
|
||||||
readonly property real _dockRadius: win._dockBodyBlurRadius()
|
x: Theme.snap(_notifBodyBlurAnchor.x - (_isHoriz ? _notifCcr : (_notifSide === "left" ? _sideUnderlap : 0)), win._dpr)
|
||||||
topLeftRadius: (_dockSide === "top" || _dockSide === "left") ? 0 : _dockRadius
|
y: Theme.snap(_notifBodyBlurAnchor.y - (_isHoriz ? 0 : _notifCcr), win._dpr)
|
||||||
topRightRadius: (_dockSide === "top" || _dockSide === "right") ? 0 : _dockRadius
|
width: _isHoriz ? Theme.snap(_bodyW + _notifCcr * 2, win._dpr) : _bodyW
|
||||||
bottomLeftRadius: (_dockSide === "bottom" || _dockSide === "left") ? 0 : _dockRadius
|
height: Theme.snap(_bodyH + (_isHoriz ? 0 : _notifCcr * 2), win._dpr)
|
||||||
bottomRightRadius: (_dockSide === "bottom" || _dockSide === "right") ? 0 : _dockRadius
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectedCorner {
|
ConnectedShape {
|
||||||
id: _connDockLeft
|
visible: _notifBodyBlurAnchor._active && _notifBodyBlurAnchor.width > 0 && _notifBodyBlurAnchor.height > 0
|
||||||
visible: _dockBodyBlurAnchor._active
|
barSide: _notifChrome._notifSide
|
||||||
barSide: win._dockState.barSide
|
bodyWidth: _notifChrome._bodyW
|
||||||
placement: "left"
|
bodyHeight: _notifChrome._bodyH
|
||||||
spacing: 0
|
connectorRadius: _notifChrome._notifCcr
|
||||||
connectorRadius: win._dockConnectorRadius()
|
surfaceRadius: win._surfaceRadius
|
||||||
color: win._opaqueSurfaceColor
|
fillColor: win._opaqueSurfaceColor
|
||||||
dpr: win._dpr
|
x: 0
|
||||||
x: Theme.snap(win._dockConnectorX(_dockBodyBlurAnchor.x, _dockBodyBlurAnchor.width, "left", 0) - _dockChrome.x, win._dpr)
|
y: 0
|
||||||
y: Theme.snap(win._dockConnectorY(_dockBodyBlurAnchor.y, _dockBodyBlurAnchor.height, "left", 0) - _dockChrome.y, win._dpr)
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectedCorner {
|
|
||||||
id: _connDockRight
|
|
||||||
visible: _dockBodyBlurAnchor._active
|
|
||||||
barSide: win._dockState.barSide
|
|
||||||
placement: "right"
|
|
||||||
spacing: 0
|
|
||||||
connectorRadius: win._dockConnectorRadius()
|
|
||||||
color: win._opaqueSurfaceColor
|
|
||||||
dpr: win._dpr
|
|
||||||
x: Theme.snap(win._dockConnectorX(_dockBodyBlurAnchor.x, _dockBodyBlurAnchor.width, "right", 0) - _dockChrome.x, win._dpr)
|
|
||||||
y: Theme.snap(win._dockConnectorY(_dockBodyBlurAnchor.y, _dockBodyBlurAnchor.height, "right", 0) - _dockChrome.y, win._dpr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,29 @@ import qs.Widgets
|
|||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: win
|
id: win
|
||||||
|
|
||||||
|
readonly property bool connectedFrameMode: SettingsData.frameEnabled
|
||||||
|
&& Theme.isConnectedEffect
|
||||||
|
&& SettingsData.isScreenInPreferences(win.screen, SettingsData.frameScreenPreferences)
|
||||||
|
readonly property string notifBarSide: {
|
||||||
|
const pos = SettingsData.notificationPopupPosition;
|
||||||
|
if (pos === -1) return "top";
|
||||||
|
switch (pos) {
|
||||||
|
case SettingsData.Position.Top: return "right";
|
||||||
|
case SettingsData.Position.Left: return "left";
|
||||||
|
case SettingsData.Position.BottomCenter: return "bottom";
|
||||||
|
case SettingsData.Position.Right: return "right";
|
||||||
|
case SettingsData.Position.Bottom: return "left";
|
||||||
|
default: return "top";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WindowBlur {
|
WindowBlur {
|
||||||
targetWindow: win
|
targetWindow: win
|
||||||
blurX: content.x + content.cardInset + swipeTx.x + tx.x
|
blurX: content.x + content.cardInset + swipeTx.x + tx.x
|
||||||
blurY: content.y + content.cardInset + swipeTx.y + tx.y
|
blurY: content.y + content.cardInset + swipeTx.y + tx.y
|
||||||
blurWidth: !win._finalized ? Math.max(0, content.width - content.cardInset * 2) : 0
|
blurWidth: !win._finalized && !win.connectedFrameMode ? Math.max(0, content.width - content.cardInset * 2) : 0
|
||||||
blurHeight: !win._finalized ? Math.max(0, content.height - content.cardInset * 2) : 0
|
blurHeight: !win._finalized && !win.connectedFrameMode ? Math.max(0, content.height - content.cardInset * 2) : 0
|
||||||
blurRadius: SettingsData.connectedFrameModeActive ? Theme.connectedSurfaceRadius : Theme.cornerRadius
|
blurRadius: win.connectedFrameMode ? Theme.connectedSurfaceRadius : Theme.cornerRadius
|
||||||
}
|
}
|
||||||
|
|
||||||
WlrLayershell.namespace: "dms:notification-popup"
|
WlrLayershell.namespace: "dms:notification-popup"
|
||||||
@@ -84,6 +100,7 @@ PanelWindow {
|
|||||||
signal exitStarted
|
signal exitStarted
|
||||||
signal exitFinished
|
signal exitFinished
|
||||||
signal popupHeightChanged
|
signal popupHeightChanged
|
||||||
|
signal popupChromeGeometryChanged
|
||||||
|
|
||||||
function startExit() {
|
function startExit() {
|
||||||
if (exiting || _isDestroying) {
|
if (exiting || _isDestroying) {
|
||||||
@@ -91,6 +108,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
exiting = true;
|
exiting = true;
|
||||||
exitStarted();
|
exitStarted();
|
||||||
|
popupChromeGeometryChanged();
|
||||||
exitAnim.restart();
|
exitAnim.restart();
|
||||||
exitWatchdog.restart();
|
exitWatchdog.restart();
|
||||||
if (NotificationService.removeFromVisibleNotifications)
|
if (NotificationService.removeFromVisibleNotifications)
|
||||||
@@ -171,6 +189,7 @@ PanelWindow {
|
|||||||
duration: Theme.variantDuration(descriptionExpanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration, descriptionExpanded)
|
duration: Theme.variantDuration(descriptionExpanded ? Theme.notificationExpandDuration : Theme.notificationCollapseDuration, descriptionExpanded)
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: descriptionExpanded ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
|
easing.bezierCurve: descriptionExpanded ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
|
||||||
|
onFinished: win.popupHeightChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,12 +282,24 @@ PanelWindow {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _frameEdgeInset(side) {
|
||||||
|
if (!screen)
|
||||||
|
return 0;
|
||||||
|
const edges = SettingsData.getActiveBarEdgesForScreen(screen);
|
||||||
|
const raw = edges.includes(side) ? SettingsData.frameBarSize : SettingsData.frameThickness;
|
||||||
|
return Math.max(0, Math.round(Theme.px(raw, dpr)));
|
||||||
|
}
|
||||||
|
|
||||||
function getTopMargin() {
|
function getTopMargin() {
|
||||||
const popupPos = SettingsData.notificationPopupPosition;
|
const popupPos = SettingsData.notificationPopupPosition;
|
||||||
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left;
|
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left;
|
||||||
if (!isTop)
|
if (!isTop)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (connectedFrameMode) {
|
||||||
|
const cornerClear = isCenterPosition ? 0 : (Theme.px(SettingsData.frameRounding, dpr) + Theme.px(Theme.connectedCornerRadius, dpr));
|
||||||
|
return _frameEdgeInset("top") + cornerClear + screenY;
|
||||||
|
}
|
||||||
const barInfo = getBarInfo();
|
const barInfo = getBarInfo();
|
||||||
const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance;
|
const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance;
|
||||||
return base + screenY;
|
return base + screenY;
|
||||||
@@ -280,6 +311,10 @@ PanelWindow {
|
|||||||
if (!isBottom)
|
if (!isBottom)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (connectedFrameMode) {
|
||||||
|
const cornerClear = isCenterPosition ? 0 : (Theme.px(SettingsData.frameRounding, dpr) + Theme.px(Theme.connectedCornerRadius, dpr));
|
||||||
|
return _frameEdgeInset("bottom") + cornerClear + screenY;
|
||||||
|
}
|
||||||
const barInfo = getBarInfo();
|
const barInfo = getBarInfo();
|
||||||
const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance;
|
const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance;
|
||||||
return base + screenY;
|
return base + screenY;
|
||||||
@@ -294,6 +329,8 @@ PanelWindow {
|
|||||||
if (!isLeft)
|
if (!isLeft)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (connectedFrameMode)
|
||||||
|
return _frameEdgeInset("left");
|
||||||
const barInfo = getBarInfo();
|
const barInfo = getBarInfo();
|
||||||
return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance;
|
return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance;
|
||||||
}
|
}
|
||||||
@@ -307,6 +344,8 @@ PanelWindow {
|
|||||||
if (!isRight)
|
if (!isRight)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (connectedFrameMode)
|
||||||
|
return _frameEdgeInset("right");
|
||||||
const barInfo = getBarInfo();
|
const barInfo = getBarInfo();
|
||||||
return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance;
|
return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance;
|
||||||
}
|
}
|
||||||
@@ -351,10 +390,64 @@ PanelWindow {
|
|||||||
return Theme.snap(getContentY() - windowShadowPad, dpr);
|
return Theme.snap(getContentY() - windowShadowPad, dpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _swipeDismissTarget() {
|
||||||
|
return (content.swipeDismissDirection < 0 ? -1 : 1) * content.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _frameEdgeSwipeDirection() {
|
||||||
|
const popupPos = SettingsData.notificationPopupPosition;
|
||||||
|
return (popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _swipeDismissesTowardFrameEdge() {
|
||||||
|
return content.swipeDismissDirection === _frameEdgeSwipeDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupChromeMotionActive() {
|
||||||
|
return exiting || content.swipeActive || content.swipeDismissing || Math.abs(content.swipeOffset) > 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupLayoutReservesSlot() {
|
||||||
|
return !content.swipeDismissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupChromeReservesSlot() {
|
||||||
|
return !content.swipeDismissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupChromeReleaseProgress() {
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupChromeMotionX() {
|
||||||
|
if (!popupChromeMotionActive() || isCenterPosition)
|
||||||
|
return 0;
|
||||||
|
const motion = content.swipeOffset + tx.x;
|
||||||
|
if (content.swipeDismissing && !_swipeDismissesTowardFrameEdge())
|
||||||
|
return exiting ? Theme.snap(tx.x, dpr) : 0;
|
||||||
|
if (content.swipeActive && motion * _frameEdgeSwipeDirection() < 0)
|
||||||
|
return 0;
|
||||||
|
return Theme.snap(motion, dpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupChromeMotionY() {
|
||||||
|
return popupChromeMotionActive() ? Theme.snap(tx.y, dpr) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
readonly property bool screenValid: win.screen && !_isDestroying
|
readonly property bool screenValid: win.screen && !_isDestroying
|
||||||
readonly property real dpr: screenValid ? CompositorService.getScreenScale(win.screen) : 1
|
readonly property real dpr: screenValid ? CompositorService.getScreenScale(win.screen) : 1
|
||||||
readonly property real alignedWidth: Theme.px(Math.max(0, implicitWidth - (windowShadowPad * 2)), dpr)
|
readonly property real alignedWidth: Theme.px(Math.max(0, implicitWidth - (windowShadowPad * 2)), dpr)
|
||||||
readonly property real alignedHeight: Theme.px(Math.max(0, implicitHeight - (windowShadowPad * 2)), dpr)
|
readonly property real alignedHeight: Theme.px(Math.max(0, implicitHeight - (windowShadowPad * 2)), dpr)
|
||||||
|
onScreenYChanged: popupChromeGeometryChanged()
|
||||||
|
onScreenChanged: popupChromeGeometryChanged()
|
||||||
|
onConnectedFrameModeChanged: popupChromeGeometryChanged()
|
||||||
|
onAlignedWidthChanged: popupChromeGeometryChanged()
|
||||||
|
onAlignedHeightChanged: popupChromeGeometryChanged()
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: content
|
id: content
|
||||||
@@ -363,7 +456,7 @@ PanelWindow {
|
|||||||
y: Theme.snap(windowShadowPad, dpr)
|
y: Theme.snap(windowShadowPad, dpr)
|
||||||
width: alignedWidth
|
width: alignedWidth
|
||||||
height: alignedHeight
|
height: alignedHeight
|
||||||
visible: !win._finalized
|
visible: !win._finalized && !chromeOnlyExit
|
||||||
scale: cardHoverHandler.hovered ? 1.01 : 1.0
|
scale: cardHoverHandler.hovered ? 1.01 : 1.0
|
||||||
transformOrigin: Item.Center
|
transformOrigin: Item.Center
|
||||||
|
|
||||||
@@ -375,13 +468,25 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
property real swipeOffset: 0
|
property real swipeOffset: 0
|
||||||
readonly property real dismissThreshold: isCenterPosition ? height * 0.4 : width * 0.35
|
property real swipeDismissDirection: 1
|
||||||
|
property bool chromeOnlyExit: false
|
||||||
|
readonly property real dismissThreshold: width * 0.35
|
||||||
readonly property real swipeFadeStartRatio: 0.75
|
readonly property real swipeFadeStartRatio: 0.75
|
||||||
readonly property real swipeTravelDistance: isCenterPosition ? height : width
|
readonly property real swipeTravelDistance: width
|
||||||
readonly property real swipeFadeStartOffset: swipeTravelDistance * swipeFadeStartRatio
|
readonly property real swipeFadeStartOffset: swipeTravelDistance * swipeFadeStartRatio
|
||||||
readonly property real swipeFadeDistance: Math.max(1, swipeTravelDistance - swipeFadeStartOffset)
|
readonly property real swipeFadeDistance: Math.max(1, swipeTravelDistance - swipeFadeStartOffset)
|
||||||
readonly property bool swipeActive: swipeDragHandler.active
|
readonly property bool swipeActive: swipeDragHandler.active
|
||||||
property bool swipeDismissing: false
|
property bool swipeDismissing: false
|
||||||
|
onSwipeDismissingChanged: {
|
||||||
|
if (!win.connectedFrameMode)
|
||||||
|
return;
|
||||||
|
win.popupHeightChanged();
|
||||||
|
win.popupChromeGeometryChanged();
|
||||||
|
}
|
||||||
|
onSwipeOffsetChanged: {
|
||||||
|
if (win.connectedFrameMode)
|
||||||
|
win.popupChromeGeometryChanged();
|
||||||
|
}
|
||||||
|
|
||||||
readonly property bool shadowsAllowed: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled
|
readonly property bool shadowsAllowed: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled
|
||||||
readonly property var elevLevel: cardHoverHandler.hovered ? Theme.elevationLevel4 : Theme.elevationLevel3
|
readonly property var elevLevel: cardHoverHandler.hovered ? Theme.elevationLevel4 : Theme.elevationLevel3
|
||||||
@@ -422,7 +527,7 @@ PanelWindow {
|
|||||||
shadowOffsetX: content.shadowOffsetX
|
shadowOffsetX: content.shadowOffsetX
|
||||||
shadowOffsetY: content.shadowOffsetY
|
shadowOffsetY: content.shadowOffsetY
|
||||||
shadowColor: content.shadowsAllowed && content.elevLevel ? Theme.elevationShadowColor(content.elevLevel) : "transparent"
|
shadowColor: content.shadowsAllowed && content.elevLevel ? Theme.elevationShadowColor(content.elevLevel) : "transparent"
|
||||||
shadowEnabled: !win._isDestroying && win.screenValid && content.shadowsAllowed
|
shadowEnabled: !win._isDestroying && win.screenValid && content.shadowsAllowed && !win.connectedFrameMode
|
||||||
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
|
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
|
||||||
layer.textureMirroring: ShaderEffectSource.MirrorVertically
|
layer.textureMirroring: ShaderEffectSource.MirrorVertically
|
||||||
|
|
||||||
@@ -431,8 +536,12 @@ PanelWindow {
|
|||||||
sourceRect.y: content.shadowRenderPadding + content.cardInset
|
sourceRect.y: content.shadowRenderPadding + content.cardInset
|
||||||
sourceRect.width: Math.max(0, content.width - (content.cardInset * 2))
|
sourceRect.width: Math.max(0, content.width - (content.cardInset * 2))
|
||||||
sourceRect.height: Math.max(0, content.height - (content.cardInset * 2))
|
sourceRect.height: Math.max(0, content.height - (content.cardInset * 2))
|
||||||
sourceRect.radius: Theme.cornerRadius
|
sourceRect.radius: win.connectedFrameMode ? Theme.connectedSurfaceRadius : Theme.cornerRadius
|
||||||
sourceRect.color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
sourceRect.color: win.connectedFrameMode ? Theme.popupLayerColor(Theme.surfaceContainer) : Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||||
|
sourceRect.antialiasing: true
|
||||||
|
sourceRect.layer.enabled: win.connectedFrameMode
|
||||||
|
sourceRect.layer.smooth: true
|
||||||
|
sourceRect.layer.textureSize: win.connectedFrameMode && win.dpr > 1 ? Qt.size(Math.ceil(sourceRect.width * win.dpr), Math.ceil(sourceRect.height * win.dpr)) : Qt.size(0, 0)
|
||||||
sourceRect.border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.outline, 0.08)
|
sourceRect.border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.outline, 0.08)
|
||||||
sourceRect.border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
|
sourceRect.border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
|
||||||
|
|
||||||
@@ -470,10 +579,10 @@ PanelWindow {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: content.cardInset
|
anchors.margins: content.cardInset
|
||||||
radius: Theme.cornerRadius
|
radius: win.connectedFrameMode ? Theme.connectedSurfaceRadius : Theme.cornerRadius
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
border.color: BlurService.borderColor
|
border.color: win.connectedFrameMode ? "transparent" : BlurService.borderColor
|
||||||
border.width: BlurService.borderWidth
|
border.width: win.connectedFrameMode ? 0 : BlurService.borderWidth
|
||||||
z: 100
|
z: 100
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,14 +982,15 @@ PanelWindow {
|
|||||||
DragHandler {
|
DragHandler {
|
||||||
id: swipeDragHandler
|
id: swipeDragHandler
|
||||||
target: null
|
target: null
|
||||||
xAxis.enabled: !isCenterPosition
|
xAxis.enabled: true
|
||||||
yAxis.enabled: isCenterPosition
|
yAxis.enabled: false
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
if (active || win.exiting || content.swipeDismissing)
|
if (active || win.exiting || content.swipeDismissing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Math.abs(content.swipeOffset) > content.dismissThreshold) {
|
if (Math.abs(content.swipeOffset) > content.dismissThreshold) {
|
||||||
|
content.swipeDismissDirection = content.swipeOffset < 0 ? -1 : 1;
|
||||||
content.swipeDismissing = true;
|
content.swipeDismissing = true;
|
||||||
swipeDismissAnim.start();
|
swipeDismissAnim.start();
|
||||||
} else {
|
} else {
|
||||||
@@ -892,15 +1002,7 @@ PanelWindow {
|
|||||||
if (win.exiting)
|
if (win.exiting)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const raw = isCenterPosition ? translation.y : translation.x;
|
content.swipeOffset = 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,20 +1033,28 @@ PanelWindow {
|
|||||||
id: swipeDismissAnim
|
id: swipeDismissAnim
|
||||||
target: content
|
target: content
|
||||||
property: "swipeOffset"
|
property: "swipeOffset"
|
||||||
to: isTopCenter ? -content.height : isBottomCenter ? content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width)
|
to: win._swipeDismissTarget()
|
||||||
duration: Theme.notificationExitDuration
|
duration: Theme.notificationExitDuration
|
||||||
easing.type: Easing.OutCubic
|
easing.type: Easing.OutCubic
|
||||||
onStopped: {
|
onStopped: {
|
||||||
NotificationService.dismissNotification(notificationData);
|
const inwardConnectedExit = win.connectedFrameMode && !win.isCenterPosition && !win._swipeDismissesTowardFrameEdge();
|
||||||
win.forceExit();
|
if (inwardConnectedExit)
|
||||||
|
content.chromeOnlyExit = true;
|
||||||
|
if (win.connectedFrameMode && (win.isCenterPosition || inwardConnectedExit)) {
|
||||||
|
win.startExit();
|
||||||
|
NotificationService.dismissNotification(notificationData);
|
||||||
|
} else {
|
||||||
|
NotificationService.dismissNotification(notificationData);
|
||||||
|
win.forceExit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transform: [
|
transform: [
|
||||||
Translate {
|
Translate {
|
||||||
id: swipeTx
|
id: swipeTx
|
||||||
x: isCenterPosition ? 0 : content.swipeOffset
|
x: content.swipeOffset
|
||||||
y: isCenterPosition ? content.swipeOffset : 0
|
y: 0
|
||||||
},
|
},
|
||||||
Translate {
|
Translate {
|
||||||
id: tx
|
id: tx
|
||||||
@@ -955,6 +1065,14 @@ PanelWindow {
|
|||||||
return isLeft ? -entryTravel : entryTravel;
|
return isLeft ? -entryTravel : entryTravel;
|
||||||
}
|
}
|
||||||
y: isTopCenter ? -entryTravel : isBottomCenter ? entryTravel : 0
|
y: isTopCenter ? -entryTravel : isBottomCenter ? entryTravel : 0
|
||||||
|
onXChanged: {
|
||||||
|
if (win.connectedFrameMode)
|
||||||
|
win.popupChromeGeometryChanged();
|
||||||
|
}
|
||||||
|
onYChanged: {
|
||||||
|
if (win.connectedFrameMode)
|
||||||
|
win.popupChromeGeometryChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,24 +8,40 @@ QtObject {
|
|||||||
property var modelData
|
property var modelData
|
||||||
property int topMargin: 0
|
property int topMargin: 0
|
||||||
readonly property bool compactMode: SettingsData.notificationCompactMode
|
readonly property bool compactMode: SettingsData.notificationCompactMode
|
||||||
readonly property bool connectedFrameMode: SettingsData.connectedFrameModeActive
|
readonly property bool notificationConnectedMode: SettingsData.frameEnabled
|
||||||
|
&& Theme.isConnectedEffect
|
||||||
|
&& SettingsData.isScreenInPreferences(manager.modelData, SettingsData.frameScreenPreferences)
|
||||||
|
readonly property string notifBarSide: {
|
||||||
|
const pos = SettingsData.notificationPopupPosition;
|
||||||
|
if (pos === -1) return "top";
|
||||||
|
switch (pos) {
|
||||||
|
case SettingsData.Position.Top: return "right";
|
||||||
|
case SettingsData.Position.Left: return "left";
|
||||||
|
case SettingsData.Position.BottomCenter: return "bottom";
|
||||||
|
case SettingsData.Position.Right: return "right";
|
||||||
|
case SettingsData.Position.Bottom: return "left";
|
||||||
|
default: return "top";
|
||||||
|
}
|
||||||
|
}
|
||||||
readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding
|
readonly property real cardPadding: compactMode ? Theme.notificationCardPaddingCompact : Theme.notificationCardPadding
|
||||||
readonly property real popupIconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal
|
readonly property real popupIconSize: compactMode ? Theme.notificationIconSizeCompact : Theme.notificationIconSizeNormal
|
||||||
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
||||||
readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS
|
readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS
|
||||||
readonly property real popupSpacing: connectedFrameMode ? 0 : (compactMode ? 0 : Theme.spacingXS)
|
readonly property real popupSpacing: notificationConnectedMode ? 0 : (compactMode ? 0 : Theme.spacingXS)
|
||||||
readonly property real collapsedContentHeight: Math.max(popupIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2))
|
readonly property real collapsedContentHeight: Math.max(popupIconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2))
|
||||||
readonly property int baseNotificationHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing + popupSpacing
|
readonly property int baseNotificationHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing + popupSpacing
|
||||||
property var popupWindows: []
|
property var popupWindows: []
|
||||||
property var destroyingWindows: new Set()
|
property var destroyingWindows: new Set()
|
||||||
property var pendingDestroys: []
|
property var pendingDestroys: []
|
||||||
property int destroyDelayMs: 100
|
property int destroyDelayMs: 100
|
||||||
|
property bool _chromeSyncPending: false
|
||||||
property Component popupComponent
|
property Component popupComponent
|
||||||
|
|
||||||
popupComponent: Component {
|
popupComponent: Component {
|
||||||
NotificationPopup {
|
NotificationPopup {
|
||||||
onExitFinished: manager._onPopupExitFinished(this)
|
onExitFinished: manager._onPopupExitFinished(this)
|
||||||
onPopupHeightChanged: manager._onPopupHeightChanged(this)
|
onPopupHeightChanged: manager._onPopupHeightChanged(this)
|
||||||
|
onPopupChromeGeometryChanged: manager._onPopupChromeGeometryChanged(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +125,14 @@ QtObject {
|
|||||||
return p && p.status !== Component.Null && !p._isDestroying && p.hasValidData;
|
return p && p.status !== Component.Null && !p._isDestroying && p.hasValidData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _layoutWindows() {
|
||||||
|
return popupWindows.filter(p => _isValidWindow(p) && p.notificationData?.popup && !p.exiting && (!p.popupLayoutReservesSlot || p.popupLayoutReservesSlot()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function _chromeWindows() {
|
||||||
|
return popupWindows.filter(p => p && p.status !== Component.Null && p.visible && !p._finalized && p.hasValidData && (p.notificationData?.popup || p.exiting));
|
||||||
|
}
|
||||||
|
|
||||||
function _isFocusedScreen() {
|
function _isFocusedScreen() {
|
||||||
if (!SettingsData.notificationFocusedMonitor)
|
if (!SettingsData.notificationFocusedMonitor)
|
||||||
return true;
|
return true;
|
||||||
@@ -117,18 +141,24 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _sync(newWrappers) {
|
function _sync(newWrappers) {
|
||||||
|
let needsReposition = false;
|
||||||
for (const p of popupWindows.slice()) {
|
for (const p of popupWindows.slice()) {
|
||||||
if (!_isValidWindow(p) || p.exiting)
|
if (!_isValidWindow(p) || p.exiting)
|
||||||
continue;
|
continue;
|
||||||
if (p.notificationData && newWrappers.indexOf(p.notificationData) === -1) {
|
if (p.notificationData && newWrappers.indexOf(p.notificationData) === -1) {
|
||||||
p.notificationData.removedByLimit = true;
|
p.notificationData.removedByLimit = true;
|
||||||
p.notificationData.popup = false;
|
p.notificationData.popup = false;
|
||||||
|
needsReposition = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const w of newWrappers) {
|
for (const w of newWrappers) {
|
||||||
if (w && !_hasWindowFor(w) && _isFocusedScreen())
|
if (w && !_hasWindowFor(w) && _isFocusedScreen()) {
|
||||||
_insertAtTop(w);
|
_insertAtTop(w);
|
||||||
|
needsReposition = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (needsReposition)
|
||||||
|
_repositionAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _popupHeight(p) {
|
function _popupHeight(p) {
|
||||||
@@ -158,7 +188,7 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _repositionAll() {
|
function _repositionAll() {
|
||||||
const active = popupWindows.filter(p => _isValidWindow(p) && p.notificationData?.popup && !p.exiting);
|
const active = _layoutWindows();
|
||||||
|
|
||||||
const pinnedSlots = [];
|
const pinnedSlots = [];
|
||||||
for (const p of active) {
|
for (const p of active) {
|
||||||
@@ -182,6 +212,168 @@ QtObject {
|
|||||||
win.screenY = currentY;
|
win.screenY = currentY;
|
||||||
currentY += _popupHeight(win);
|
currentY += _popupHeight(win);
|
||||||
}
|
}
|
||||||
|
_scheduleNotificationChromeSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _scheduleNotificationChromeSync() {
|
||||||
|
if (_chromeSyncPending)
|
||||||
|
return;
|
||||||
|
_chromeSyncPending = true;
|
||||||
|
Qt.callLater(() => {
|
||||||
|
_chromeSyncPending = false;
|
||||||
|
_syncNotificationChromeState();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 w = p.alignedWidth || 0;
|
||||||
|
const h = Math.max(p.alignedHeight || 0, baseNotificationHeight);
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
return null;
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
right: x + w,
|
||||||
|
bottom: y + h
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _popupChromeBoundsRect(p, trailing, useMotionOffset) {
|
||||||
|
const rect = _popupChromeRect(p, useMotionOffset);
|
||||||
|
if (!rect || p !== trailing || !p.popupChromeReleaseProgress)
|
||||||
|
return rect;
|
||||||
|
|
||||||
|
const progress = Math.max(0, Math.min(1, p.popupChromeReleaseProgress()));
|
||||||
|
if (progress <= 0)
|
||||||
|
return rect;
|
||||||
|
|
||||||
|
const anchorsTop = _stackAnchorsTop();
|
||||||
|
const h = Math.max(0, rect.bottom - rect.y);
|
||||||
|
const shrink = h * progress;
|
||||||
|
if (anchorsTop)
|
||||||
|
rect.bottom = Math.max(rect.y, rect.bottom - shrink);
|
||||||
|
else
|
||||||
|
rect.y = Math.min(rect.bottom, rect.y + shrink);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stackAnchorsTop() {
|
||||||
|
const pos = SettingsData.notificationPopupPosition;
|
||||||
|
return pos === -1 || pos === SettingsData.Position.Top || pos === SettingsData.Position.Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _trailingChromeWindow(candidates) {
|
||||||
|
const anchorsTop = _stackAnchorsTop();
|
||||||
|
let trailing = null;
|
||||||
|
let edge = anchorsTop ? -Infinity : Infinity;
|
||||||
|
for (const p of candidates) {
|
||||||
|
const rect = _popupChromeRect(p, false);
|
||||||
|
if (!rect)
|
||||||
|
continue;
|
||||||
|
const candidateEdge = anchorsTop ? rect.bottom : rect.y;
|
||||||
|
if ((anchorsTop && candidateEdge > edge) || (!anchorsTop && candidateEdge < edge)) {
|
||||||
|
edge = candidateEdge;
|
||||||
|
trailing = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trailing;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _chromeWindowReservesSlot(p, trailing) {
|
||||||
|
if (p === trailing)
|
||||||
|
return true;
|
||||||
|
return !p.popupChromeReservesSlot || p.popupChromeReservesSlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stackAnchoredChromeEdge(candidates) {
|
||||||
|
const anchorsTop = _stackAnchorsTop();
|
||||||
|
let edge = anchorsTop ? Infinity : -Infinity;
|
||||||
|
for (const p of candidates) {
|
||||||
|
const rect = _popupChromeRect(p, false);
|
||||||
|
if (!rect)
|
||||||
|
continue;
|
||||||
|
if (anchorsTop && rect.y < edge)
|
||||||
|
edge = rect.y;
|
||||||
|
if (!anchorsTop && rect.bottom > edge)
|
||||||
|
edge = rect.bottom;
|
||||||
|
}
|
||||||
|
if (edge === Infinity || edge === -Infinity)
|
||||||
|
return null;
|
||||||
|
return {
|
||||||
|
anchorsTop: anchorsTop,
|
||||||
|
edge: edge
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _syncNotificationChromeState() {
|
||||||
|
const screenName = manager.modelData?.name || "";
|
||||||
|
if (!screenName)
|
||||||
|
return;
|
||||||
|
if (!notificationConnectedMode) {
|
||||||
|
ConnectedModeState.clearNotificationState(screenName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const chromeCandidates = _chromeWindows();
|
||||||
|
if (chromeCandidates.length === 0) {
|
||||||
|
ConnectedModeState.clearNotificationState(screenName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const trailing = chromeCandidates.length > 1 ? _trailingChromeWindow(chromeCandidates) : null;
|
||||||
|
let active = chromeCandidates;
|
||||||
|
if (chromeCandidates.length > 1) {
|
||||||
|
const reserving = chromeCandidates.filter(p => _chromeWindowReservesSlot(p, trailing));
|
||||||
|
if (reserving.length > 0)
|
||||||
|
active = reserving;
|
||||||
|
}
|
||||||
|
let minX = Infinity;
|
||||||
|
let minY = Infinity;
|
||||||
|
let maxXEnd = -Infinity;
|
||||||
|
let maxYEnd = -Infinity;
|
||||||
|
const useMotionOffset = active.length === 1 && active[0].popupChromeMotionActive && active[0].popupChromeMotionActive();
|
||||||
|
for (const p of active) {
|
||||||
|
const rect = _popupChromeBoundsRect(p, trailing, useMotionOffset);
|
||||||
|
if (!rect)
|
||||||
|
continue;
|
||||||
|
if (rect.x < minX)
|
||||||
|
minX = rect.x;
|
||||||
|
if (rect.y < minY)
|
||||||
|
minY = rect.y;
|
||||||
|
if (rect.right > maxXEnd)
|
||||||
|
maxXEnd = rect.right;
|
||||||
|
if (rect.bottom > maxYEnd)
|
||||||
|
maxYEnd = rect.bottom;
|
||||||
|
}
|
||||||
|
const stackEdge = _stackAnchoredChromeEdge(chromeCandidates);
|
||||||
|
if (stackEdge !== null) {
|
||||||
|
if (stackEdge.anchorsTop && stackEdge.edge < minY)
|
||||||
|
minY = stackEdge.edge;
|
||||||
|
if (!stackEdge.anchorsTop && stackEdge.edge > maxYEnd)
|
||||||
|
maxYEnd = stackEdge.edge;
|
||||||
|
}
|
||||||
|
if (minX === Infinity || minY === Infinity || maxXEnd <= minX || maxYEnd <= minY) {
|
||||||
|
ConnectedModeState.clearNotificationState(screenName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ConnectedModeState.setNotificationState(screenName, {
|
||||||
|
visible: true,
|
||||||
|
barSide: notifBarSide,
|
||||||
|
bodyX: minX,
|
||||||
|
bodyY: minY,
|
||||||
|
bodyW: maxXEnd - minX,
|
||||||
|
bodyH: maxYEnd - minY
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _onPopupChromeGeometryChanged(p) {
|
||||||
|
if (!p || popupWindows.indexOf(p) === -1)
|
||||||
|
return;
|
||||||
|
_scheduleNotificationChromeSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onPopupHeightChanged(p) {
|
function _onPopupHeightChanged(p) {
|
||||||
@@ -228,8 +420,15 @@ QtObject {
|
|||||||
}
|
}
|
||||||
popupWindows = [];
|
popupWindows = [];
|
||||||
destroyingWindows.clear();
|
destroyingWindows.clear();
|
||||||
|
_chromeSyncPending = false;
|
||||||
|
_syncNotificationChromeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onNotificationConnectedModeChanged: _scheduleNotificationChromeSync()
|
||||||
|
onNotifBarSideChanged: _scheduleNotificationChromeSync()
|
||||||
|
onModelDataChanged: _scheduleNotificationChromeSync()
|
||||||
|
onTopMarginChanged: _repositionAll()
|
||||||
|
|
||||||
onPopupWindowsChanged: {
|
onPopupWindowsChanged: {
|
||||||
if (popupWindows.length > 0 && !sweeper.running) {
|
if (popupWindows.length > 0 && !sweeper.running) {
|
||||||
sweeper.start();
|
sweeper.start();
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ Item {
|
|||||||
}
|
}
|
||||||
radiusX: root._cr
|
radiusX: root._cr
|
||||||
radiusY: root._cr
|
radiusY: root._cr
|
||||||
direction: PathArc.Counterclockwise
|
direction: root.barSide === "bottom" ? PathArc.Clockwise : PathArc.Counterclockwise
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body edge to first convex corner
|
// Body edge to first convex corner
|
||||||
@@ -169,7 +169,7 @@ Item {
|
|||||||
}
|
}
|
||||||
radiusX: root._sr
|
radiusX: root._sr
|
||||||
radiusY: root._sr
|
radiusY: root._sr
|
||||||
direction: PathArc.Clockwise
|
direction: root.barSide === "bottom" ? PathArc.Counterclockwise : PathArc.Clockwise
|
||||||
}
|
}
|
||||||
|
|
||||||
// Far edge
|
// Far edge
|
||||||
@@ -224,7 +224,7 @@ Item {
|
|||||||
}
|
}
|
||||||
radiusX: root._sr
|
radiusX: root._sr
|
||||||
radiusY: root._sr
|
radiusY: root._sr
|
||||||
direction: PathArc.Clockwise
|
direction: root.barSide === "bottom" ? PathArc.Counterclockwise : PathArc.Clockwise
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body edge to second concave arc
|
// Body edge to second concave arc
|
||||||
@@ -279,7 +279,7 @@ Item {
|
|||||||
}
|
}
|
||||||
radiusX: root._cr
|
radiusX: root._cr
|
||||||
radiusY: root._cr
|
radiusY: root._cr
|
||||||
direction: PathArc.Counterclockwise
|
direction: root.barSide === "bottom" ? PathArc.Clockwise : PathArc.Counterclockwise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user