Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 8 additions & 73 deletions TablePro/Views/DatabaseSwitcher/DatabaseSwitcherPopover.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ struct DatabaseSwitcherPopover: View {
@State private var viewModel: DatabaseSwitcherViewModel
@State private var supportsCreateDatabase = false

private enum FocusField {
case search
case list
}

@FocusState private var focus: FocusField?

private static let popoverWidth: CGFloat = 320
private static let popoverHeight: CGFloat = 360

Expand Down Expand Up @@ -99,18 +92,6 @@ struct DatabaseSwitcherPopover: View {
.background(refreshShortcut)
.task { await viewModel.fetchDatabases() }
.task { await refreshCreateSupport() }
.onKeyPress(.return) {
commitSelection()
return .handled
}
.onKeyPress(.upArrow) {
viewModel.moveUp()
return .handled
}
.onKeyPress(.downArrow) {
viewModel.moveDown()
return .handled
}
}

private var refreshShortcut: some View {
Expand All @@ -122,61 +103,16 @@ struct DatabaseSwitcherPopover: View {
}

private var searchField: some View {
HStack(spacing: 5) {
Image(systemName: "magnifyingglass")
.imageScale(.small)
.foregroundStyle(.secondary)
.frame(width: 14)

TextField(
"",
text: $viewModel.searchText,
prompt: Text(String(localized: "Search databases"))
.foregroundStyle(.tertiary)
)
.textFieldStyle(.plain)
.font(.body)
.focused($focus, equals: .search)
.onKeyPress(.downArrow) {
viewModel.moveDown()
return .handled
}
.onKeyPress(.upArrow) {
viewModel.moveUp()
return .handled
}
.onKeyPress(.return) {
commitSelection()
return .handled
}
.onKeyPress(.escape) {
if viewModel.searchText.isEmpty {
return .ignored
}
viewModel.searchText = ""
return .handled
}

if !viewModel.searchText.isEmpty {
Button {
viewModel.searchText = ""
} label: {
Image(systemName: "xmark.circle.fill")
.imageScale(.small)
.foregroundStyle(.tertiary)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal, 6)
.padding(.vertical, 4)
.background(
RoundedRectangle(cornerRadius: 5, style: .continuous)
.fill(Color(nsColor: .quaternaryLabelColor).opacity(0.35))
NativeSearchField(
text: $viewModel.searchText,
placeholder: String(localized: "Search databases"),
onMoveUp: { viewModel.moveUp() },
onMoveDown: { viewModel.moveDown() },
onSubmit: { commitSelection() },
focusOnAppear: true
)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.onAppear { focus = .search }
.padding(.vertical, 6)
}

@ViewBuilder
Expand All @@ -203,7 +139,6 @@ struct DatabaseSwitcherPopover: View {
}
.listStyle(.inset)
.scrollContentBackground(.hidden)
.focused($focus, equals: .list)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contextMenu(forSelectionType: String.self) { selection in
contextMenuItems(for: selection)
Expand Down
13 changes: 12 additions & 1 deletion TablePro/Views/Sidebar/NativeSearchField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
import AppKit
import SwiftUI

private final class IntrinsicHeightSearchField: NSSearchField {
override var intrinsicContentSize: NSSize {
let cellHeight = cell?.cellSize.height ?? super.intrinsicContentSize.height
return NSSize(width: NSView.noIntrinsicMetric, height: cellHeight)
}
}

struct NativeSearchField: NSViewRepresentable {
@Binding var text: String
var placeholder: String
Expand All @@ -20,7 +27,7 @@ struct NativeSearchField: NSViewRepresentable {
var maxWidth: CGFloat?

func makeNSView(context: Context) -> NSSearchField {
let field = NSSearchField()
let field = IntrinsicHeightSearchField()
field.placeholderString = placeholder
field.delegate = context.coordinator
field.controlSize = controlSize
Expand All @@ -44,6 +51,10 @@ struct NativeSearchField: NSViewRepresentable {
if field.stringValue != text {
field.stringValue = text
}
if field.controlSize != controlSize {
field.controlSize = controlSize
field.invalidateIntrinsicContentSize()
}
field.placeholderString = placeholder
context.coordinator.onMoveUp = onMoveUp
context.coordinator.onMoveDown = onMoveDown
Expand Down
64 changes: 8 additions & 56 deletions TablePro/Views/Toolbar/ConnectionSwitcherPopover.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct ConnectionSwitcherPopover: View {
@State private var savedConnections: [DatabaseConnection] = []
@State private var selectedConnectionId: UUID?
@State private var searchText = ""
@FocusState private var searchFocused: Bool

private static let popoverWidth: CGFloat = 400
private static let popoverHeight: CGFloat = 460
Expand Down Expand Up @@ -84,72 +83,25 @@ struct ConnectionSwitcherPopover: View {
if selectedConnectionId == nil {
selectedConnectionId = currentSessionId ?? orderedIds.first
}
searchFocused = true
}
.onChange(of: searchText) { _, _ in
let ids = orderedIds
if let id = selectedConnectionId, ids.contains(id) { return }
selectedConnectionId = ids.first
}
.onKeyPress(.return) {
activateSelected()
return .handled
}
}

private var searchField: some View {
HStack(spacing: 5) {
Image(systemName: "magnifyingglass")
.imageScale(.small)
.foregroundStyle(.secondary)
.frame(width: 14)

TextField(
"",
text: $searchText,
prompt: Text(String(localized: "Search connections"))
.foregroundStyle(.tertiary)
)
.textFieldStyle(.plain)
.font(.body)
.focused($searchFocused)
.onKeyPress(.downArrow) {
moveSelection(by: 1)
return .handled
}
.onKeyPress(.upArrow) {
moveSelection(by: -1)
return .handled
}
.onKeyPress(.return) {
activateSelected()
return .handled
}
.onKeyPress(.escape) {
if searchText.isEmpty { return .ignored }
searchText = ""
return .handled
}

if !searchText.isEmpty {
Button {
searchText = ""
} label: {
Image(systemName: "xmark.circle.fill")
.imageScale(.small)
.foregroundStyle(.tertiary)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal, 6)
.padding(.vertical, 4)
.background(
RoundedRectangle(cornerRadius: 5, style: .continuous)
.fill(Color(nsColor: .quaternaryLabelColor).opacity(0.35))
NativeSearchField(
text: $searchText,
placeholder: String(localized: "Search connections"),
onMoveUp: { moveSelection(by: -1) },
onMoveDown: { moveSelection(by: 1) },
onSubmit: { activateSelected() },
focusOnAppear: true
)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.padding(.vertical, 6)
}

@ViewBuilder
Expand Down
Loading