From 622659f6ca65fd743552f73feb362448e7dce9b8 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 12 Jul 2026 13:57:45 -0700 Subject: [PATCH] ios: preserve chat scroll position on resume --- .../Sybil/Sources/Sybil/SybilChatTranscriptView.swift | 1 - ios/Packages/Sybil/Sources/Sybil/SybilViewModel.swift | 5 ++++- ios/Packages/Sybil/Tests/SybilTests/SybilTests.swift | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ios/Packages/Sybil/Sources/Sybil/SybilChatTranscriptView.swift b/ios/Packages/Sybil/Sources/Sybil/SybilChatTranscriptView.swift index cb763b6..da1e979 100644 --- a/ios/Packages/Sybil/Sources/Sybil/SybilChatTranscriptView.swift +++ b/ios/Packages/Sybil/Sources/Sybil/SybilChatTranscriptView.swift @@ -67,7 +67,6 @@ struct SybilChatTranscriptView: View { .scrollDismissesKeyboard(.interactively) .onAppear { syncKnownToolCallMessageIDs() - scrollToBottom(with: proxy, animated: false) } .onChange(of: toolCallMessageIDSignature) { _, _ in syncKnownToolCallMessageIDs() diff --git a/ios/Packages/Sybil/Sources/Sybil/SybilViewModel.swift b/ios/Packages/Sybil/Sources/Sybil/SybilViewModel.swift index c1df12e..9cc5c91 100644 --- a/ios/Packages/Sybil/Sources/Sybil/SybilViewModel.swift +++ b/ios/Packages/Sybil/Sources/Sybil/SybilViewModel.swift @@ -1752,13 +1752,16 @@ final class SybilViewModel { switch target { case let .chat(chatID): SybilLog.debug(SybilLog.app, "Refreshing chat \(chatID)") + let isSelectingDifferentChat = selectedChat?.id != chatID let chat = try await client.getChat(chatID: chatID) guard selectedItem == target, draftKind == nil else { return } selectedChat = chat selectedSearch = nil - requestChatBottomPin() + if isSelectingDifferentChat { + requestChatBottomPin() + } if let provider = chat.lastUsedProvider, let model = chat.lastUsedModel, diff --git a/ios/Packages/Sybil/Tests/SybilTests/SybilTests.swift b/ios/Packages/Sybil/Tests/SybilTests/SybilTests.swift index ea98bc7..ba6d38f 100644 --- a/ios/Packages/Sybil/Tests/SybilTests/SybilTests.swift +++ b/ios/Packages/Sybil/Tests/SybilTests/SybilTests.swift @@ -544,12 +544,14 @@ private func makeToolCallMessage(id: String, date: Date, summary: String = "Ran @MainActor @Test func foregroundChatRefreshReloadsSelectedTranscript() async throws { let date = Date(timeIntervalSince1970: 1_700_000_100) + let staleDetail = makeChatDetail(id: "chat-2", date: date, body: "stale transcript") let detail = makeChatDetail(id: "chat-2", date: date, body: "refreshed transcript") let client = MockSybilClient(chatDetails: ["chat-2": detail]) let viewModel = SybilViewModel(settings: testSettings(named: #function)) { _ in client } viewModel.isAuthenticated = true viewModel.isCheckingSession = false viewModel.selectedItem = .chat("chat-2") + viewModel.selectedChat = staleDetail await viewModel.refreshVisibleContent(refreshCollections: false, refreshSelection: true) @@ -559,7 +561,7 @@ private func makeToolCallMessage(id: String, date: Date, summary: String = "Ran #expect(snapshot.listSearches == 0) #expect(snapshot.getChat == 1) #expect(viewModel.selectedChat?.messages.first?.content == "refreshed transcript") - #expect(viewModel.chatBottomPinRequestID == 1) + #expect(viewModel.chatBottomPinRequestID == 0) } @MainActor @@ -675,6 +677,7 @@ private func makeToolCallMessage(id: String, date: Date, summary: String = "Ran #expect(viewModel.displayedMessages.first?.content == "fresh transcript") #expect(!viewModel.isLoadingSelection) + #expect(viewModel.chatBottomPinRequestID == 1) } @MainActor