Files
Flaro/Flixy/Views/Navigation/AccountBar.swift
T
ScarriffleandClaude Opus 5 0aa11e1c25 Die Einstellungen verlassen die Leiste — oben rechts steht jetzt das Konto
Auf dem iPhone belegten die Einstellungen einen von fünf Plätzen in der
unteren Leiste, gleichrangig neben Start und Bibliothek. Das unterstellt,
dass man zwischen ihnen hin und her wechselt, und das tut niemand.

Jetzt stehen dort drei Einträge — Start, Bibliothek, Downloads — und der
Weg in die Einstellungen führt über das Monogramm oben rechts. Auf dem
iPad und am Mac bleibt alles, wie es war: dort hat die Seitenleiste Platz,
und den Weg über das Konto gibt es ohnehin schon.

Drei Entscheidungen, die nicht offensichtlich sind:

**Ein Überzug, kein Werkzeugleisten-Knopf.** Die Startseite schaltet ihre
Navigationsleiste ganz ab — sie war leer und belegte trotzdem Höhe —, ein
`ToolbarItem` erschiene dort gar nicht. Der Knopf liegt deshalb einmal
über allen Bildschirmen statt dreimal in deren Leisten und sitzt überall
an derselben Stelle. Beim Scrollen blendet er sich aus, wie die Insel auf
dem iPad: über einem Film, den man gerade sucht, hat ein Kontoknopf
nichts verloren.

**Ein Blatt, kein Bereich.** `SettingsView` ist ein Formular aus
geschobenen Unterbildschirmen und braucht nur einen Navigationsstapel um
sich; die Medienziele aus `mediaStack` ruft es nie auf. Beim Schliessen
steht man wieder dort, wo man war.

**Ein Buchstabe, kein Bild.** Den Avatar gab es schon — er steckte in der
Kontozeile der Seitenleiste und wird jetzt von beiden benutzt. Ein
Serverbild führt das Konto heute nirgends mit, weder bei Jellyfin noch
bei Plex; eine graue Silhouette, die bei jedem gleich aussieht, sagt
weniger als der Anfangsbuchstabe.

Dazu gehört `.settings` in die Rückfallliste beim Grössenwechsel: wer am
iPad in den Einstellungen steht und das Fenster schmal zieht, stünde sonst
vor einem Bereich, den die Leiste gar nicht mehr führt.

Geprüft im Simulator: drei Einträge unten, Monogramm oben rechts, Tippen
öffnet die Einstellungen, Schliessen führt zurück.

iOS und tvOS bauen, 469 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-01 09:32:38 +02:00

139 lines
5.0 KiB
Swift

import SwiftUI
import FlixyDesign
/// Wer angemeldet ist — unten in der Seitenleiste.
///
/// Der Platz ist nicht zufällig: dort sucht man sein Konto, weil es in jeder
/// App der letzte Eintrag ist. Und von dort führt der Weg in die
/// Einstellungen, statt dass sie als gleichrangiger Eintrag zwischen den
/// Mediatheken stehen.
///
/// **Eine Karte, die über der Zeile aufgeht**, kein Systemmenü: mit denselben
/// Abständen und derselben Schrift wie der Rest der App, statt der grauen
/// Standardliste.
///
/// Sie hängt als Popover an der Zeile und wächst nicht in der Leiste selbst.
/// Das war der erste Versuch, und er ging schief: die Leiste unten hat eine
/// feste Höhe, die Karte wuchs nach unten aus dem Bild heraus, und die Zeile
/// mit dem Namen verschwand dabei.
///
/// Auf dem iPhone gibt es diese Leiste nicht; dort haben die Einstellungen
/// ihren eigenen Eintrag.
struct AccountBar: View {
@Binding var selection: SidebarDestination
@Environment(FlixySession.self) private var session
@State private var isExpanded = false
@State private var showsSignOutConfirmation = false
private var title: String {
session.accountName ?? session.serverName
}
/// Der Server steht nur dann darunter, wenn oben schon der Kontoname
/// steht — sonst stünde zweimal dasselbe.
private var subtitle: String? {
session.accountName == nil ? nil : session.serverName
}
var body: some View {
accountRow
.popover(isPresented: $isExpanded, arrowEdge: .bottom) {
VStack(spacing: 0) {
action("account.settings", symbol: "gearshape") {
isExpanded = false
selection = .settings
}
separator
action(
"action.signOut",
symbol: "rectangle.portrait.and.arrow.right",
isDestructive: true
) {
isExpanded = false
showsSignOutConfirmation = true
}
}
.frame(minWidth: 240)
.background(Color.flixySurface)
// Auf dem iPhone gäbe es diese Leiste gar nicht; die Angabe
// steht trotzdem da, damit aus dem Popover dort kein
// bildschirmfüllendes Sheet wird.
.presentationCompactAdaptation(.popover)
}
.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 var accountRow: some View {
Button {
isExpanded.toggle()
} label: {
HStack(spacing: FlixySpacing.snug) {
AccountAvatar(name: title)
VStack(alignment: .leading, spacing: 0) {
Text(title)
.font(.flixyCardTitle)
.foregroundStyle(Color.flixyTextPrimary)
.lineLimit(1)
if let subtitle {
Text(subtitle)
.font(.flixyCaption)
.foregroundStyle(Color.flixyTextMuted)
.lineLimit(1)
}
}
// Ohne Vorrang staucht SwiftUI den Text vor dem Zwischenraum:
// in einer schmalen Leiste stand vom Namen nur noch „S…" da.
.layoutPriority(1)
Spacer(minLength: 0)
// Zeigt nach oben: dorthin geht die Karte auf.
Image(systemName: "chevron.up")
.font(.caption2.weight(.semibold))
.foregroundStyle(Color.flixyTextMuted)
}
.padding(.horizontal, FlixySpacing.regular)
.padding(.vertical, FlixySpacing.snug)
.contentShape(.rect)
}
.buttonStyle(.plain)
.accessibilityLabel(Text(title))
.accessibilityHint(Text("account.hint"))
}
private func action(
_ title: LocalizedStringKey,
symbol: String,
isDestructive: Bool = false,
perform: @escaping () -> Void
) -> some View {
Button(action: perform) {
Label(title, systemImage: symbol)
.font(.flixyBody)
.foregroundStyle(isDestructive ? Color.flixyDestructive : Color.flixyTextPrimary)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, FlixySpacing.regular)
.padding(.vertical, FlixySpacing.regular)
.contentShape(.rect)
}
.buttonStyle(.plain)
}
private var separator: some View {
Divider().overlay(Color.flixySeparator)
}
}