163 lines
5.4 KiB
Swift
163 lines
5.4 KiB
Swift
import SwiftUI
|
|
|
|
/// Tab root for "Konto" (see `App/MainTabView.swift`, which references
|
|
/// `SettingsView()` with a zero-arg initializer as its third tab). Wrapped in
|
|
/// its own `NavigationStack` — every push (folders, change password, delete
|
|
/// account) and the Pro-upgrade sheet originate from here.
|
|
struct SettingsView: View {
|
|
@EnvironmentObject private var appState: AppState
|
|
@State private var showPaywall = false
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
profileSection
|
|
foldersSection
|
|
accountSection
|
|
}
|
|
.zenithListBackground()
|
|
.navigationTitle("Konto")
|
|
.sheet(isPresented: $showPaywall) {
|
|
PaywallView()
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Profil
|
|
|
|
@ViewBuilder
|
|
private var profileSection: some View {
|
|
Section {
|
|
if let user = appState.currentUser {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text(user.name?.isEmpty == false ? user.name! : "Unbenannt")
|
|
.zenithHeadlineMdStyle()
|
|
if let email = user.email {
|
|
Text(email)
|
|
.zenithBodySmStyle()
|
|
}
|
|
}
|
|
.padding(.vertical, ZenithSpacing.unit)
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
|
|
if user.isPro {
|
|
proStatusRow(for: user)
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
} else {
|
|
freeStatusRow
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func proStatusRow(for user: User) -> some View {
|
|
VStack(alignment: .leading, spacing: ZenithSpacing.xs) {
|
|
HStack(spacing: ZenithSpacing.xs) {
|
|
Text("PRO")
|
|
.zenithLabelCapsStyle(color: .white)
|
|
.padding(.horizontal, 8)
|
|
.padding(.vertical, 3)
|
|
.background(Color.zenithBlack)
|
|
ZenithChip(text: planDisplayName(user.plan))
|
|
}
|
|
if let expiresAt = user.expiresAt, let date = ISO8601.parse(expiresAt) {
|
|
let formatted = date.formatted(date: .abbreviated, time: .omitted)
|
|
Text(user.cancelAtPeriodEnd ? "Läuft aus am \(formatted)" : "Verlängert sich am \(formatted)")
|
|
.zenithLabelMdStyle(color: .zenithMuted)
|
|
}
|
|
}
|
|
.padding(.vertical, ZenithSpacing.unit)
|
|
}
|
|
|
|
private var freeStatusRow: some View {
|
|
VStack(alignment: .leading, spacing: ZenithSpacing.xs) {
|
|
Text("Kostenlos")
|
|
.zenithBodyStyle(color: .zenithMuted)
|
|
Button("Auf Pro upgraden") {
|
|
showPaywall = true
|
|
}
|
|
.buttonStyle(.zenithPrimary)
|
|
}
|
|
.padding(.vertical, ZenithSpacing.unit)
|
|
}
|
|
|
|
private func planDisplayName(_ plan: String) -> String {
|
|
switch plan {
|
|
case "weekly": return "Wochen-Pass"
|
|
case "annual": return "Jahres-Pass"
|
|
case "lifetime": return "Lifetime"
|
|
case "free": return "Kostenlos"
|
|
default: return plan.capitalized
|
|
}
|
|
}
|
|
|
|
// MARK: - Ordner
|
|
|
|
private var foldersSection: some View {
|
|
Section {
|
|
NavigationLink {
|
|
ProjectsListView()
|
|
} label: {
|
|
Label {
|
|
Text("Ordner verwalten").zenithBodyStyle()
|
|
} icon: {
|
|
Image(systemName: "folder").foregroundStyle(Color.zenithMuted)
|
|
}
|
|
}
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
} header: {
|
|
Text("Ordner").zenithLabelCapsStyle()
|
|
}
|
|
}
|
|
|
|
// MARK: - Konto
|
|
|
|
private var accountSection: some View {
|
|
Section {
|
|
NavigationLink {
|
|
ChangePasswordView()
|
|
} label: {
|
|
Label {
|
|
Text("Passwort ändern").zenithBodyStyle()
|
|
} icon: {
|
|
Image(systemName: "lock").foregroundStyle(Color.zenithMuted)
|
|
}
|
|
}
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
|
|
Button {
|
|
Task { await appState.logout() }
|
|
} label: {
|
|
Label {
|
|
Text("Abmelden")
|
|
} icon: {
|
|
Image(systemName: "arrow.backward.square")
|
|
}
|
|
}
|
|
.buttonStyle(.zenithPlain)
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
|
|
NavigationLink {
|
|
DeleteAccountView()
|
|
} label: {
|
|
Label {
|
|
Text("Konto löschen").zenithBodyStyle(color: .zenithError)
|
|
} icon: {
|
|
Image(systemName: "trash").foregroundStyle(Color.zenithError)
|
|
}
|
|
}
|
|
.listRowBackground(Color.zenithSurface)
|
|
.listRowSeparatorTint(Color.zenithBorder)
|
|
} header: {
|
|
Text("Konto").zenithLabelCapsStyle()
|
|
}
|
|
}
|
|
}
|