Skip to content

Commit ed2a215

Browse files
authored
refactor(ios): drop UIApplication.sendAction keyboard dismiss for binding-driven focus (#1167)
1 parent 5cad8f4 commit ed2a215

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Changed
1818

19+
- Internal: iOS query editor uses a `Binding<Bool>` focus channel into `SQLHighlightTextView` to dismiss the keyboard before running a query, replacing the `UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder))` call. Keyboard behavior is unchanged
1920
- Internal: iOS row detail (edit lifecycle, save SQL build, lazy cell value load, primary key extraction, success-toast auto-dismiss) moves out of the View into `RowDetailViewModel`. The View now keeps only sheet flags and haptic triggers; behavior is unchanged
2021
- Internal: iOS connection form (test connection, save, file picker handlers, default port resolution, credential hydration) moves out of the View into `ConnectionFormViewModel`. The View drops from 53 to 5 `@State` properties; behavior is unchanged
2122
- Internal: iOS data browser business logic (page load, pagination, sort, filter, search, delete, foreign-key fetch, memory pressure) moves out of the View into `DataBrowserViewModel`. The View drops 30 of its 33 `@State` properties and a dozen private functions; behavior is unchanged

TableProMobile/TableProMobile/Views/Components/SQLHighlightTextView.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import UIKit
88

99
struct SQLHighlightTextView: UIViewRepresentable {
1010
@Binding var text: String
11+
@Binding var isFocused: Bool
1112

1213
private static let font = UIFont.monospacedSystemFont(ofSize: 15, weight: .regular)
1314

15+
init(text: Binding<String>, isFocused: Binding<Bool> = .constant(false)) {
16+
self._text = text
17+
self._isFocused = isFocused
18+
}
19+
1420
func makeUIView(context: Context) -> UITextView {
1521
let textView = UITextView()
1622
context.coordinator.textView = textView
@@ -40,6 +46,11 @@ struct SQLHighlightTextView: UIViewRepresentable {
4046
}
4147
context.coordinator.isUpdating = false
4248
}
49+
if isFocused, !textView.isFirstResponder {
50+
textView.becomeFirstResponder()
51+
} else if !isFocused, textView.isFirstResponder {
52+
textView.resignFirstResponder()
53+
}
4354
}
4455

4556
func makeCoordinator() -> Coordinator { Coordinator(self) }
@@ -58,6 +69,14 @@ struct SQLHighlightTextView: UIViewRepresentable {
5869
parent.text = textView.text
5970
}
6071

72+
func textViewDidBeginEditing(_ textView: UITextView) {
73+
if !parent.isFocused { parent.isFocused = true }
74+
}
75+
76+
func textViewDidEndEditing(_ textView: UITextView) {
77+
if parent.isFocused { parent.isFocused = false }
78+
}
79+
6180
func textStorage(
6281
_ textStorage: NSTextStorage,
6382
didProcessEditing editedMask: NSTextStorage.EditActions,

TableProMobile/TableProMobile/Views/QueryEditorView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct QueryEditorView: View {
1414
private static let logger = Logger(subsystem: "com.TablePro", category: "QueryEditorView")
1515

1616
@State private var query = ""
17+
@State private var editorFocused = false
1718
@State private var viewModel = QueryEditorViewModel()
1819
@State private var appError: AppError?
1920
@State private var isExecuting = false
@@ -112,7 +113,7 @@ struct QueryEditorView: View {
112113

113114
private var editorSection: some View {
114115
VStack(spacing: 0) {
115-
SQLHighlightTextView(text: $query)
116+
SQLHighlightTextView(text: $query, isFocused: $editorFocused)
116117
.frame(minHeight: 80, maxHeight: hasResult || appError != nil ? 120 : 250)
117118

118119
actionBar
@@ -392,7 +393,7 @@ struct QueryEditorView: View {
392393
private func executeQueryDirect(_ trimmed: String) async {
393394
guard let session else { return }
394395

395-
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
396+
editorFocused = false
396397
isExecuting = true
397398
executionStartTime = Date()
398399
defer {

0 commit comments

Comments
 (0)