import SwiftUI import ProxyCore struct SetupGuideView: View { @Environment(AppState.self) private var appState var isReady: Bool { appState.isVPNConnected && appState.hasSharedCertificate } var body: some View { VStack(spacing: 24) { // Status Banner HStack { Image(systemName: isReady ? "checkmark.circle.fill" : "exclamationmark.triangle.fill") .font(.title2) VStack(alignment: .leading) { Text(isReady ? "Ready to Capture" : "Setup Required") .font(.headline) Text(isReady ? "The tunnel and shared certificate are configured" : "Complete the steps below to start") .font(.caption) .foregroundStyle(.white.opacity(0.8)) } Spacer() } .foregroundStyle(.white) .padding() .background(isReady ? Color.green : Color.orange, in: RoundedRectangle(cornerRadius: 12)) Text("Follow these two steps to start capturing network traffic on your device.") .font(.subheadline) .foregroundStyle(.secondary) // Step 1: VPN stepRow( title: "VPN Extension Enabled", subtitle: appState.isVPNConnected ? "VPN is running and capturing traffic" : "Tap to enable VPN", isComplete: appState.isVPNConnected, action: { Task { await appState.toggleVPN() } } ) // Step 2: Certificate NavigationLink { CertificateView() } label: { HStack(spacing: 12) { Image(systemName: appState.hasSharedCertificate ? "checkmark.circle.fill" : "circle") .font(.title2) .foregroundStyle(appState.hasSharedCertificate ? .green : .secondary) VStack(alignment: .leading) { Text("Shared Certificate Available") .font(.subheadline.weight(.medium)) .foregroundStyle(appState.hasSharedCertificate ? .green : .primary) Text(certificateSubtitle) .font(.caption) .foregroundStyle(.secondary) } Spacer() } .padding() .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) if let lastError = appState.lastRuntimeError { VStack(alignment: .leading, spacing: 8) { Label("Latest Runtime Error", systemImage: "exclamationmark.triangle.fill") .font(.subheadline.weight(.medium)) .foregroundStyle(.orange) Text(lastError) .font(.caption) .foregroundStyle(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) .padding() .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12)) } Spacer() } .padding() .navigationTitle("Setup Guide") .navigationBarTitleDisplayMode(.inline) } private var certificateSubtitle: String { if !appState.isCertificateInstalled { return "Generate and install the Proxy CA certificate." } if !appState.hasSharedCertificate { return "The app has a CA, but the extension has not loaded the same one yet." } if appState.isHTTPSInspectionVerified { return "HTTPS inspection has been verified on live traffic." } return "Include a domain in SSL Proxying, trust the CA in Settings, then retry the request." } private func stepRow(title: String, subtitle: String, isComplete: Bool, action: @escaping () -> Void) -> some View { Button(action: action) { HStack(spacing: 12) { Image(systemName: isComplete ? "checkmark.circle.fill" : "circle") .font(.title2) .foregroundStyle(isComplete ? .green : .secondary) VStack(alignment: .leading) { Text(title) .font(.subheadline.weight(.medium)) .foregroundStyle(isComplete ? .green : .primary) Text(subtitle) .font(.caption) .foregroundStyle(.secondary) } Spacer() } .padding() .background(Color(.secondarySystemGroupedBackground), in: RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) } }