From f6722a223f467205ef46578a8241be880c6e579a Mon Sep 17 00:00:00 2001 From: Shane Maynard Date: Sat, 12 Sep 2026 08:36:01 -0400 Subject: [PATCH] Fix regressions N1-N3 from re-verification - Transcript: selection suspension clears when press ends; Latest re-enables follow fully (clears stale selection state) - Send disabled until transport ready in pending Type composer - Server URL: programmatic success-trim no longer erases its own saved-confirmation; only user edits clear it --- .../Conversation/TranscriptListView.swift | 8 ++++++-- Sources/Features/Settings/SettingsView.swift | 20 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Sources/Features/Conversation/TranscriptListView.swift b/Sources/Features/Conversation/TranscriptListView.swift index 0337ab3..6bc3138 100644 --- a/Sources/Features/Conversation/TranscriptListView.swift +++ b/Sources/Features/Conversation/TranscriptListView.swift @@ -74,6 +74,9 @@ struct TranscriptListView: View { HStack { Spacer() Button { + // Explicit Latest restores full eligibility, + // clearing any stale selection suspension. + selectionActive = false followingLatest = true withAnimation(reduceMotion ? nil : Nearlight.standard) { proxy.scrollTo("latest", anchor: .bottom) @@ -130,8 +133,9 @@ struct TranscriptListView: View { .frame(maxWidth: .infinity, alignment: .leading) .onLongPressGesture(minimumDuration: 0.05, pressing: { pressing in // Text-selection interaction begins with long-press on the row; - // suspend auto-follow while pressing/held. - if pressing { selectionActive = true } + // suspend auto-follow while pressing/held and restore when the + // press ends so following can resume. + selectionActive = pressing }, perform: {}) .contextMenu { Button("Copy message", systemImage: "doc.on.doc") { UIPasteboard.general.string = text } diff --git a/Sources/Features/Settings/SettingsView.swift b/Sources/Features/Settings/SettingsView.swift index 8dea03b..36d10cc 100644 --- a/Sources/Features/Settings/SettingsView.swift +++ b/Sources/Features/Settings/SettingsView.swift @@ -15,6 +15,8 @@ struct SettingsView: View { @State private var urlJustSaved = false @State private var showModelPicker = false @FocusState private var urlFocused: Bool + @State private var applyingTrim = false + /// Guards the success-trim against the edit observer (N3). init(settings: SettingsStore, session: VoiceSession) { self.settings = settings @@ -71,10 +73,14 @@ struct SettingsView: View { .accessibilityLabel("Server URL") .focused($urlFocused) .onAppear { urlText = settings.serverURL } - .onChange(of: urlText) { _, _ in - // Any edit clears the saved confirmation and error. - urlJustSaved = false - urlError = nil + .onChange(of: urlText) { oldValue, newValue in + // A programmatic normalization on successful Save must + // not erase its own confirmation; only user edits do. + guard applyingTrim == false else { return } + if newValue != oldValue { + urlJustSaved = false + urlError = nil + } } .overlay(alignment: .trailing) { if urlJustSaved { @@ -142,7 +148,11 @@ struct SettingsView: View { switch ServerConfig.parse(trimmed) { case .success: settings.serverURL = trimmed - urlText = trimmed + if trimmed != urlText { + applyingTrim = true + urlText = trimmed + applyingTrim = false + } urlError = nil urlJustSaved = true urlFocused = false