Einstellungen: die Linie unter den Reitern ist weg, und eine Fläche für alles

Die Linie kam von `TabView` selbst: es zieht unter seiner Leiste einen Trenner
quer durchs Fenster, und der lässt sich nicht abschalten. Der Abstand nach
oben, den ich beim letzten Mal eingebaut habe, hat deshalb nichts geändert —
der Trenner ist mitgewandert. Jetzt ist die Reiterleiste selbst gebaut, ein
Auswahlfeld über dem Inhalt, dann gibt es die Linie gar nicht erst.

Der zweite Punkt hat dieselbe Wurzel: die Formulare bringen ihren eigenen
Untergrund mit, der Rest des Fensters hat den des Systems. In Dunkelgrau
liegen die beiden ein, zwei Prozent auseinander — sichtbar als Kante quer
durchs Fenster, genau dort, wo das Formular anfängt. Der Untergrund der
Formulare ist jetzt abgeschaltet, und das ganze Fenster hat einen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-13 23:34:47 +02:00
parent 6c92e7fed6
commit 2c3b3cdd55
4 changed files with 76 additions and 30 deletions

View File

@@ -88,6 +88,9 @@ struct ColorSettingsView: View {
}
}
.formStyle(.grouped)
// Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem
// des Fensters ab. In Dunkelgrau sieht man genau das als Kante.
.scrollContentBackground(.hidden)
}
}

View File

@@ -29,6 +29,9 @@ struct FanSettingsView: View {
}
}
.formStyle(.grouped)
// Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem
// des Fensters ab. In Dunkelgrau sieht man genau das als Kante.
.scrollContentBackground(.hidden)
.padding()
.onAppear {
control.refreshInstallState()

View File

@@ -24,42 +24,73 @@ struct SettingsView: View {
let showOnboarding: () -> Void
@Binding var selectedTab: SettingsTab
/// Die Reiter in der Reihenfolge, in der sie oben stehen.
private static let tabs: [(tab: SettingsTab, label: LocalizedStringKey)] = [
(.widgets, "settings.tab.widgets"),
(.display, "settings.tab.display"),
(.colors, "settings.tab.colors"),
(.sources, "settings.tab.options"),
(.menubar, "settings.tab.menubar"),
(.fans, "settings.tab.fans"),
(.permissions, "settings.tab.permissions"),
]
var body: some View {
TabView(selection: $selectedTab) {
WidgetSettings(model: model, shelfStore: shelfStore)
.tabItem { Label("settings.tab.widgets", systemImage: "square.grid.2x2") }
.tag(SettingsTab.widgets)
DisplaySettings(model: model)
.tabItem { Label("settings.tab.display", systemImage: "macbook") }
.tag(SettingsTab.display)
ColorSettingsView(theme: OnyxTheme.shared)
.tabItem { Label("settings.tab.colors", systemImage: "paintpalette") }
.tag(SettingsTab.colors)
WidgetOptionsView(calendarModel: calendarModel, weatherModel: weatherModel,
shelfStore: shelfStore)
.tabItem { Label("settings.tab.options", systemImage: "slider.horizontal.3") }
.tag(SettingsTab.sources)
MenuBarSettings(model: model, metricsModel: metricsModel)
.tabItem { Label("settings.tab.menubar", systemImage: "menubar.rectangle") }
.tag(SettingsTab.menubar)
FanSettingsView(control: fanControl)
.tabItem { Label("settings.tab.fans", systemImage: "fan") }
.tag(SettingsTab.fans)
PermissionSettings(calendarModel: calendarModel, weatherModel: weatherModel,
launchAtLogin: launchAtLogin, showOnboarding: showOnboarding)
.tabItem { Label("settings.tab.permissions", systemImage: "hand.raised") }
.tag(SettingsTab.permissions)
// Eigene Reiterleiste statt `TabView`.
//
// `TabView` zieht unter seiner Leiste einen Trenner quer durchs
// Fenster nicht abschaltbar, und die Leiste sitzt mittig darauf.
// Abstand nach oben half nicht: der Trenner wandert mit. Also die
// Leiste selbst gebaut, dann gibt es die Linie gar nicht erst.
VStack(spacing: 0) {
Picker("", selection: $selectedTab) {
ForEach(Self.tabs, id: \.tab) { entry in
Text(entry.label).tag(entry.tab)
}
// Abstand nach oben: ohne ihn sitzt die Reiterleiste genau auf der
// Trennlinie unter dem Titelbalken und sieht aus, als läge sie auf
// einer Kante. `TabView` in einem gewöhnlichen Fenster bekommt diesen
// Abstand nicht von selbst in Apples `Settings`-Szene schon, und die
// benutzt Onyx bewusst nicht.
.padding(.top, 12)
}
.pickerStyle(.segmented)
.labelsHidden()
// Nur so breit wie nötig und mittig: über die volle Fensterbreite
// gezogen sähen sieben Reiter aus wie eine Werkzeugleiste.
.fixedSize()
.padding(.top, 10)
.padding(.bottom, 14)
content
}
// Eine Fläche für alles.
//
// Vorher hatte jeder Bereich seinen eigenen Untergrund: die
// Formulare bringen einen mit, der Rest des Fensters hat den des
// Systems, und die beiden liegen in Dunkelgrau ein, zwei Prozent
// auseinander. Sichtbar wurde das als Kante quer durchs Fenster.
.background(Color(nsColor: .windowBackgroundColor))
// Nur ein Mindestmaß, keine feste Größe: sonst kann das Fenster
// wachsen, der Inhalt aber nicht mit.
.frame(minWidth: 740, minHeight: 460)
}
@ViewBuilder
private var content: some View {
switch selectedTab {
case .widgets:
WidgetSettings(model: model, shelfStore: shelfStore)
case .display:
DisplaySettings(model: model)
case .colors:
ColorSettingsView(theme: OnyxTheme.shared)
case .sources:
WidgetOptionsView(calendarModel: calendarModel, weatherModel: weatherModel,
shelfStore: shelfStore)
case .menubar:
MenuBarSettings(model: model, metricsModel: metricsModel)
case .fans:
FanSettingsView(control: fanControl)
case .permissions:
PermissionSettings(calendarModel: calendarModel, weatherModel: weatherModel,
launchAtLogin: launchAtLogin, showOnboarding: showOnboarding)
}
}
}
// MARK: - Berechtigungen
@@ -141,6 +172,9 @@ private struct PermissionSettings: View {
}
}
.formStyle(.grouped)
// Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem
// des Fensters ab. In Dunkelgrau sieht man genau das als Kante.
.scrollContentBackground(.hidden)
.padding()
.task {
launchAtLogin.refresh()
@@ -517,6 +551,9 @@ private struct DisplaySettings: View {
.fixedSize(horizontal: false, vertical: true)
}
.formStyle(.grouped)
// Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem
// des Fensters ab. In Dunkelgrau sieht man genau das als Kante.
.scrollContentBackground(.hidden)
.padding()
}
}

View File

@@ -33,6 +33,9 @@ struct WidgetOptionsView: View {
}
}
.formStyle(.grouped)
// Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem
// des Fensters ab. In Dunkelgrau sieht man genau das als Kante.
.scrollContentBackground(.hidden)
.padding()
}
}