From 742605d359168d8f74522f7a70efa19d978805cb Mon Sep 17 00:00:00 2001 From: Alan Wizemann Date: Fri, 24 Apr 2026 13:08:35 +0200 Subject: [PATCH] =?UTF-8?q?M7=20#3:=20Chat=20'Connecting=E2=80=A6'=20overl?= =?UTF-8?q?ay=20during=20SSH=20exec=20handshake?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ChatController already transitioned through a `.connecting` state between tap-Chat and first-message-ready (ACP initialize + session/new take ~0.5–1.5 s on a warm network), but there was no visible UI — the screen stayed on the idle layout with a disabled composer. Users interpreted the silence as a frozen app (pass-1 M7 #3). Adds a `.regularMaterial` overlay with a large ProgressView + "Connecting to …" text, rendered whenever `controller.state == .connecting`. Disappears automatically when state flips to `.ready` (normal path) or `.failed` (handoff to the existing errorOverlay). Co-Authored-By: Claude Opus 4.7 (1M context) --- scarf/Scarf iOS/Chat/ChatView.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scarf/Scarf iOS/Chat/ChatView.swift b/scarf/Scarf iOS/Chat/ChatView.swift index 7c6a5bd..9a81bc0 100644 --- a/scarf/Scarf iOS/Chat/ChatView.swift +++ b/scarf/Scarf iOS/Chat/ChatView.swift @@ -63,6 +63,8 @@ struct ChatView: View { .overlay { if case .failed(let msg) = controller.state { errorOverlay(msg) + } else if controller.state == .connecting { + connectingOverlay } } .sheet(item: Binding( @@ -163,6 +165,24 @@ struct ChatView: View { .background(.regularMaterial) } + /// Shown while we're opening the SSH exec channel + spawning + /// `hermes acp` + creating the ACP session. Typically ~0.5–1.5 s + /// on a warm network — silent before this overlay existed, which + /// made the app feel frozen (pass-1 M7 #3). + @ViewBuilder + private var connectingOverlay: some View { + VStack(spacing: 12) { + ProgressView() + .controlSize(.large) + Text("Connecting to \(config.displayName)…") + .font(.callout) + .foregroundStyle(.secondary) + } + .padding(24) + .background(.regularMaterial) + .clipShape(RoundedRectangle(cornerRadius: 14)) + } + @ViewBuilder private func errorOverlay(_ message: String) -> some View { VStack(spacing: 12) {