import SwiftUI struct LinkScreen: View { @EnvironmentObject private var app: AppModel @State private var code: String? @State private var linkUrl = "" @State private var status = "Verbinden…" @State private var error: String? var body: some View { ZStack { LinearGradient( colors: [ Color(red: 0.12, green: 0.04, blue: 0.06), McColors.bg, Color(red: 0.04, green: 0.05, blue: 0.1), ], startPoint: .topLeading, endPoint: .bottomTrailing ) .ignoresSafeArea() VStack(spacing: 18) { Text("VMC") .font(McFonts.brand) .foregroundStyle(McColors.accent) .shadow(color: McColors.accent.opacity(0.4), radius: 18) Text("Koppel dit apparaat") .font(McFonts.title) .foregroundStyle(McColors.text) Text("Open je Vonas-account, voer deze code in en bevestig.") .font(McFonts.body) .foregroundStyle(McColors.textDim) .multilineTextAlignment(.center) .padding(.horizontal, 28) if let code { Text(code) .font(.system(size: 42, weight: .bold, design: .monospaced)) .foregroundStyle(McColors.text) .padding(.vertical, 10) .padding(.horizontal, 22) .background(McColors.surface.opacity(0.9), in: RoundedRectangle(cornerRadius: 16, style: .continuous)) .overlay( RoundedRectangle(cornerRadius: 16, style: .continuous) .stroke(McColors.accent.opacity(0.35), lineWidth: 1) ) } else if error == nil { ProgressView().tint(.white) } if !linkUrl.isEmpty { Text(linkUrl) .font(McFonts.caption) .foregroundStyle(McColors.textDim) } Text(status) .font(McFonts.caption) .foregroundStyle(McColors.textDim) if let error { Text(error) .font(McFonts.body) .foregroundStyle(McColors.danger) .multilineTextAlignment(.center) .padding(.horizontal) Button("Opnieuw") { Task { await startLink() } } .buttonStyle(McPrimaryButtonStyle()) } } .padding() .frame(maxWidth: 420) } .task { await startLink() } } private func startLink() async { error = nil code = nil status = "Verbinden…" await app.api.configure(baseUrl: app.store.apiBase, token: nil) do { let created = try await app.api.createDeviceCode(deviceName: AppModel.deviceName) code = created.code linkUrl = created.linkUrl ?? "" status = "Wachten tot je de code bevestigt…" let interval = max(created.pollIntervalSeconds ?? 2, 2) while true { try await Task.sleep(nanoseconds: UInt64(interval) * 1_000_000_000) switch try await app.api.pollDeviceCode(code: created.code) { case .linked(let token, let name): status = "Welkom, \(name)" try await Task.sleep(nanoseconds: 700_000_000) await app.didLink(token: token) return case .expired: status = "Code verlopen" error = "Code verlopen — probeer opnieuw" return case .alreadyLinked: status = "Al gekoppeld" error = "Al gekoppeld — herstart de app" return case .pending: break } } } catch { self.error = error.localizedDescription status = "Mislukt" } } }