import SwiftUI import FlixyDesign import PlexKit /// Der Anmeldebildschirm. /// /// Zeigt den Code, den Plex vergeben hat, und schickt in den Browser. Die App /// bekommt Benutzername und Passwort nie zu sehen — sie fragt nur regelmäßig /// nach, ob der Code bestätigt wurde. struct SignInView: View { let phase: FlixySession.Phase let clientIdentifier: String let onSignIn: () -> Void let onCancel: () -> Void @Environment(\.openURL) private var openURL @Environment(\.flixyAccent) private var accent var body: some View { VStack(spacing: FlixySpacing.section) { Spacer() VStack(spacing: FlixySpacing.regular) { Image(systemName: "play.rectangle.on.rectangle") .font(.system(size: 52)) .foregroundStyle(accent) Text(Branding.appName) .font(.flixyHero) .foregroundStyle(Color.flixyTextPrimary) Text("signIn.tagline") .font(.flixyBody) .foregroundStyle(Color.flixyTextSecondary) .multilineTextAlignment(.center) } Spacer() if case .awaitingAuthorization(let pin) = phase { awaitingAuthorization(pin: pin) } else { Button(action: onSignIn) { Text("signIn.action") .font(.flixyRowHeader) .frame(maxWidth: .infinity) .padding(.vertical, FlixySpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) } Spacer().frame(height: FlixySpacing.section) } .padding(.horizontal, FlixySpacing.section) .frame(maxWidth: 420) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.flixyCanvas) } @ViewBuilder private func awaitingAuthorization(pin: PlexPin) -> some View { VStack(spacing: FlixySpacing.loose) { Text("signIn.codeHint") .font(.flixyCaption) .foregroundStyle(Color.flixyTextSecondary) .multilineTextAlignment(.center) Text(pin.code) // Feste Zeichenbreite, damit der Code beim Abtippen nicht // springt und Ziffern nicht mit Buchstaben verschwimmen. .font(.system(.largeTitle, design: .monospaced, weight: .semibold)) .tracking(6) .foregroundStyle(Color.flixyTextPrimary) .textSelection(.enabled) .padding(.vertical, FlixySpacing.regular) .frame(maxWidth: .infinity) .background(Color.flixyElevated, in: .rect(cornerRadius: FlixyRadius.sheet)) Button { if let url = pin.authorizationURL( clientIdentifier: clientIdentifier, product: Branding.plexProduct ) { openURL(url) } } label: { Label("signIn.openBrowser", systemImage: "safari") .frame(maxWidth: .infinity) .padding(.vertical, FlixySpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) HStack(spacing: FlixySpacing.snug) { ProgressView().controlSize(.small) Text("signIn.waiting") .font(.flixyCaption) .foregroundStyle(Color.flixyTextMuted) } Button("action.cancel", action: onCancel) .font(.flixyCaption) .foregroundStyle(Color.flixyTextSecondary) } } }