diff --git a/modules/NotifCard.qml b/modules/NotifCard.qml index fa4b8da..bd19ee0 100644 --- a/modules/NotifCard.qml +++ b/modules/NotifCard.qml @@ -28,7 +28,7 @@ Item { Rectangle { anchors.fill: parent color: _hover.hovered ? M.Theme.base02 : M.Theme.base01 - opacity: _hover.hovered ? 1.0 : Math.max(M.Theme.barOpacity, 0.9) + opacity: Math.max(M.Theme.barOpacity, 0.9) radius: M.Theme.radius Behavior on color { diff --git a/modules/NotifCenter.qml b/modules/NotifCenter.qml index 8b54608..ee07ebf 100644 --- a/modules/NotifCenter.qml +++ b/modules/NotifCenter.qml @@ -67,18 +67,6 @@ M.HoverPanel { property var _pendingDismissIds: [] - // Collapsed groups set — reassign to trigger reactivity - property var _collapsedGroups: ({}) - - function _toggleCollapse(appName) { - const next = Object.assign({}, _collapsedGroups); - if (next[appName]) - delete next[appName]; - else - next[appName] = true; - _collapsedGroups = next; - } - // Group notifications by appName, sorted by max urgency desc then most recent time desc readonly property var _groups: { const map = {}; @@ -105,26 +93,21 @@ M.HoverPanel { }); } - // Flat model: group header followed by its notifications (omitted when collapsed) + // Flat model: group header followed by its notifications readonly property var _flatModel: { const arr = []; for (const g of _groups) { - const collapsed = !!_collapsedGroups[g.appName]; arr.push({ type: "header", appName: g.appName, appIcon: g.appIcon, - count: g.notifs.length, - collapsed: collapsed, - summaries: g.notifs.map(n => n.summary || "").filter(Boolean).join(" · ") + count: g.notifs.length }); - if (!collapsed) { - for (const n of g.notifs) - arr.push({ - type: "notif", - data: n - }); - } + for (const n of g.notifs) + arr.push({ + type: "notif", + data: n + }); } return arr; } @@ -235,25 +218,11 @@ M.HoverPanel { readonly property var _notif: _type === "notif" ? modelData.data : null width: menuWindow.contentWidth - height: _displayTargetHeight * _heightScale + height: _targetHeight * _heightScale clip: true opacity: 0 - readonly property real _targetHeight: { - if (_type === "header") - return modelData.collapsed ? (28 + M.Theme.fontSize + 4) : 28; - return _notifCard.implicitHeight; - } - - // Animated version of _targetHeight — smoothly transitions header height on collapse - property real _displayTargetHeight: _targetHeight - Behavior on _displayTargetHeight { - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - + readonly property real _targetHeight: _type === "header" ? 28 : _notifCard.implicitHeight property real _heightScale: 1 property bool _skipDismiss: false @@ -288,29 +257,11 @@ M.HoverPanel { visible: notifDelegate._type === "header" anchors.fill: parent - HoverHandler { - id: _headerHover - } - - // Tap target for collapse — covers header row only, excludes dismiss button - Item { - anchors.left: parent.left - anchors.right: _groupDismissBtn.left - anchors.top: parent.top - height: 28 - - TapHandler { - cursorShape: Qt.PointingHandCursor - onTapped: menuWindow._toggleCollapse(notifDelegate.modelData.appName) - } - } - Image { id: _headerIcon anchors.left: parent.left anchors.leftMargin: 10 - anchors.top: parent.top - anchors.topMargin: (28 - height) / 2 + anchors.verticalCenter: parent.verticalCenter width: M.Theme.fontSize + 2 height: M.Theme.fontSize + 2 source: { @@ -327,29 +278,12 @@ M.HoverPanel { asynchronous: true } - // Collapse chevron - Text { - id: _chevron - anchors.right: _groupDismissBtn.left - anchors.rightMargin: 8 - anchors.top: parent.top - height: 28 - verticalAlignment: Text.AlignVCenter - text: notifDelegate._type === "header" && notifDelegate.modelData.collapsed ? "\u25B8" : "\u25BE" - color: M.Theme.base04 - font.pixelSize: M.Theme.fontSize - 2 - font.family: M.Theme.fontFamily - } - - // App name Text { anchors.left: _headerIcon.visible ? _headerIcon.right : parent.left anchors.leftMargin: _headerIcon.visible ? 6 : 10 - anchors.right: _chevron.left - anchors.rightMargin: 4 - anchors.top: parent.top - height: 28 - verticalAlignment: Text.AlignVCenter + anchors.right: _groupDismissBtn.left + anchors.rightMargin: 6 + anchors.verticalCenter: parent.verticalCenter text: notifDelegate._type === "header" ? (notifDelegate.modelData.appName || "Unknown") : "" color: M.Theme.base05 font.pixelSize: M.Theme.fontSize - 1 @@ -358,50 +292,28 @@ M.HoverPanel { elide: Text.ElideRight } - // Dismiss button — opacity-hidden when header not hovered Text { id: _groupDismissBtn anchors.right: parent.right anchors.rightMargin: 10 - anchors.top: parent.top - height: 28 - verticalAlignment: Text.AlignVCenter + anchors.verticalCenter: parent.verticalCenter text: "\uF1F8" - color: _groupDismissHover.hovered ? M.Theme.base08 : M.Theme.base04 + color: _groupDismissArea.containsMouse ? M.Theme.base08 : M.Theme.base04 font.pixelSize: M.Theme.fontSize - 1 font.family: M.Theme.iconFontFamily - opacity: _headerHover.hovered ? 1 : 0 - HoverHandler { - id: _groupDismissHover - } - - TapHandler { + MouseArea { + id: _groupDismissArea + anchors.fill: parent + anchors.margins: -4 + hoverEnabled: true cursorShape: Qt.PointingHandCursor - onTapped: { + onClicked: { if (notifDelegate._type === "header") menuWindow._cascadeGroupDismiss(notifDelegate.modelData.appName); } } } - - // Collapsed preview: notification summaries on a subtitle row - Text { - visible: notifDelegate._type === "header" && notifDelegate.modelData.collapsed - anchors.left: parent.left - anchors.leftMargin: 10 - anchors.right: parent.right - anchors.rightMargin: 10 - anchors.top: parent.top - anchors.topMargin: 28 - height: M.Theme.fontSize + 4 - verticalAlignment: Text.AlignVCenter - text: notifDelegate._type === "header" ? (notifDelegate.modelData.summaries ?? "") : "" - elide: Text.ElideRight - font.pixelSize: M.Theme.fontSize - 2 - font.family: M.Theme.fontFamily - color: M.Theme.base04 - } } // ---- Individual notification ---- diff --git a/modules/OverviewBackdrop.qml b/modules/OverviewBackdrop.qml index 6abb7e8..ab17be2 100644 --- a/modules/OverviewBackdrop.qml +++ b/modules/OverviewBackdrop.qml @@ -32,9 +32,6 @@ PanelWindow { property real uSize: 50.0 property real uWavePhase: -200 - property real uBreath: 0 - property real uGlitch: 0 - property real uGlitchSeed: 0.0 property vector4d uResolution: Qt.vector4d(width, height, 0, 0) property color uC0: M.Theme.base0C property color uC1: M.Theme.base0E @@ -43,10 +40,8 @@ PanelWindow { Connections { target: M.NiriIpc function onOverviewOpenChanged() { - if (!M.NiriIpc.overviewOpen) { + if (!M.NiriIpc.overviewOpen) fx.uWavePhase = -200; - fx.uBreath = 0; - } } } @@ -64,66 +59,5 @@ PanelWindow { duration: 8000 } } - - // Breathing pulse while overview is open - SequentialAnimation on uBreath { - loops: Animation.Infinite - running: M.NiriIpc.overviewOpen && !M.Theme.reducedMotion - NumberAnimation { - from: 0 - to: 1 - duration: 2500 - easing.type: Easing.InOutSine - } - NumberAnimation { - from: 1 - to: 0 - duration: 2500 - easing.type: Easing.InOutSine - } - } - - // Random subtle glitches — fire every 12–37s, total ~250ms each - Timer { - interval: 20000 - repeat: true - running: !M.Theme.reducedMotion - onTriggered: { - interval = 12000 + Math.floor(Math.random() * 25000); - fx.uGlitchSeed = Math.random() * 1000.0; - _glitchAnim.start(); - } - } - - SequentialAnimation { - id: _glitchAnim - NumberAnimation { - target: fx - property: "uGlitch" - to: 0.7 - duration: 50 - easing.type: Easing.OutQuad - } - NumberAnimation { - target: fx - property: "uGlitch" - to: 0.15 - duration: 50 - } - NumberAnimation { - target: fx - property: "uGlitch" - to: 0.85 - duration: 60 - easing.type: Easing.OutQuad - } - NumberAnimation { - target: fx - property: "uGlitch" - to: 0 - duration: 100 - easing.type: Easing.InQuad - } - } } } diff --git a/modules/hex_wave.frag b/modules/hex_wave.frag index 4a87666..6f204df 100644 --- a/modules/hex_wave.frag +++ b/modules/hex_wave.frag @@ -8,9 +8,6 @@ layout(std140, binding = 0) uniform buf { float qt_Opacity; float uSize; float uWavePhase; - float uBreath; - float uGlitch; - float uGlitchSeed; vec4 uResolution; vec4 uC0; vec4 uC1; @@ -32,24 +29,9 @@ vec3 themeGradient(float t) { : mix(uC1.rgb, uC2.rgb, (t - 0.5) * 2.0); } -// Cheap hash for glitch bands -float hash(float n) { - return fract(sin(n) * 43758.5453123); -} - void main() { vec2 res = uResolution.xy; - - // Glitch: shift some horizontal bands slightly vec2 frag = qt_TexCoord0 * res; - if (uGlitch > 0.0) { - float band = floor(frag.y / 7.0); - float h = hash(band * 127.1 + uGlitchSeed * 311.7); - if (h > 0.72) { - float shift = (hash(band * 93.9 + uGlitchSeed) - 0.5) * 14.0 * uGlitch; - frag.x = clamp(frag.x + shift, 0.0, res.x); - } - } float dx = uSize * 1.5; float dy = uSize * 1.7320508; @@ -59,12 +41,12 @@ void main() { float row = round((frag.y - yoff) / dy); vec2 center = vec2(col * dx, row * dy + yoff); - // Wave — wide gaussian so it reads more as a broad pulse than a sharp sweep + // Wave factor float dist = center.x - uWavePhase; - float wf = exp(-dist * dist / 40000.0); + float wf = exp(-dist * dist / 9000.0); float baseR = uSize * 0.48; - float inradius = baseR * (1.0 + 0.15 * wf); + float inradius = baseR * (1.0 + 0.35 * wf); vec2 p = frag - center; float d = sdHexagon(p.yx, inradius); // swap for flat-top @@ -80,31 +62,28 @@ void main() { ? mix(uC0.rgb, uC1.rgb, fx * 2.0) : mix(uC1.rgb, uC2.rgb, (fx - 0.5) * 2.0); - // Alpha from distance to center (vignette) + // Alpha from distance to center float fy = clamp(center.y / res.y, 0.0, 1.0); float dc = length(vec2(fx - 0.5, fy - 0.5)); float a = 0.03 + dc * 0.06; - // Breathing pulse (when overview open) - a += 0.025 * uBreath; - rgb = min(rgb + vec3(0.04 * uBreath), vec3(1.0)); + // Wave brighten + rgb = min(rgb + vec3(0.3 * wf), vec3(1.0)); + a += 0.12 * wf; - // Wave brighten (softer than before) - rgb = min(rgb + vec3(0.15 * wf), vec3(1.0)); - a += 0.07 * wf; - - // Shimmer on hex edges as wave passes + // Rainbow shimmer on hex edges when wave passes float edgeWidth = 5.0; - float edgeFactor = smoothstep(-edgeWidth, 0.0, d); + float edgeFactor = smoothstep(-edgeWidth, 0.0, d); // 0 at interior, 1 at edge if (wf > 0.01 && edgeFactor > 0.0) { + // Vary shimmer color across theme gradient using angle + position float angle = atan(p.y, p.x); float rawT = fract((angle + 3.14159) / 6.28318 + center.x * 0.003 + center.y * 0.005); - float t = abs(rawT * 2.0 - 1.0); + float t = abs(rawT * 2.0 - 1.0); // triangle wave → uC0→uC1→uC2→uC1→uC0, no hard jump vec3 shimmerColor = themeGradient(t); float shimmer = edgeFactor * wf; - rgb = mix(rgb, shimmerColor, shimmer * 0.5); - a = mix(a, 0.5, shimmer * 0.35); + rgb = mix(rgb, shimmerColor, shimmer * 0.8); + a = mix(a, 0.5, shimmer * 0.6); } // Anti-alias outer edge