Der schwarze Streifen über der Navigation war kein gezeichneter Balken, sondern fehlender Inhalt: der gesamte Baum saß innerhalb des Sicherheitsrands. Deshalb erreichte kein noch so gut gesetzter Rand weiter unten die Fläche darüber — Inhalt kam dort nie hin. Jetzt reißt der HStack den Rand oben auf und gibt den Platz kontrolliert zurück: Seitenleiste und Insel bekommen ihren Abstand zur Statusleiste explizit, der Inhalt bekommt ihn als Sicherheitsrand. Der Aufmacher nimmt ihn sich wieder — um genau diese Strecke höher und um genau diese Strecke größer, sodass unten alles bleibt, wo es war. Dazu ein knapper Verlauf oben, damit Uhrzeit und Batterie auch über einem hellen Bild lesbar bleiben. Und die Leiste oben fährt beim Scrollen weg. Nur sie: der Sicherheitsrand darunter bleibt stehen, sonst ruckte die Seite bei jedem Ein- und Ausblenden unter dem Finger weg. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
121 lines
4.4 KiB
Swift
121 lines
4.4 KiB
Swift
import SwiftUI
|
|
import FlixyDesign
|
|
|
|
/// Die Einstellungen — als Übersicht, nicht als eine lange Liste.
|
|
///
|
|
/// Vorher stand alles untereinander auf einem Bildschirm: Serverangaben,
|
|
/// Qualität, Wiedergabe, drei Verweise, Downloads, Version, Abmelden. Das
|
|
/// war beim Bauen bequem und beim Suchen anstrengend — je mehr Einstellungen
|
|
/// dazukamen, desto weiter rutschte alles nach unten.
|
|
///
|
|
/// Jetzt führt jede Zeile in einen Bildschirm, der zu **einer** Frage gehört.
|
|
struct SettingsView: View {
|
|
@Environment(FlixySession.self) private var session
|
|
@Environment(\.flixyAccent) private var accent
|
|
@State private var showsSignOutConfirmation = false
|
|
|
|
var body: some View {
|
|
Form {
|
|
if session.backend != nil {
|
|
Section {
|
|
NavigationLink {
|
|
ServerSettingsView()
|
|
} label: {
|
|
LabeledContent {
|
|
Text(session.serverName)
|
|
.foregroundStyle(Color.flixyTextSecondary)
|
|
} label: {
|
|
row(
|
|
"settings.server",
|
|
symbol: "externaldrive.connected.to.line.below",
|
|
colour: SettingsPalette.server
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Section("settings.section.look") {
|
|
link("appearance.title", symbol: "paintpalette", colour: SettingsPalette.appearance) {
|
|
AppearanceView()
|
|
}
|
|
link("homeLayout.title", symbol: "rectangle.stack", colour: SettingsPalette.home) {
|
|
HomeLayoutView()
|
|
}
|
|
}
|
|
|
|
Section("settings.section.playing") {
|
|
link("settings.playback", symbol: "play.rectangle", colour: SettingsPalette.playback) {
|
|
PlaybackSettingsView()
|
|
}
|
|
link("languages.title", symbol: "captions.bubble", colour: SettingsPalette.languages) {
|
|
LanguagesView()
|
|
}
|
|
link("sidebar.downloads", symbol: "arrow.down.circle", colour: SettingsPalette.downloads) {
|
|
DownloadSettingsView()
|
|
}
|
|
}
|
|
|
|
Section {
|
|
link("diagnostics.title", symbol: "stethoscope", colour: SettingsPalette.diagnostics) {
|
|
DiagnosticsView()
|
|
}
|
|
}
|
|
|
|
Section("settings.app") {
|
|
LabeledContent("settings.version", value: Branding.version)
|
|
LabeledContent("settings.build", value: Branding.buildStamp)
|
|
}
|
|
|
|
Section {
|
|
Button("action.signOut", role: .destructive) {
|
|
showsSignOutConfirmation = true
|
|
}
|
|
}
|
|
}
|
|
// Ausdrücklich, nicht nur geerbt.
|
|
//
|
|
// Listen und Formulare zeichnen ihre Zeilen teilweise in einem
|
|
// eigenen Darstellungskontext, in dem eigene Umgebungswerte verloren
|
|
// gehen können — sichtbar an Picker-Werten, die in der Standardfarbe
|
|
// leuchteten, während die Schalter daneben schon die gewählte trugen.
|
|
.tint(accent)
|
|
.flixyForm()
|
|
.scrollContentBackground(.hidden)
|
|
.flixyRevealsTopChrome()
|
|
.background(Color.flixyCanvas)
|
|
.navigationTitle(Text("sidebar.settings"))
|
|
.flixyInlineTitle()
|
|
.confirmationDialog(
|
|
Text("settings.signOutConfirm"),
|
|
isPresented: $showsSignOutConfirmation,
|
|
titleVisibility: .visible
|
|
) {
|
|
Button("action.signOut", role: .destructive) { session.signOut() }
|
|
Button("action.cancel", role: .cancel) {}
|
|
} message: {
|
|
Text("settings.signOutExplanation")
|
|
}
|
|
}
|
|
|
|
private func link<Destination: View>(
|
|
_ title: LocalizedStringKey,
|
|
symbol: String,
|
|
colour: Color,
|
|
@ViewBuilder destination: @escaping () -> Destination
|
|
) -> some View {
|
|
NavigationLink {
|
|
destination()
|
|
} label: {
|
|
row(title, symbol: symbol, colour: colour)
|
|
}
|
|
}
|
|
|
|
private func row(_ title: LocalizedStringKey, symbol: String, colour: Color) -> some View {
|
|
HStack(spacing: FlixySpacing.regular) {
|
|
SettingsIcon(symbol: symbol, colour: colour)
|
|
Text(title)
|
|
}
|
|
}
|
|
}
|