diff --git a/Tusker/Screens/Compose/ComposeContentWarningTextField.swift b/Tusker/Screens/Compose/ComposeContentWarningTextField.swift index 33f8b2b2..70059cee 100644 --- a/Tusker/Screens/Compose/ComposeContentWarningTextField.swift +++ b/Tusker/Screens/Compose/ComposeContentWarningTextField.swift @@ -58,6 +58,10 @@ struct ComposeContentWarningTextField: UIViewRepresentable { } func textFieldDidChangeSelection(_ textField: UITextField) { + // Update text binding before potentially triggering SwiftUI view update. + // See comment in MainComposeTextView.Coordinator.textViewDidChangeSelection + text.wrappedValue = textField.text ?? "" + updateAutocompleteState(textField: textField) } diff --git a/Tusker/Screens/Compose/MainComposeTextView.swift b/Tusker/Screens/Compose/MainComposeTextView.swift index d2b87e5d..2ac83120 100644 --- a/Tusker/Screens/Compose/MainComposeTextView.swift +++ b/Tusker/Screens/Compose/MainComposeTextView.swift @@ -144,6 +144,7 @@ struct MainComposeWrappedTextView: UIViewRepresentable { func updateUIView(_ uiView: UITextView, context: Context) { uiView.text = text + if let visibilityButton = visibilityButton { visibilityButton.image = UIImage(systemName: visibility.imageName) updateVisibilityMenu(visibilityButton) @@ -227,6 +228,17 @@ struct MainComposeWrappedTextView: UIViewRepresentable { } func textViewDidChangeSelection(_ textView: UITextView) { + // Update the value of the text binding. + // Sometimes, when the user accepts an autocomplete suggestion from the system keyboard, the system + // calls didChangeSelection before textDidChange, resulting in a loop where the updating the Tusker autocomplete + // state in didChangeSection (via updateAutocompleteState) triggers a new SwiftUI view update, + // but when that SwiftUI update is handled, the model still has the old text (from prior to accepting the autocomplete + // suggestion), meaning the UITextView's text gets set back to whatever it was prior to the system autocomplete. + // To work around that, we also update the text binding in didChangeSelection, to ensure that, if the autocomplete state + // does change and trigger a SwiftUI update, the binding will have the correct text that was produced by the system + // autocompletion. + text.wrappedValue = textView.text ?? "" + updateAutocompleteState() }