import SwiftUI struct MacRegistrationView: View { @Environment(WizardModel.self) private var model @State private var macInfo: MacDeviceInfo? @State private var isRegistering = false @State private var isInstallingProfile = false @State private var errorMessage: String? @State private var successMessage: String? @State private var profileInstalled = false @State private var checkingProfile = false var body: some View { VStack(spacing: 24) { Image(systemName: "desktopcomputer.and.arrow.down") .font(.system(size: 80)) .foregroundStyle(.blue) Text("Mac für ReBreak Magic registrieren") .font(.title) .bold() Text("Bevor wir mit dem iPhone-Setup starten, muss dieser Mac registriert und geschützt werden.") .multilineTextAlignment(.center) .foregroundStyle(.secondary) .padding(.horizontal, 40) if let info = macInfo { macInfoCard(info) } else { ProgressView("Lese Mac-Informationen...") .progressViewStyle(.circular) } if let error = errorMessage { errorCard(error) } if let success = successMessage { successCard(success) } if let registration = model.magicRegistration, profileInstalled { VStack(spacing: 12) { HStack(spacing: 8) { Image(systemName: "checkmark.shield.fill") .foregroundStyle(.green) Text("Mac erfolgreich geschützt") .font(.headline) .foregroundStyle(.green) } VStack(alignment: .leading, spacing: 6) { Text("✓ DNS-Filter-Profil installiert") Text("✓ Device registriert: \(registration.deviceId.prefix(8))...") } .font(.caption) .foregroundStyle(.secondary) .frame(maxWidth: .infinity, alignment: .leading) } .padding() .background(Color.green.opacity(0.1)) .cornerRadius(8) .frame(maxWidth: 400) } HStack(spacing: 12) { if model.magicRegistration == nil { Button("Mac registrieren") { handleRegistration() } .buttonStyle(.borderedProminent) .disabled(isRegistering || macInfo == nil || isInstallingProfile) } else if !profileInstalled { Button("DNS-Profil installieren") { handleProfileInstall() } .buttonStyle(.borderedProminent) .disabled(isInstallingProfile) } else { Button("Weiter → iPhone-Setup") { model.advance() } .buttonStyle(.borderedProminent) } if isRegistering || isInstallingProfile { ProgressView() .controlSize(.small) } } } .padding(40) .onAppear { loadMacInfo() checkProfileStatus() } } @ViewBuilder private func macInfoCard(_ info: MacDeviceInfo) -> some View { VStack(alignment: .leading, spacing: 8) { HStack { Image(systemName: "desktopcomputer") .foregroundStyle(.blue) Text(info.hostname) .font(.headline) } Text("\(info.model) · macOS \(info.osVersion)") .font(.callout) .foregroundStyle(.secondary) Text("Device-ID: \(info.deviceId.prefix(8))...\(info.deviceId.suffix(8))") .font(.system(.caption, design: .monospaced)) .foregroundStyle(.tertiary) } .padding() .frame(maxWidth: 400, alignment: .leading) .background(Color.blue.opacity(0.08)) .cornerRadius(8) } @ViewBuilder private func errorCard(_ error: String) -> some View { VStack(spacing: 8) { HStack(spacing: 8) { Image(systemName: "exclamationmark.triangle.fill") .foregroundStyle(.red) Text(error) .font(.callout) .foregroundStyle(.red) .multilineTextAlignment(.leading) } .frame(maxWidth: .infinity, alignment: .leading) } .padding() .background(Color.red.opacity(0.1)) .cornerRadius(8) .frame(maxWidth: 400) } @ViewBuilder private func successCard(_ message: String) -> some View { HStack(spacing: 8) { Image(systemName: "checkmark.circle.fill") .foregroundStyle(.green) Text(message) .font(.callout) .foregroundStyle(.green) } .padding() .background(Color.green.opacity(0.1)) .cornerRadius(8) .frame(maxWidth: 400) } private func loadMacInfo() { Task { do { let info = try MacDeviceDetector.detect() await MainActor.run { macInfo = info } } catch { await MainActor.run { errorMessage = "Mac-Info konnte nicht gelesen werden: \(error.localizedDescription)" } } } } private func checkProfileStatus() { Task { checkingProfile = true let installed = await MacProfileInstaller.isInstalled() await MainActor.run { profileInstalled = installed checkingProfile = false } } } private func handleRegistration() { Task { isRegistering = true errorMessage = nil successMessage = nil do { try await model.registerMac() await MainActor.run { successMessage = "Mac erfolgreich registriert ✓" isRegistering = false } // Auto-trigger profile install try await Task.sleep(nanoseconds: 500_000_000) // 0.5s delay await handleProfileInstall() } catch { await MainActor.run { isRegistering = false errorMessage = error.localizedDescription } } } } private func handleProfileInstall() { guard let registration = model.magicRegistration else { errorMessage = "Keine Registrierung vorhanden. Bitte zuerst registrieren." return } Task { isInstallingProfile = true errorMessage = nil do { try await MacProfileInstaller.downloadAndInstall(registration: registration) // Re-check profile status await checkProfileStatus() await MainActor.run { isInstallingProfile = false successMessage = "DNS-Filter-Profil installiert ✓" } } catch { await MainActor.run { isInstallingProfile = false errorMessage = "Profil-Installation fehlgeschlagen: \(error.localizedDescription)" } } } } } #Preview { MacRegistrationView() .environment(WizardModel()) .frame(width: 720, height: 600) }