From 49635fb005033c186b26ff9e42c08b10f86cd03e Mon Sep 17 00:00:00 2001 From: Fimeg Date: Fri, 31 Jul 2026 12:51:17 -0400 Subject: [PATCH] shell: give the subconscious event log a host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tier 2 was written, deployed and mounted by nothing — its own header named the gap. The chat sidebar hosts it now: ticker long-press, or the psychology indicator by the input box, which works when no pass is running. --- .../modules/ii/sidebarLeft/AiChat.qml | 111 +++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/surfaces/quickshell/modules/ii/sidebarLeft/AiChat.qml b/surfaces/quickshell/modules/ii/sidebarLeft/AiChat.qml index 170efe2..54b6607 100644 --- a/surfaces/quickshell/modules/ii/sidebarLeft/AiChat.qml +++ b/surfaces/quickshell/modules/ii/sidebarLeft/AiChat.qml @@ -528,7 +528,10 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\) } } - SubconsciousTicker {} + SubconsciousTicker { + // Tier 1 declares the intent; mounting Tier 2 is the host's job. + onRequestOpenPanel: root.subconsciousPanelOpen = true + } Rectangle { // Input area id: inputWrapper @@ -823,6 +826,26 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\) tooltipText: Translation.tr("Current tool: %1\nSet it with %2tool TOOL").arg(Ai.currentTool ?? "").arg(root?.commandPrefix ?? "/") } + ApiInputBoxIndicator { + // Tier-2 subconscious log. The ticker's long-press is the + // other way in, but the ticker only exists while a pass is + // actually running — without this the event log would be + // reachable only during the few seconds it is already on + // screen, which is to say not reachable. + icon: "psychology" + text: Ai.subconsciousEvents.length > 0 ? String(Ai.subconsciousEvents.length) : "" + tooltipText: Translation.tr("Subconscious event log") + + MouseArea { + anchors.fill: parent + // hoverEnabled false so hover still falls through to the + // tooltip's own MouseArea underneath; we only want clicks. + hoverEnabled: false + cursorShape: Qt.PointingHandCursor + onClicked: root.subconsciousPanelOpen = !root.subconsciousPanelOpen + } + } + Item { Layout.fillWidth: true } @@ -855,4 +878,90 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\) } } } + + // ── Tier-2 subconscious event log ──────────────────────────────────── + // SubconsciousEventPanel is content, not a window: by design it carries no + // scrim, no close button and no placement — its own header says so, and + // names the gap ("no souveraine host mounts this yet"). Somebody has to be + // the host, and until now nobody was: the panel was written, deployed, and + // unreachable. That is exactly the failure SHELL-SURFACES.md exists to + // stop — a surface that reaches the tree but never the glass, silently, + // because nothing errors when nothing instantiates. + // + // The AI chat is the right host: the Tier-1 ticker already lives here and + // Tier 2 is the same stream after the fact. Chrome is ours; the panel stays + // placeable anywhere else later, viewtop included. + property bool subconsciousPanelOpen: false + + Item { + id: subconsciousPanelHost + anchors.fill: parent + z: 100 + visible: opacity > 0 + opacity: root.subconsciousPanelOpen ? 1 : 0 + + Behavior on opacity { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + + Rectangle { // Scrim — tap outside the panel to dismiss + anchors.fill: parent + radius: Appearance.rounding.small + color: Appearance.colors.colScrim + MouseArea { + anchors.fill: parent + preventStealing: true + propagateComposedEvents: false + onClicked: root.subconsciousPanelOpen = false + } + } + + // The panel ships no close affordance, so the host draws one. It sits + // above the panel rather than over it: the panel's own header already + // occupies its top-right with the event count. + RowLayout { + id: subconsciousChrome + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: 8 + } + height: 32 + + Item { Layout.fillWidth: true } + + Item { + // Finger-sized hit area; the glyph alone is far too small a + // target on the phone. + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + + MaterialSymbol { + anchors.centerIn: parent + text: "close" + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colSubtext + } + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: root.subconsciousPanelOpen = false + } + } + } + + SubconsciousEventPanel { + anchors { + top: subconsciousChrome.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + leftMargin: 8 + rightMargin: 8 + bottomMargin: 8 + topMargin: 4 + } + } + } }