import SwiftUI struct SuperviseView: View { @Environment(WizardModel.self) private var model @State private var task: Task? var body: some View { VStack(alignment: .leading, spacing: 16) { header Text("Wir schreiben jetzt die Supervision-Plist auf dein iPhone und starten es neu. Das dauert ~60 Sekunden. **Trenne das USB-Kabel nicht.**") .foregroundStyle(.secondary) statusBox logViewer Spacer() navigationBar } .padding(40) .onAppear { startIfNeeded() } .onDisappear { task?.cancel() } } private var header: some View { HStack { Image(systemName: "lock.shield") .font(.system(size: 30)) .foregroundStyle(.tint) Text("Supervisieren") .font(.title).bold() } } @ViewBuilder private var statusBox: some View { if model.supervisionRunning { HStack(spacing: 8) { ProgressView().controlSize(.small) Text("supervise-magic läuft …") } .padding(10) .background(Color.blue.opacity(0.08)) .cornerRadius(6) } else if let err = model.supervisionError { HStack(alignment: .top, spacing: 8) { Image(systemName: "xmark.octagon") .foregroundStyle(.red) Text(err).font(.callout) } .padding(10) .background(Color.red.opacity(0.08)) .cornerRadius(6) } else if !model.supervisionLog.isEmpty { HStack { Image(systemName: "checkmark.circle.fill").foregroundStyle(.green) Text("Supervisieren abgeschlossen.") } .padding(10) .background(Color.green.opacity(0.08)) .cornerRadius(6) } } private var logViewer: some View { ScrollViewReader { proxy in ScrollView { LazyVStack(alignment: .leading, spacing: 2) { ForEach(Array(model.supervisionLog.enumerated()), id: \.offset) { idx, line in Text(line) .font(.system(.caption, design: .monospaced)) .foregroundStyle(line.contains("[stderr]") ? .orange : .secondary) .id(idx) } } .padding(8) .frame(maxWidth: .infinity, alignment: .leading) } .background(Color.black.opacity(0.04)) .cornerRadius(6) .frame(maxHeight: 220) .onChange(of: model.supervisionLog.count) { _, newCount in if newCount > 0 { proxy.scrollTo(newCount - 1, anchor: .bottom) } } } } private var navigationBar: some View { HStack { Button("Zurück") { model.goTo(.preflight) } .buttonStyle(.bordered) .disabled(model.supervisionRunning) Spacer() if model.supervisionError != nil { Button("Neu versuchen") { startSupervise() } .buttonStyle(.bordered) } Button("Weiter →") { model.advance() } .buttonStyle(.borderedProminent) .disabled(model.supervisionRunning || model.supervisionLog.isEmpty || model.supervisionError != nil) } } private func startIfNeeded() { if model.supervisionLog.isEmpty && !model.supervisionRunning && model.supervisionError == nil { startSupervise() } } private func startSupervise() { model.supervisionLog = [] model.supervisionError = nil model.supervisionRunning = true task?.cancel() task = Task { @MainActor in do { _ = try await SuperviseRunner.supervise(organizationName: "ReBreak", force: true) { line in model.supervisionLog.append(line) } model.supervisionRunning = false model.device?.isSupervised = true } catch { model.supervisionError = error.localizedDescription model.supervisionRunning = false } } } }