From bf3f7350628c1a2ddddbed618079ac3eb9934891 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 12 Nov 2022 14:16:05 -0500 Subject: [PATCH] Focus CW field immediately when CW enabled, move focus to main text view when return key pressed Closes #226 --- .../Compose/ComposeEmojiTextField.swift | 28 +++++++++++++++---- Tusker/Screens/Compose/ComposeView.swift | 19 +++++++++++-- .../Screens/Compose/MainComposeTextView.swift | 2 +- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/Tusker/Screens/Compose/ComposeEmojiTextField.swift b/Tusker/Screens/Compose/ComposeEmojiTextField.swift index d7e18398..6d363ec7 100644 --- a/Tusker/Screens/Compose/ComposeEmojiTextField.swift +++ b/Tusker/Screens/Compose/ComposeEmojiTextField.swift @@ -13,15 +13,19 @@ struct ComposeEmojiTextField: UIViewRepresentable { @EnvironmentObject private var uiState: ComposeUIState - @Binding private var text: String - private let placeholder: String - private var didChange: ((String) -> Void)? - private var didEndEditing: (() -> Void)? + @Binding var text: String + let placeholder: String + let becomeFirstResponder: Binding? + let focusNextView: Binding? + private var didChange: ((String) -> Void)? = nil + private var didEndEditing: (() -> Void)? = nil private var backgroundColor: UIColor? = nil - init(text: Binding, placeholder: String) { + init(text: Binding, placeholder: String, becomeFirstResponder: Binding? = nil, focusNextView: Binding? = nil) { self._text = text self.placeholder = placeholder + self.becomeFirstResponder = becomeFirstResponder + self.focusNextView = focusNextView self.didChange = nil self.didEndEditing = nil } @@ -52,6 +56,7 @@ struct ComposeEmojiTextField: UIViewRepresentable { view.delegate = context.coordinator view.addTarget(context.coordinator, action: #selector(Coordinator.didChange(_:)), for: .editingChanged) + view.addTarget(context.coordinator, action: #selector(Coordinator.returnKeyPressed), for: .primaryActionTriggered) // otherwise when the text gets too wide it starts expanding the ComposeView view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) @@ -71,6 +76,14 @@ struct ComposeEmojiTextField: UIViewRepresentable { } context.coordinator.didChange = didChange context.coordinator.didEndEditing = didEndEditing + context.coordinator.focusNextView = focusNextView + + if becomeFirstResponder?.wrappedValue == true { + DispatchQueue.main.async { + uiView.becomeFirstResponder() + becomeFirstResponder?.wrappedValue = false + } + } } func makeCoordinator() -> Coordinator { @@ -84,6 +97,7 @@ struct ComposeEmojiTextField: UIViewRepresentable { unowned var uiState: ComposeUIState! var didChange: ((String) -> Void)? var didEndEditing: (() -> Void)? + var focusNextView: Binding? var skipSettingTextOnNextUpdate = false @@ -96,6 +110,10 @@ struct ComposeEmojiTextField: UIViewRepresentable { didChange?(text.wrappedValue) } + @objc func returnKeyPressed() { + focusNextView?.wrappedValue = true + } + func textFieldDidBeginEditing(_ textField: UITextField) { uiState.currentInput = self updateAutocompleteState(textField: textField) diff --git a/Tusker/Screens/Compose/ComposeView.swift b/Tusker/Screens/Compose/ComposeView.swift index c26c8bdc..be2a3023 100644 --- a/Tusker/Screens/Compose/ComposeView.swift +++ b/Tusker/Screens/Compose/ComposeView.swift @@ -47,6 +47,8 @@ struct ComposeView: View { @EnvironmentObject var uiState: ComposeUIState @State private var globalFrameOutsideList: CGRect = .zero + @State private var contentWarningBecomeFirstResponder = false + @State private var mainComposeTextViewBecomeFirstResponder = false @OptionalStateObject private var poster: PostService? @State private var isShowingPostErrorAlert = false @@ -145,12 +147,20 @@ struct ComposeView: View { .listRowSeparator(.hidden) if draft.contentWarningEnabled { - ComposeEmojiTextField(text: $draft.contentWarning, placeholder: "Write your warning here") + ComposeEmojiTextField( + text: $draft.contentWarning, + placeholder: "Write your warning here", + becomeFirstResponder: $contentWarningBecomeFirstResponder, + focusNextView: $mainComposeTextViewBecomeFirstResponder + ) .listRowInsets(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) } - MainComposeTextView(draft: draft) + MainComposeTextView( + draft: draft, + becomeFirstResponder: $mainComposeTextViewBecomeFirstResponder + ) .listRowInsets(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) @@ -170,6 +180,11 @@ struct ComposeView: View { .listStyle(.plain) .disabled(isPosting) .padding(.bottom, uiState.autocompleteState != nil ? 46 : 0) + .onChange(of: draft.contentWarningEnabled) { newValue in + if newValue { + contentWarningBecomeFirstResponder = true + } + } } private var header: some View { diff --git a/Tusker/Screens/Compose/MainComposeTextView.swift b/Tusker/Screens/Compose/MainComposeTextView.swift index 090740d3..a962ecf8 100644 --- a/Tusker/Screens/Compose/MainComposeTextView.swift +++ b/Tusker/Screens/Compose/MainComposeTextView.swift @@ -35,7 +35,7 @@ struct MainComposeTextView: View { let minHeight: CGFloat = 150 @State private var height: CGFloat? - @State private var becomeFirstResponder: Bool = false + @Binding var becomeFirstResponder: Bool @State private var hasFirstAppeared = false @ScaledMetric private var fontSize = 20