Refocus app around identity proof flows

This commit is contained in:
2026-04-18 01:05:22 +02:00
parent d195037eb6
commit ea6b45388f
45 changed files with 2784 additions and 3159 deletions
+64 -32
View File
@@ -9,56 +9,58 @@ import AppKit
struct QRScannerSheet: View {
let seededPayload: String
let title: String
let description: String
let navigationTitleText: String
let onCodeScanned: (String) -> Void
@Environment(\.dismiss) private var dismiss
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@State private var manualFallback = ""
init(
seededPayload: String,
title: String = "Scan QR",
description: String = "Use the camera to scan an idp.global QR challenge.",
navigationTitle: String = "Scan QR",
onCodeScanned: @escaping (String) -> Void
) {
self.seededPayload = seededPayload
self.title = title
self.description = description
self.navigationTitleText = navigationTitle
self.onCodeScanned = onCodeScanned
}
var body: some View {
NavigationStack {
ScrollView {
VStack(alignment: .leading, spacing: 20) {
Text("Use the camera to scan the QR code shown by the web portal. If youre on a simulator or desktop without a camera, the seeded payload works as a mock fallback.")
AppScrollScreen(compactLayout: compactLayout) {
AppSectionCard(title: title, compactLayout: compactLayout) {
Text(description)
.font(.subheadline)
.foregroundStyle(.secondary)
LiveQRScannerView(onCodeScanned: onCodeScanned)
.frame(minHeight: 340)
}
VStack(alignment: .leading, spacing: 12) {
Text("Fallback Pairing Payload")
.font(.headline)
TextEditor(text: $manualFallback)
.font(.body.monospaced())
.scrollContentBackground(.hidden)
.padding(14)
.frame(minHeight: 120)
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 24, style: .continuous))
AppSectionCard(title: "Manual fallback", compactLayout: compactLayout) {
AppTextEditorField(text: $manualFallback, minHeight: 120)
if compactLayout {
VStack(spacing: 12) {
useFallbackButton
useSeededButton
}
} else {
HStack(spacing: 12) {
Button {
let chosen = manualFallback.trimmingCharacters(in: .whitespacesAndNewlines)
onCodeScanned(chosen.isEmpty ? seededPayload : chosen)
dismiss()
} label: {
Label("Use Fallback Payload", systemImage: "arrow.up.forward.square")
}
.buttonStyle(.borderedProminent)
Button {
manualFallback = seededPayload
} label: {
Label("Use Seeded Mock", systemImage: "wand.and.rays")
}
.buttonStyle(.bordered)
useFallbackButton
useSeededButton
}
}
.padding(20)
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 28, style: .continuous))
}
.padding(24)
}
.navigationTitle("Scan QR Code")
.navigationTitle(navigationTitleText)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Close") {
@@ -71,6 +73,36 @@ struct QRScannerSheet: View {
}
}
}
private var compactLayout: Bool {
#if os(iOS)
horizontalSizeClass == .compact
#else
false
#endif
}
private var useFallbackButton: some View {
Button {
let chosen = manualFallback.trimmingCharacters(in: .whitespacesAndNewlines)
onCodeScanned(chosen.isEmpty ? seededPayload : chosen)
dismiss()
} label: {
Label("Use payload", systemImage: "arrow.up.forward.square")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
}
private var useSeededButton: some View {
Button {
manualFallback = seededPayload
} label: {
Label("Reset sample", systemImage: "wand.and.rays")
.frame(maxWidth: .infinity)
}
.buttonStyle(.bordered)
}
}
private struct LiveQRScannerView: View {