mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 10:36:35 +00:00
M7 #14 (pass-2): keep ACP session alive across tab switches
Pass-2 observation: "when a user switches away from chat and comes
back, there is a loading time — should we keep it open so there
isn't a reload needed?"
Removed the .onDisappear { controller.stop() } hook. TabView unmounts
tab content on switch (disappear fires), but @State keeps the
ChatController alive — so dropping the SSH exec channel + re-
opening on next appear was costing a ~1-2s reconnect every time
the user bounced Dashboard → Chat → Memory → Chat.
Cleanup still happens correctly because ChatController's lifetime
is tied to ChatView's parent (ScarfGoTabRoot). When the user
Disconnects/Forgets from the More tab, RootModel flips out of
.connected, the whole tab root unmounts, and the controller + its
ACPClient tear down via .deinit. Background termination is handled
by iOS naturally.
A comment in the file documents why we no longer tear down on
.onDisappear — easy to re-add if a future iPad / multi-window
variant wants explicit idle-pause behaviour.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,9 +93,22 @@ struct ChatView: View {
|
||||
coordinator?.pendingResumeSessionID = nil
|
||||
Task { await controller.startResuming(sessionID: sessionID) }
|
||||
}
|
||||
.onDisappear {
|
||||
Task { await controller.stop() }
|
||||
}
|
||||
// Deliberately NOT tearing down the ACP session on .onDisappear.
|
||||
// `TabView` unmounts tab content when the user switches tabs
|
||||
// (disappear fires), but `@State var controller` keeps the
|
||||
// ChatController alive across those switches, so dropping the
|
||||
// SSH exec channel + re-opening on next appear would cost the
|
||||
// user a ~1-2s reconnect every time they hop to Dashboard
|
||||
// and back. The ACPClient stays open; the controller cleans up
|
||||
// properly when:
|
||||
// - the user Disconnects / Forgets the server (RootModel
|
||||
// flips out of .connected, whole tab root unmounts, and
|
||||
// ChatController.deinit + transport teardown runs),
|
||||
// - or the app goes to background (iOS will terminate the
|
||||
// socket eventually if memory pressure hits anyway).
|
||||
// If a future iPad / multi-window variant wants to explicitly
|
||||
// pause idle connections, add a coordinator-driven stop() on
|
||||
// app-lifecycle phase changes instead.
|
||||
.overlay {
|
||||
if case .failed(let msg) = controller.state {
|
||||
errorOverlay(msg)
|
||||
|
||||
Reference in New Issue
Block a user