Adopt root-level tsswift app layout
CI / test (push) Has been cancelled

Move the app payload under swift/ while keeping git, package.json, and .smartconfig.json at the repo root. This standardizes the Swift app setup so build, test, run, and watch workflows match the other repos.
This commit is contained in:
2026-04-19 01:21:43 +02:00
parent d534964601
commit a6939453f8
61 changed files with 2341 additions and 3 deletions
@@ -0,0 +1,193 @@
import SwiftUI
private let loginAccent = AppTheme.accent
struct LoginRootView: View {
@ObservedObject var model: AppViewModel
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
var body: some View {
AppScrollScreen(compactLayout: compactLayout) {
LoginHeroPanel(model: model, compactLayout: compactLayout)
PairingConsoleCard(model: model, compactLayout: compactLayout)
}
.sheet(isPresented: $model.isScannerPresented) {
QRScannerSheet(
seededPayload: model.suggestedPairingPayload,
title: "Scan linking QR",
description: "Use the camera to scan the QR code from the web flow that activates this device as your passport.",
navigationTitle: "Scan Linking QR",
onCodeScanned: { payload in
model.manualPairingPayload = payload
Task {
await model.signIn(with: payload, transport: .qr)
}
}
)
}
}
private var compactLayout: Bool {
#if os(iOS)
horizontalSizeClass == .compact
#else
false
#endif
}
}
private struct LoginHeroPanel: View {
@ObservedObject var model: AppViewModel
let compactLayout: Bool
var body: some View {
AppPanel(compactLayout: compactLayout, radius: AppLayout.largeCardRadius) {
AppBadge(title: "Secure passport setup", tone: loginAccent)
Text("Turn this device into a passport for your idp.global identity")
.font(.system(size: compactLayout ? 28 : 36, weight: .bold, design: .rounded))
.lineLimit(3)
Text("Scan a linking QR code or paste a payload to activate this device as your passport for identity proofs and security alerts.")
.font(.subheadline)
.foregroundStyle(.secondary)
Divider()
VStack(alignment: .leading, spacing: 14) {
LoginFeatureRow(icon: "qrcode.viewfinder", title: "Scan a QR code from the web flow")
LoginFeatureRow(icon: "doc.text.viewfinder", title: "Paste a payload when you already have one")
LoginFeatureRow(icon: "iphone.gen3", title: "Handle identity checks and alerts here")
}
if model.isBootstrapping {
ProgressView("Preparing preview passport...")
.tint(loginAccent)
}
}
}
}
private struct LoginFeatureRow: View {
let icon: String
let title: String
var body: some View {
HStack(alignment: .center, spacing: 12) {
Image(systemName: icon)
.font(.subheadline.weight(.semibold))
.foregroundStyle(loginAccent)
.frame(width: 28, height: 28)
Text(title)
.font(.headline)
Spacer(minLength: 0)
}
}
}
private struct PairingConsoleCard: View {
@ObservedObject var model: AppViewModel
let compactLayout: Bool
var body: some View {
AppSectionCard(title: "Set up passport", compactLayout: compactLayout) {
VStack(alignment: .leading, spacing: 8) {
Text("Link payload")
.font(.subheadline.weight(.semibold))
AppTextEditorField(
text: $model.manualPairingPayload,
minHeight: compactLayout ? 132 : 150
)
}
if model.isAuthenticating {
HStack(spacing: 10) {
ProgressView()
Text("Activating this passport...")
.foregroundStyle(.secondary)
}
}
Text("NFC, QR, and OTP proof methods become available after this passport is active.")
.font(.footnote)
.foregroundStyle(.secondary)
if compactLayout {
VStack(spacing: 12) {
primaryButtons
secondaryButtons
}
} else {
VStack(spacing: 12) {
HStack(spacing: 12) {
primaryButtons
}
secondaryButtons
}
}
}
}
@ViewBuilder
private var primaryButtons: some View {
Button {
model.isScannerPresented = true
} label: {
Label("Scan QR", systemImage: "qrcode.viewfinder")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.controlSize(.large)
}
@ViewBuilder
private var secondaryButtons: some View {
if compactLayout {
VStack(spacing: 12) {
usePayloadButton
previewPayloadButton
}
} else {
HStack(spacing: 12) {
usePayloadButton
previewPayloadButton
}
}
}
private var usePayloadButton: some View {
Button {
Task {
await model.signInWithManualPayload()
}
} label: {
if model.isAuthenticating {
ProgressView()
.frame(maxWidth: .infinity)
} else {
Label("Link with payload", systemImage: "arrow.right.circle")
.frame(maxWidth: .infinity)
}
}
.buttonStyle(.bordered)
.controlSize(.large)
.disabled(model.isAuthenticating)
}
private var previewPayloadButton: some View {
Button {
Task {
await model.signInWithSuggestedPayload()
}
} label: {
Label("Use preview passport", systemImage: "wand.and.stars")
.frame(maxWidth: .infinity)
}
.buttonStyle(.bordered)
.controlSize(.large)
}
}