import SwiftUI /// Benutzername und Passwort – einmal. Danach trägt die Gerätemarke, und /// das Passwort wird nirgends gespeichert. struct AnmeldeAnsicht: View { @Environment(AppZustand.self) private var zustand @State private var benutzer = Ablage.benutzername ?? "" @State private var passwort = "" @FocusState private var feld: Feld? private enum Feld { case benutzer, passwort } var body: some View { NavigationStack { Form { Section { TextField(String(localized: "anmeldung.benutzer"), text: $benutzer) .textContentType(.username) .textInputAutocapitalization(.never) .autocorrectionDisabled() .focused($feld, equals: .benutzer) .submitLabel(.next) .onSubmit { feld = .passwort } SecureField(String(localized: "anmeldung.passwort"), text: $passwort) .textContentType(.password) .focused($feld, equals: .passwort) .submitLabel(.go) .onSubmit { melde() } } footer: { Text(String(localized: "anmeldung.erklaerung")) } if let meldung = zustand.meldung { Section { Label(meldung, systemImage: "exclamationmark.triangle") .foregroundStyle(.red) } } Section { Button(action: melde) { if zustand.beschaeftigt { ProgressView() } else { Text(String(localized: "anmeldung.anmelden")) } } .disabled(bereit == false || zustand.beschaeftigt) } Section { Button(String(localized: "anmeldung.andererServer"), role: .destructive) { Task { await zustand.meldeAb(adresseBehalten: false) } } } footer: { if let adresse = zustand.serverAdresse { Text(String(format: String(localized: "anmeldung.aktuellerServer"), adresse.host() ?? adresse.absoluteString)) } } } .navigationTitle(String(localized: "anmeldung.titel")) .onAppear { feld = benutzer.isEmpty ? .benutzer : .passwort } } } private var bereit: Bool { !benutzer.trimmingCharacters(in: .whitespaces).isEmpty && !passwort.isEmpty } private func melde() { guard bereit else { return } let name = benutzer.trimmingCharacters(in: .whitespaces) let geheim = passwort passwort = "" Task { await zustand.melde(benutzer: name, passwort: geheim) } } }