import ManaCore import SwiftUI /// ViewModifier, der das Sign-In-Sheet für einen ``ManaAuthGate`` /// präsentiert. Die App liefert via `signIn`-Builder, welche Auth- /// View im Sheet gezeigt wird (üblich: ``ManaLoginView``). /// /// Beobachtet `gate.auth.status` und schließt das Sheet automatisch /// sobald der User eingeloggt ist; die ausstehende Aktion wird dann /// gestartet. Wird das Sheet vorher dismisst, wird die Aktion verworfen. public struct ManaAuthGateModifier: ViewModifier { @Bindable private var gate: ManaAuthGate private let signInContent: () -> SignInContent public init(gate: ManaAuthGate, @ViewBuilder signIn: @escaping () -> SignInContent) { self.gate = gate signInContent = signIn } public func body(content: Content) -> some View { content .sheet( isPresented: $gate.isPresentingSignIn, onDismiss: { gate.cancelPending() } ) { signInContent() .onChange(of: authStatusKey(gate.auth.status)) { _, _ in gate.resolvePending() } } } } /// Reduziert `AuthClient.Status` auf einen `Equatable`-stabilen Key /// für `onChange(of:)`. `Status` selbst ist `Equatable` — aber assoziierte /// Werte (Email-String) sind hier irrelevant, wir wollen nur auf den /// Übergang signedOut/guest → signedIn reagieren. private func authStatusKey(_ status: AuthClient.Status) -> Int { switch status { case .unknown: 0 case .signedOut: 1 case .guest: 2 case .signingIn: 3 case .twoFactorRequired: 4 case .signedIn: 5 case .error: 6 } } public extension View { /// Hängt einen ``ManaAuthGate`` an die View. Aufrufe von /// `gate.require { ... }` führen entweder zur Aktion (signedIn) oder /// zum Sign-In-Sheet, das der `signIn`-Builder liefert. /// /// Idiomatischer Einsatz: einmal am App-Root, danach den Gate via /// `.environment(gate)` in den Sub-Views verfügbar machen. func manaAuthGate( _ gate: ManaAuthGate, @ViewBuilder signIn: @escaping () -> some View ) -> some View { modifier(ManaAuthGateModifier(gate: gate, signIn: signIn)) } }