import SwiftUI /// Pflicht-Passwortwechsel. Solange der offen ist, sperrt das Backend jeden /// fachlichen Endpunkt mit 403 – auch das Anlegen der Gerätemarke. Deshalb /// steht dieser Bildschirm vor allem anderen. /// /// Die Richtlinie des Servers (Mindestlänge, Zeichenarten) prüfen wir hier /// nicht nach. Das Backend kennt sie, und sie doppelt zu pflegen hiesse, sie /// irgendwann unterschiedlich zu haben. Es meldet den Grund im Klartext. struct PasswortWechselAnsicht: View { @Environment(AppZustand.self) private var zustand @State private var alt = "" @State private var neu = "" @State private var wiederholung = "" @FocusState private var feld: Feld? private enum Feld { case alt, neu, wiederholung } var body: some View { NavigationStack { Form { Section { SecureField(String(localized: "passwort.bisher"), text: $alt) .textContentType(.password) .focused($feld, equals: .alt) .submitLabel(.next) .onSubmit { feld = .neu } } footer: { Text(String(localized: "passwort.erklaerung")) } Section { SecureField(String(localized: "passwort.neu"), text: $neu) .textContentType(.newPassword) .focused($feld, equals: .neu) .submitLabel(.next) .onSubmit { feld = .wiederholung } SecureField(String(localized: "passwort.wiederholen"), text: $wiederholung) .textContentType(.newPassword) .focused($feld, equals: .wiederholung) .submitLabel(.go) .onSubmit { wechsle() } } footer: { if !wiederholung.isEmpty, neu != wiederholung { Text(String(localized: "passwort.stimmtNichtUeberein")) .foregroundStyle(.red) } } if let meldung = zustand.meldung { Section { Label(meldung, systemImage: "exclamationmark.triangle") .foregroundStyle(.red) } } Section { Button(action: wechsle) { if zustand.beschaeftigt { ProgressView() } else { Text(String(localized: "passwort.speichern")) } } .disabled(bereit == false || zustand.beschaeftigt) } Section { Button(String(localized: "allgemein.abmelden"), role: .destructive) { Task { await zustand.meldeAb() } } } } .navigationTitle(String(localized: "passwort.titel")) .onAppear { feld = .alt } } } private var bereit: Bool { !alt.isEmpty && !neu.isEmpty && neu == wiederholung } private func wechsle() { guard bereit else { return } let bisher = alt let frisch = neu Task { await zustand.wechslePasswort(alt: bisher, neu: frisch) alt = ""; neu = ""; wiederholung = "" } } }