payfrit-beacon-ios/PayfritBeacon/Views/RootView.swift
Schwifty cfa78679be feat: complete rebuild of PayfritBeacon iOS from scratch
100% fresh codebase — no legacy code carried over. Built against
the Android beacon app as the behavioral spec.

Architecture:
- App: SwiftUI @main, AppState-driven navigation, Keychain storage
- Views: LoginView (OTP + biometric), BusinessListView, ScanView (provisioning hub)
- Models: Business, ServicePoint, BeaconConfig, BeaconType, DiscoveredBeacon
- Services: APIClient (actor, async/await), BLEManager (CoreBluetooth scanner)
- Provisioners: KBeacon, DXSmart (2-step auth + flashing), BlueCharm
- Utils: UUIDFormatting, BeaconBanList, BeaconShardPool (64 shards)

Matches Android feature parity:
- 4-screen flow: Login → Business Select → Scan/Provision
- 3 beacon types with correct GATT protocols and timeouts
- Namespace allocation via beacon-sharding API
- Smart service point naming (Table N auto-increment)
- DXSmart special flow (connect → flash → user confirms → write)
- Biometric auth, dev/prod build configs, DEV banner overlay

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 17:13:36 +00:00

39 lines
1.1 KiB
Swift

import SwiftUI
/// Root navigation switches between Login, BusinessList, and Scan screens
struct RootView: View {
@EnvironmentObject var appState: AppState
var body: some View {
ZStack {
switch appState.currentScreen {
case .login:
LoginView()
.transition(.opacity)
case .businessList:
BusinessListView()
.transition(.move(edge: .trailing))
case .scan(let business):
ScanView(business: business)
.transition(.move(edge: .trailing))
}
}
.animation(.easeInOut(duration: 0.3), value: screenKey)
.overlay(alignment: .top) {
if APIConfig.isDev {
DevBanner()
}
}
}
/// Stable key for animation
private var screenKey: String {
switch appState.currentScreen {
case .login: return "login"
case .businessList: return "businesses"
case .scan(let b): return "scan-\(b.id)"
}
}
}