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>
39 lines
1.1 KiB
Swift
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)"
|
|
}
|
|
}
|
|
}
|