Skip to content

Commit 6b5f3f4

Browse files
committed
feat: dynamic per-tab settings window sizing with animation
1 parent 49f3d7b commit 6b5f3f4

2 files changed

Lines changed: 61 additions & 1 deletion

File tree

TablePro/Views/Settings/SettingsView.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ import SwiftUI
1010
/// Settings tab identifiers for programmatic navigation
1111
enum SettingsTab: String {
1212
case general, appearance, editor, dataGrid, keyboard, history, ai, plugins, sync, license
13+
14+
var preferredSize: CGSize {
15+
switch self {
16+
case .general: CGSize(width: 450, height: 380)
17+
case .appearance: CGSize(width: 720, height: 500)
18+
case .editor: CGSize(width: 450, height: 300)
19+
case .dataGrid: CGSize(width: 450, height: 380)
20+
case .keyboard: CGSize(width: 500, height: 500)
21+
case .history: CGSize(width: 450, height: 320)
22+
case .ai: CGSize(width: 500, height: 520)
23+
case .plugins: CGSize(width: 650, height: 500)
24+
case .sync: CGSize(width: 450, height: 420)
25+
case .license: CGSize(width: 450, height: 280)
26+
}
27+
}
1328
}
1429

1530
/// Main settings view with tab-based navigation (macOS Settings style)
@@ -18,6 +33,10 @@ struct SettingsView: View {
1833
@Environment(UpdaterBridge.self) var updaterBridge
1934
@AppStorage("selectedSettingsTab") private var selectedTab: String = SettingsTab.general.rawValue
2035

36+
private var currentTab: SettingsTab {
37+
SettingsTab(rawValue: selectedTab) ?? .general
38+
}
39+
2140
var body: some View {
2241
TabView(selection: $selectedTab) {
2342
GeneralSettingsView(settings: $settingsManager.general, updaterBridge: updaterBridge)
@@ -81,7 +100,8 @@ struct SettingsView: View {
81100
}
82101
.tag(SettingsTab.license.rawValue)
83102
}
84-
.frame(width: 720, height: 500)
103+
.frame(width: currentTab.preferredSize.width, height: currentTab.preferredSize.height)
104+
.background(SettingsWindowResizer(size: currentTab.preferredSize))
85105
}
86106
}
87107

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// SettingsWindowResizer.swift
3+
// TablePro
4+
//
5+
6+
import AppKit
7+
import SwiftUI
8+
9+
/// Resizes the Settings window to match the selected tab's preferred size.
10+
/// Uses AppKit's `NSWindow.setFrame(_:display:animate:)` for smooth transitions,
11+
/// keeping the top-left corner pinned (standard macOS preferences behavior).
12+
struct SettingsWindowResizer: NSViewRepresentable {
13+
var size: CGSize
14+
15+
func makeNSView(context: Context) -> NSView {
16+
let view = _SettingsWindowSizeView()
17+
return view
18+
}
19+
20+
func updateNSView(_ nsView: NSView, context: Context) {
21+
guard let window = nsView.window else { return }
22+
let contentSize = size
23+
let newFrameSize = window.frameRect(forContentRect: NSRect(origin: .zero, size: contentSize)).size
24+
var frame = window.frame
25+
// Pin top-left corner
26+
frame.origin.y += frame.size.height - newFrameSize.height
27+
frame.size = newFrameSize
28+
let shouldAnimate = window.isVisible
29+
window.setFrame(frame, display: true, animate: shouldAnimate)
30+
window.minSize = newFrameSize
31+
window.maxSize = newFrameSize
32+
}
33+
}
34+
35+
private final class _SettingsWindowSizeView: NSView {
36+
override func viewDidMoveToWindow() {
37+
super.viewDidMoveToWindow()
38+
needsLayout = true
39+
}
40+
}

0 commit comments

Comments
 (0)