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