Skip to content

Commit 25efaa9

Browse files
authored
refactor: rebuild Welcome window as NavigationSplitView with toolbar-hosted search (#1052)
* refactor: rebuild Welcome window as NavigationSplitView with toolbar-hosted search * fix: drop out-of-scope plugin lookup change and dead minWidth from welcome detail
1 parent ab2ca90 commit 25efaa9

3 files changed

Lines changed: 40 additions & 130 deletions

File tree

TablePro/TableProApp.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ struct TableProApp: App {
636636
var body: some Scene {
637637
Window("Welcome to TablePro", id: SceneId.welcome) {
638638
WelcomeWindowView()
639-
.frame(width: 700, height: 450)
639+
.frame(width: 820, height: 500)
640640
.background(WindowOpenerBridge())
641641
.background(WindowChromeConfigurator(
642642
restorable: false,
@@ -646,7 +646,6 @@ struct TableProApp: App {
646646
))
647647
}
648648
.windowResizability(.contentSize)
649-
.windowStyle(.hiddenTitleBar)
650649
.commandsRemoved()
651650

652651
WindowGroup("New Connection", id: SceneId.connectionForm, for: UUID?.self) { $editingId in

TablePro/Views/Connection/WelcomeLeftPanel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct WelcomeLeftPanel: View {
6161
.padding(.horizontal, 12)
6262
.padding(.bottom, 20)
6363
}
64-
.frame(width: 260)
64+
.frame(maxWidth: .infinity, maxHeight: .infinity)
6565
}
6666

6767
private var versionLine: some View {

TablePro/Views/Connection/WelcomeWindowView.swift

Lines changed: 38 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33
// TablePro
44
//
55

6-
import AppKit
76
import os
87
import SwiftUI
98
import UniformTypeIdentifiers
109

1110
struct WelcomeWindowView: View {
1211
private enum FocusField {
13-
case search
1412
case connectionList
1513
}
1614

@@ -35,11 +33,9 @@ struct WelcomeWindowView: View {
3533
.transition(.move(edge: .trailing))
3634
}
3735
}
38-
.background(VisualEffectBackground(material: .underWindowBackground, blendingMode: .behindWindow))
39-
.ignoresSafeArea()
4036
.onAppear {
4137
vm.setUp()
42-
focus = .search
38+
focus = .connectionList
4339
}
4440
.alert(
4541
vm.connectionsToDelete.count == 1
@@ -199,104 +195,60 @@ struct WelcomeWindowView: View {
199195
// MARK: - Layout
200196

201197
private var welcomeContent: some View {
202-
HStack(spacing: 0) {
198+
NavigationSplitView(columnVisibility: .constant(.all)) {
203199
WelcomeLeftPanel(
204200
onActivateLicense: { vm.activeSheet = .activation },
205201
onCreateConnection: { WindowOpener.shared.openConnectionForm() }
206202
)
207-
Divider()
208-
rightPanel
203+
.navigationSplitViewColumnWidth(240)
204+
.toolbar(removing: .sidebarToggle)
205+
} detail: {
206+
connectionsDetail
209207
}
208+
.navigationSplitViewStyle(.balanced)
210209
.transition(.opacity)
211210
}
212211

213-
// MARK: - Right Panel
214-
215-
private var rightPanel: some View {
216-
VStack(spacing: 0) {
217-
HStack(spacing: 0) {
218-
HStack(spacing: 4) {
219-
WelcomeToolbarButton(
220-
systemImage: "plus",
221-
help: String(localized: "New Connection (⌘N)"),
222-
accessibilityLabel: String(localized: "New Connection")
223-
) {
224-
WindowOpener.shared.openConnectionForm()
225-
}
226-
227-
WelcomeToolbarButton(
228-
systemImage: "folder.badge.plus",
229-
help: String(localized: "New Group"),
230-
accessibilityLabel: String(localized: "New Group")
231-
) {
232-
vm.pendingMoveToNewGroup = []
233-
vm.activeSheet = .newGroup(parentId: nil)
234-
}
235-
}
236-
.padding(.trailing, 12)
237-
238-
NativeSearchField(
239-
text: $vm.searchText,
240-
placeholder: String(localized: "Search for connection..."),
241-
controlSize: .regular
242-
)
243-
.focused($focus, equals: .search)
244-
.onKeyPress(.return) {
245-
vm.connectSelectedConnections()
246-
return .handled
247-
}
248-
.onKeyPress(.escape) {
249-
if !vm.searchText.isEmpty {
250-
vm.searchText = ""
251-
}
252-
focus = .connectionList
253-
return .handled
254-
}
255-
.onKeyPress(characters: .init(charactersIn: "\u{7F}\u{08}"), phases: .down) { keyPress in
256-
guard keyPress.modifiers.contains(.command) else { return .ignored }
257-
let toDelete = vm.selectedConnections
258-
guard !toDelete.isEmpty else { return .ignored }
259-
vm.connectionsToDelete = toDelete
260-
vm.showDeleteConfirmation = true
261-
return .handled
262-
}
263-
.onKeyPress(characters: .init(charactersIn: "jn"), phases: [.down, .repeat]) { keyPress in
264-
guard keyPress.modifiers.contains(.control) else { return .ignored }
265-
vm.moveToNextConnection()
266-
focus = .connectionList
267-
return .handled
268-
}
269-
.onKeyPress(characters: .init(charactersIn: "kp"), phases: [.down, .repeat]) { keyPress in
270-
guard keyPress.modifiers.contains(.control) else { return .ignored }
271-
vm.moveToPreviousConnection()
272-
focus = .connectionList
273-
return .handled
274-
}
275-
.onKeyPress(.downArrow) {
276-
vm.moveToNextConnection()
277-
focus = .connectionList
278-
return .handled
279-
}
280-
.onKeyPress(.upArrow) {
281-
vm.moveToPreviousConnection()
282-
focus = .connectionList
283-
return .handled
284-
}
285-
}
286-
.padding(.horizontal, 16)
287-
.padding(.vertical, 12)
288-
289-
Divider()
212+
// MARK: - Detail (Connections)
290213

214+
private var connectionsDetail: some View {
215+
Group {
291216
if vm.treeItems.isEmpty && vm.filteredConnections.isEmpty {
292217
emptyState
293218
} else {
294219
connectionList
295220
}
296221
}
297-
.frame(minWidth: 350)
298222
.contentShape(Rectangle())
299223
.contextMenu { newConnectionContextMenu }
224+
.searchable(
225+
text: $vm.searchText,
226+
placement: .toolbar,
227+
prompt: Text("Search for connection...")
228+
)
229+
.onSubmit(of: .search) {
230+
vm.connectSelectedConnections()
231+
}
232+
.toolbar {
233+
ToolbarItem(placement: .primaryAction) {
234+
Button {
235+
WindowOpener.shared.openConnectionForm()
236+
} label: {
237+
Label(String(localized: "New Connection"), systemImage: "plus")
238+
}
239+
.help(String(localized: "New Connection (⌘N)"))
240+
}
241+
242+
ToolbarItem(placement: .primaryAction) {
243+
Button {
244+
vm.pendingMoveToNewGroup = []
245+
vm.activeSheet = .newGroup(parentId: nil)
246+
} label: {
247+
Label(String(localized: "New Group"), systemImage: "folder.badge.plus")
248+
}
249+
.help(String(localized: "New Group"))
250+
}
251+
}
300252
}
301253

302254
// MARK: - Connection List
@@ -667,47 +619,6 @@ private struct ConnectionCreationOverlays: ViewModifier {
667619
}
668620
}
669621

670-
// MARK: - Visual Effect Background
671-
672-
private struct VisualEffectBackground: NSViewRepresentable {
673-
let material: NSVisualEffectView.Material
674-
let blendingMode: NSVisualEffectView.BlendingMode
675-
676-
func makeNSView(context: Context) -> NSVisualEffectView {
677-
let view = NSVisualEffectView()
678-
view.material = material
679-
view.blendingMode = blendingMode
680-
view.state = .followsWindowActiveState
681-
view.isEmphasized = true
682-
return view
683-
}
684-
685-
func updateNSView(_ view: NSVisualEffectView, context: Context) {
686-
view.material = material
687-
view.blendingMode = blendingMode
688-
}
689-
}
690-
691-
// MARK: - Toolbar Button
692-
693-
private struct WelcomeToolbarButton: View {
694-
let systemImage: String
695-
let help: String
696-
let accessibilityLabel: String
697-
let action: () -> Void
698-
699-
var body: some View {
700-
Button(action: action) {
701-
Image(systemName: systemImage)
702-
.frame(width: 16, height: 16)
703-
}
704-
.buttonStyle(.bordered)
705-
.controlSize(.large)
706-
.help(help)
707-
.accessibilityLabel(accessibilityLabel)
708-
}
709-
}
710-
711622
// MARK: - Preview
712623

713624
#Preview("Welcome Window") {

0 commit comments

Comments
 (0)