import CryptoKit import Foundation import SwiftUI private let dashboardAccent = AppTheme.accent private let dashboardGold = AppTheme.warmAccent private extension View { @ViewBuilder func inlineNavigationTitleOnIOS() -> some View { #if os(iOS) navigationBarTitleDisplayMode(.inline) #else self #endif } @ViewBuilder func cleanTabBarOnIOS() -> some View { #if os(iOS) toolbarBackground(.visible, for: .tabBar) .toolbarBackground(Color.white.opacity(0.98), for: .tabBar) #else self #endif } } struct HomeRootView: View { @ObservedObject var model: AppViewModel var body: some View { Group { if usesCompactNavigation { CompactHomeContainer(model: model) } else { RegularHomeContainer(model: model) } } .sheet(isPresented: $model.isNotificationCenterPresented) { NotificationCenterSheet(model: model) } } private var usesCompactNavigation: Bool { #if os(iOS) true #else false #endif } } private struct CompactHomeContainer: View { @ObservedObject var model: AppViewModel @Environment(\.horizontalSizeClass) private var horizontalSizeClass var body: some View { TabView(selection: $model.selectedSection) { ForEach(AppSection.allCases) { section in NavigationStack { HomeSectionScreen(model: model, section: section, compactLayout: compactLayout) .navigationTitle(section.title) .inlineNavigationTitleOnIOS() .toolbar { DashboardToolbar(model: model) } } .tag(section) .tabItem { Label(section.title, systemImage: section.systemImage) } } } .cleanTabBarOnIOS() } private var compactLayout: Bool { #if os(iOS) horizontalSizeClass == .compact #else false #endif } } private struct RegularHomeContainer: View { @ObservedObject var model: AppViewModel var body: some View { NavigationSplitView { Sidebar(model: model) } detail: { HomeSectionScreen(model: model, section: model.selectedSection, compactLayout: false) .navigationTitle(model.selectedSection.title) .toolbar { DashboardToolbar(model: model) } } .navigationSplitViewStyle(.balanced) } } private struct DashboardToolbar: ToolbarContent { @ObservedObject var model: AppViewModel var body: some ToolbarContent { ToolbarItemGroup(placement: .primaryAction) { NotificationBellButton(model: model) } } } private struct HomeSectionScreen: View { @ObservedObject var model: AppViewModel let section: AppSection let compactLayout: Bool @State private var focusedRequest: ApprovalRequest? @State private var isOTPPresented = false @StateObject private var identifyReader = NFCIdentifyReader() var body: some View { AppScrollScreen( compactLayout: compactLayout, bottomPadding: compactLayout ? AppLayout.compactBottomDockPadding : AppLayout.regularBottomPadding ) { HomeTopActions( model: model, identifyReader: identifyReader, onScanQR: { model.isScannerPresented = true }, onShowOTP: { isOTPPresented = true } ) switch section { case .overview: OverviewPanel(model: model, compactLayout: compactLayout) case .requests: RequestsPanel(model: model, compactLayout: compactLayout, onOpenRequest: { focusedRequest = $0 }) case .activity: ActivityPanel(model: model, compactLayout: compactLayout) case .account: AccountPanel(model: model, compactLayout: compactLayout) } } .task { identifyReader.onAuthenticationRequestDetected = { request in Task { await model.identifyWithNFC(request) } } identifyReader.onError = { message in model.errorMessage = message } } .sheet(item: $focusedRequest) { request in RequestDetailSheet(request: request, model: model) } .sheet(isPresented: $model.isScannerPresented) { QRScannerSheet( seededPayload: model.session?.pairingCode ?? model.suggestedPairingPayload, title: "Scan proof QR", description: "Use the camera to scan an idp.global QR challenge from the site or device asking you to prove that it is really you.", navigationTitle: "Scan Proof QR", onCodeScanned: { payload in Task { await model.identifyWithPayload(payload, transport: .qr) } } ) } .sheet(isPresented: $isOTPPresented) { if let session = model.session { OneTimePasscodeSheet(session: session) } } } } private struct HomeTopActions: View { @ObservedObject var model: AppViewModel @ObservedObject var identifyReader: NFCIdentifyReader let onScanQR: () -> Void let onShowOTP: () -> Void var body: some View { LazyVGrid(columns: columns, spacing: 12) { identifyButton qrButton otpButton } } private var columns: [GridItem] { Array(repeating: GridItem(.flexible(), spacing: 12), count: 3) } private var identifyButton: some View { Button { identifyReader.beginScanning() } label: { AppActionTile( title: identifyReader.isScanning ? "Scanning NFC" : "Tap NFC", systemImage: "dot.radiowaves.left.and.right", tone: dashboardAccent, isBusy: identifyReader.isScanning || model.isIdentifying ) } .buttonStyle(.plain) .disabled(identifyReader.isScanning || !identifyReader.isSupported || model.isIdentifying) } private var qrButton: some View { Button { onScanQR() } label: { AppActionTile( title: "Scan QR", systemImage: "qrcode.viewfinder", tone: dashboardAccent ) } .buttonStyle(.plain) } private var otpButton: some View { Button { onShowOTP() } label: { AppActionTile( title: "OTP", systemImage: "number.square.fill", tone: dashboardGold ) } .buttonStyle(.plain) } } private struct Sidebar: View { @ObservedObject var model: AppViewModel var body: some View { List { Section { SidebarStatusCard( profile: model.profile, pendingCount: model.pendingRequests.count, unreadCount: model.unreadNotificationCount ) } Section("Workspace") { ForEach(AppSection.allCases) { section in Button { model.selectedSection = section } label: { HStack { Label(section.title, systemImage: section.systemImage) Spacer() if badgeCount(for: section) > 0 { AppStatusTag(title: "\(badgeCount(for: section))", tone: dashboardAccent) } } } .buttonStyle(.plain) .listRowBackground( model.selectedSection == section ? dashboardAccent.opacity(0.10) : Color.clear ) } } } .navigationTitle("idp.global") } private func badgeCount(for section: AppSection) -> Int { switch section { case .overview: 0 case .requests: model.pendingRequests.count case .activity: model.unreadNotificationCount case .account: 0 } } } private struct SidebarStatusCard: View { let profile: MemberProfile? let pendingCount: Int let unreadCount: Int var body: some View { VStack(alignment: .leading, spacing: 10) { Text("Digital Passport") .font(.headline) Text(profile?.handle ?? "No passport active") .foregroundStyle(.secondary) HStack(spacing: 8) { AppStatusTag(title: "\(pendingCount) pending", tone: dashboardAccent) AppStatusTag(title: "\(unreadCount) unread", tone: dashboardGold) } } .padding(.vertical, 6) } } private struct OverviewPanel: View { @ObservedObject var model: AppViewModel let compactLayout: Bool var body: some View { VStack(alignment: .leading, spacing: AppLayout.sectionSpacing(for: compactLayout)) { if let profile = model.profile, let session = model.session { OverviewHero( profile: profile, session: session, pendingCount: model.pendingRequests.count, unreadCount: model.unreadNotificationCount, compactLayout: compactLayout ) } } } } private struct RequestsPanel: View { @ObservedObject var model: AppViewModel let compactLayout: Bool let onOpenRequest: (ApprovalRequest) -> Void var body: some View { VStack(alignment: .leading, spacing: AppLayout.sectionSpacing(for: compactLayout)) { if model.requests.isEmpty { AppPanel(compactLayout: compactLayout) { EmptyStateCopy( title: "No checks waiting", systemImage: "checkmark.circle", message: "Identity proof requests from sites and devices appear here." ) } } else { RequestList( requests: model.requests, compactLayout: compactLayout, activeRequestID: model.activeRequestID, onApprove: { request in Task { await model.approve(request) } }, onReject: { request in Task { await model.reject(request) } }, onOpenRequest: onOpenRequest ) } } } } private struct ActivityPanel: View { @ObservedObject var model: AppViewModel let compactLayout: Bool var body: some View { VStack(alignment: .leading, spacing: AppLayout.sectionSpacing(for: compactLayout)) { if model.notifications.isEmpty { AppPanel(compactLayout: compactLayout) { EmptyStateCopy( title: "No proof activity yet", systemImage: "clock.badge.xmark", message: "Identity proofs and security events will appear here." ) } } else { NotificationList( notifications: model.notifications, compactLayout: compactLayout, onMarkRead: { notification in Task { await model.markNotificationRead(notification) } } ) } } } } private struct NotificationsPanel: View { @ObservedObject var model: AppViewModel let compactLayout: Bool var body: some View { VStack(alignment: .leading, spacing: AppLayout.sectionSpacing(for: compactLayout)) { AppSectionCard(title: "Delivery", compactLayout: compactLayout) { NotificationPermissionSummary(model: model, compactLayout: compactLayout) } AppSectionCard(title: "Alerts", compactLayout: compactLayout) { if model.notifications.isEmpty { EmptyStateCopy( title: "No alerts yet", systemImage: "bell.slash", message: "New passport and identity-proof alerts will accumulate here." ) } else { NotificationList( notifications: model.notifications, compactLayout: compactLayout, onMarkRead: { notification in Task { await model.markNotificationRead(notification) } } ) } } } } } private struct AccountPanel: View { @ObservedObject var model: AppViewModel let compactLayout: Bool var body: some View { VStack(alignment: .leading, spacing: AppLayout.sectionSpacing(for: compactLayout)) { if let profile = model.profile, let session = model.session { AccountHero(profile: profile, session: session, compactLayout: compactLayout) AppSectionCard(title: "Session", compactLayout: compactLayout) { AccountFactsGrid(profile: profile, session: session, compactLayout: compactLayout) } } AppSectionCard(title: "Pairing payload", compactLayout: compactLayout) { AppTextSurface(text: model.suggestedPairingPayload, monospaced: true) } AppSectionCard(title: "Actions", compactLayout: compactLayout) { Button(role: .destructive) { model.signOut() } label: { Label("Sign Out", systemImage: "rectangle.portrait.and.arrow.right") } .buttonStyle(.bordered) } } } } private struct OverviewHero: View { let profile: MemberProfile let session: AuthSession let pendingCount: Int let unreadCount: Int let compactLayout: Bool private var detailColumns: [GridItem] { Array(repeating: GridItem(.flexible(), spacing: 16), count: compactLayout ? 1 : 2) } private var metricColumns: [GridItem] { Array(repeating: GridItem(.flexible(), spacing: 16), count: 3) } var body: some View { AppPanel(compactLayout: compactLayout, radius: AppLayout.largeCardRadius) { AppBadge(title: "Digital passport", tone: dashboardAccent) VStack(alignment: .leading, spacing: 6) { Text(profile.name) .font(.system(size: compactLayout ? 30 : 38, weight: .bold, design: .rounded)) .lineLimit(2) Text("\(profile.handle) • \(profile.organization)") .font(.subheadline) .foregroundStyle(.secondary) } HStack(spacing: 8) { AppStatusTag(title: "Passport active", tone: dashboardAccent) AppStatusTag(title: session.pairingTransport.title, tone: dashboardGold) } Divider() LazyVGrid(columns: detailColumns, alignment: .leading, spacing: 16) { AppKeyValue(label: "Device", value: session.deviceName) AppKeyValue(label: "Origin", value: session.originHost, monospaced: true) AppKeyValue(label: "Linked", value: session.pairedAt.formatted(date: .abbreviated, time: .shortened)) AppKeyValue(label: "Token", value: "...\(session.tokenPreview)", monospaced: true) } Divider() LazyVGrid(columns: metricColumns, alignment: .leading, spacing: 16) { AppMetric(title: "Pending", value: "\(pendingCount)") AppMetric(title: "Alerts", value: "\(unreadCount)") AppMetric(title: "Devices", value: "\(profile.deviceCount)") } } } } private struct NotificationPermissionSummary: View { @ObservedObject var model: AppViewModel let compactLayout: Bool var body: some View { VStack(alignment: .leading, spacing: 14) { HStack(alignment: .top, spacing: 12) { Image(systemName: model.notificationPermission.systemImage) .font(.headline) .foregroundStyle(dashboardAccent) .frame(width: 28, height: 28) VStack(alignment: .leading, spacing: 4) { Text(model.notificationPermission.title) .font(.headline) Text(model.notificationPermission.summary) .font(.subheadline) .foregroundStyle(.secondary) } } if compactLayout { VStack(alignment: .leading, spacing: 12) { permissionButtons } } else { HStack(spacing: 12) { permissionButtons } } } } @ViewBuilder private var permissionButtons: some View { Button { Task { await model.requestNotificationAccess() } } label: { Label("Enable notifications", systemImage: "bell.and.waves.left.and.right.fill") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) Button { Task { await model.sendTestNotification() } } label: { Label("Send test alert", systemImage: "paperplane.fill") .frame(maxWidth: .infinity) } .buttonStyle(.bordered) } } private struct AccountHero: View { let profile: MemberProfile let session: AuthSession let compactLayout: Bool var body: some View { AppPanel(compactLayout: compactLayout, radius: AppLayout.largeCardRadius) { AppBadge(title: "Account", tone: dashboardAccent) Text(profile.name) .font(.system(size: compactLayout ? 28 : 34, weight: .bold, design: .rounded)) .lineLimit(2) Text(profile.handle) .font(.headline) .foregroundStyle(.secondary) Text("Active client: \(session.deviceName)") .font(.subheadline) .foregroundStyle(.secondary) } } } private struct AccountFactsGrid: View { let profile: MemberProfile let session: AuthSession let compactLayout: Bool private var columns: [GridItem] { Array(repeating: GridItem(.flexible(), spacing: 16), count: compactLayout ? 1 : 2) } var body: some View { LazyVGrid(columns: columns, alignment: .leading, spacing: 16) { AppKeyValue(label: "Organization", value: profile.organization) AppKeyValue(label: "Origin", value: session.originHost, monospaced: true) AppKeyValue(label: "Linked At", value: session.pairedAt.formatted(date: .abbreviated, time: .shortened)) AppKeyValue(label: "Method", value: session.pairingTransport.title) AppKeyValue(label: "Token", value: "...\(session.tokenPreview)", monospaced: true) AppKeyValue(label: "Recovery", value: profile.recoverySummary) if let signedGPSPosition = session.signedGPSPosition { AppKeyValue( label: "Signed GPS", value: "\(signedGPSPosition.coordinateSummary) \(signedGPSPosition.accuracySummary)", monospaced: true ) } AppKeyValue(label: "Trusted Devices", value: "\(profile.deviceCount)") } } } private struct RequestList: View { let requests: [ApprovalRequest] let compactLayout: Bool let activeRequestID: ApprovalRequest.ID? let onApprove: ((ApprovalRequest) -> Void)? let onReject: ((ApprovalRequest) -> Void)? let onOpenRequest: (ApprovalRequest) -> Void var body: some View { VStack(spacing: 14) { ForEach(requests) { request in RequestCard( request: request, compactLayout: compactLayout, isBusy: activeRequestID == request.id, onApprove: onApprove == nil ? nil : { onApprove?(request) }, onReject: onReject == nil ? nil : { onReject?(request) }, onOpenRequest: { onOpenRequest(request) } ) } } } } private struct RequestCard: View { let request: ApprovalRequest let compactLayout: Bool let isBusy: Bool let onApprove: (() -> Void)? let onReject: (() -> Void)? let onOpenRequest: () -> Void var body: some View { VStack(alignment: .leading, spacing: 12) { HStack(alignment: .top, spacing: 12) { Image(systemName: request.kind.systemImage) .font(.headline) .foregroundStyle(requestAccent) .frame(width: 28, height: 28) VStack(alignment: .leading, spacing: 4) { Text(request.title) .font(.headline) .multilineTextAlignment(.leading) Text(request.source) .font(.subheadline) .foregroundStyle(.secondary) .lineLimit(1) } Spacer(minLength: 0) AppStatusTag(title: request.status.title, tone: statusTone) } Text(request.subtitle) .font(.subheadline) .foregroundStyle(.secondary) .lineLimit(2) HStack(spacing: 8) { AppStatusTag(title: request.risk.title, tone: request.risk == .routine ? dashboardAccent : .orange) Text(request.scopeSummary) .font(.footnote) .foregroundStyle(.secondary) Spacer(minLength: 0) Text(request.createdAt, style: .relative) .font(.footnote) .foregroundStyle(.secondary) } if !request.scopes.isEmpty { Text("Proof details: \(request.scopes.joined(separator: ", "))") .font(.footnote) .foregroundStyle(.secondary) .lineLimit(2) } controls } .padding(compactLayout ? 18 : 20) .appSurface(radius: 24) } @ViewBuilder private var controls: some View { if compactLayout { VStack(alignment: .leading, spacing: 10) { reviewButton decisionButtons } } else { HStack(spacing: 12) { reviewButton Spacer(minLength: 0) decisionButtons } } } private var reviewButton: some View { Button { onOpenRequest() } label: { Label("Review proof", systemImage: "arrow.up.forward.app") } .buttonStyle(.bordered) } @ViewBuilder private var decisionButtons: some View { if request.status == .pending, let onApprove, let onReject { Button { onApprove() } label: { if isBusy { ProgressView() } else { Label("Verify", systemImage: "checkmark.circle.fill") } } .buttonStyle(.borderedProminent) .disabled(isBusy) Button(role: .destructive) { onReject() } label: { Label("Decline", systemImage: "xmark.circle.fill") } .buttonStyle(.bordered) .disabled(isBusy) } } private var statusTone: Color { switch request.status { case .pending: .orange case .approved: .green case .rejected: .red } } private var requestAccent: Color { switch request.status { case .approved: .green case .rejected: .red case .pending: request.risk == .routine ? dashboardAccent : .orange } } } private struct NotificationList: View { let notifications: [AppNotification] let compactLayout: Bool let onMarkRead: (AppNotification) -> Void var body: some View { VStack(spacing: 14) { ForEach(notifications) { notification in NotificationCard( notification: notification, compactLayout: compactLayout, onMarkRead: { onMarkRead(notification) } ) } } } } private struct NotificationCard: View { let notification: AppNotification let compactLayout: Bool let onMarkRead: () -> Void var body: some View { VStack(alignment: .leading, spacing: 10) { HStack(alignment: .top, spacing: 12) { Image(systemName: notification.kind.systemImage) .font(.headline) .foregroundStyle(accentColor) .frame(width: 28, height: 28) VStack(alignment: .leading, spacing: 4) { Text(notification.title) .font(.headline) HStack(spacing: 8) { AppStatusTag(title: notification.kind.title, tone: accentColor) if notification.isUnread { AppStatusTag(title: "Unread", tone: .orange) } } } Spacer(minLength: 0) } Text(notification.message) .font(.subheadline) .foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) if compactLayout { VStack(alignment: .leading, spacing: 10) { timestamp if notification.isUnread { markReadButton } } } else { HStack { timestamp Spacer(minLength: 0) if notification.isUnread { markReadButton } } } } .padding(compactLayout ? 18 : 20) .appSurface(radius: 24) } private var timestamp: some View { Text(notification.sentAt.formatted(date: .abbreviated, time: .shortened)) .font(.footnote) .foregroundStyle(.secondary) } private var markReadButton: some View { Button { onMarkRead() } label: { Label("Mark read", systemImage: "checkmark") } .buttonStyle(.bordered) } private var accentColor: Color { switch notification.kind { case .approval: .green case .security: .orange case .system: .blue } } } private struct NotificationBellButton: View { @ObservedObject var model: AppViewModel var body: some View { Button { model.isNotificationCenterPresented = true } label: { ZStack(alignment: .topTrailing) { Image(systemName: model.unreadNotificationCount == 0 ? "bell" : "bell.badge.fill") .font(.headline) .foregroundStyle(model.unreadNotificationCount == 0 ? .primary : dashboardAccent) if model.unreadNotificationCount > 0 { Text("\(min(model.unreadNotificationCount, 9))") .font(.caption2.weight(.bold)) .padding(.horizontal, 5) .padding(.vertical, 2) .background(Color.orange, in: Capsule()) .foregroundStyle(.white) .offset(x: 10, y: -10) } } .frame(width: 28, height: 28) } .accessibilityLabel("Notifications") } } private struct NotificationCenterSheet: View { @ObservedObject var model: AppViewModel @Environment(\.dismiss) private var dismiss @Environment(\.horizontalSizeClass) private var horizontalSizeClass var body: some View { NavigationStack { AppScrollScreen( compactLayout: compactLayout, bottomPadding: compactLayout ? AppLayout.compactBottomDockPadding : AppLayout.regularBottomPadding ) { NotificationsPanel(model: model, compactLayout: compactLayout) } .navigationTitle("Notifications") .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Done") { dismiss() } } } } #if os(iOS) .presentationDetents(compactLayout ? [.large] : [.medium, .large]) #endif } private var compactLayout: Bool { #if os(iOS) horizontalSizeClass == .compact #else false #endif } } private struct RequestDetailSheet: View { let request: ApprovalRequest @ObservedObject var model: AppViewModel @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { AppScrollScreen( compactLayout: true, bottomPadding: AppLayout.compactBottomDockPadding ) { RequestDetailHero(request: request) AppSectionCard(title: "Summary", compactLayout: true) { AppKeyValue(label: "Source", value: request.source) AppKeyValue(label: "Requested", value: request.createdAt.formatted(date: .abbreviated, time: .shortened)) AppKeyValue(label: "Risk", value: request.risk.summary) AppKeyValue(label: "Type", value: request.kind.title) } AppSectionCard(title: "Proof details", compactLayout: true) { if request.scopes.isEmpty { Text("No explicit proof details were provided by the mock backend.") .foregroundStyle(.secondary) } else { Text(request.scopes.joined(separator: "\n")) .font(.body.monospaced()) .foregroundStyle(.secondary) } } AppSectionCard(title: "Guidance", compactLayout: true) { Text(request.trustDetail) .foregroundStyle(.secondary) Text(request.risk.guidance) .font(.headline) } if request.status == .pending { AppSectionCard(title: "Actions", compactLayout: true) { VStack(spacing: 12) { Button { Task { await model.approve(request) dismiss() } } label: { if model.activeRequestID == request.id { ProgressView() } else { Label("Verify identity", systemImage: "checkmark.circle.fill") .frame(maxWidth: .infinity) } } .buttonStyle(.borderedProminent) .disabled(model.activeRequestID == request.id) Button(role: .destructive) { Task { await model.reject(request) dismiss() } } label: { Label("Decline", systemImage: "xmark.circle.fill") .frame(maxWidth: .infinity) } .buttonStyle(.bordered) .disabled(model.activeRequestID == request.id) } } } } .navigationTitle("Review Proof") .inlineNavigationTitleOnIOS() .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Close") { dismiss() } } } } } } private struct RequestDetailHero: View { let request: ApprovalRequest private var accent: Color { switch request.status { case .approved: .green case .rejected: .red case .pending: request.risk == .routine ? dashboardAccent : .orange } } var body: some View { AppPanel(compactLayout: true, radius: AppLayout.largeCardRadius) { AppBadge(title: request.kind.title, tone: accent) Text(request.title) .font(.system(size: 30, weight: .bold, design: .rounded)) .lineLimit(3) Text(request.subtitle) .foregroundStyle(.secondary) HStack(spacing: 8) { AppStatusTag(title: request.status.title, tone: accent) AppStatusTag(title: request.risk.title, tone: request.risk == .routine ? dashboardAccent : .orange) } } } } private struct OneTimePasscodeSheet: View { let session: AuthSession @Environment(\.dismiss) private var dismiss @Environment(\.horizontalSizeClass) private var horizontalSizeClass var body: some View { NavigationStack { TimelineView(.periodic(from: .now, by: 1)) { context in let code = passcode(at: context.date) let secondsRemaining = renewalCountdown(at: context.date) AppScrollScreen(compactLayout: compactLayout) { AppPanel(compactLayout: compactLayout, radius: AppLayout.largeCardRadius) { AppBadge(title: "One-time passcode", tone: dashboardGold) Text("OTP") .font(.system(size: compactLayout ? 32 : 40, weight: .bold, design: .rounded)) Text("Share this code only with the site or device asking you to prove that it is really you.") .font(.subheadline) .foregroundStyle(.secondary) Text(code) .font(.system(size: compactLayout ? 42 : 54, weight: .bold, design: .rounded).monospacedDigit()) .tracking(compactLayout ? 4 : 6) .frame(maxWidth: .infinity) .padding(.vertical, compactLayout ? 16 : 20) .background(AppTheme.mutedFill, in: RoundedRectangle(cornerRadius: 24, style: .continuous)) .overlay( RoundedRectangle(cornerRadius: 24, style: .continuous) .stroke(AppTheme.border, lineWidth: 1) ) HStack(spacing: 8) { AppStatusTag(title: "Renews in \(secondsRemaining)s", tone: dashboardGold) AppStatusTag(title: session.originHost, tone: dashboardAccent) } Divider() AppKeyValue(label: "Client", value: session.deviceName) AppKeyValue(label: "Linked", value: session.pairedAt.formatted(date: .abbreviated, time: .shortened)) } } } .navigationTitle("OTP") .inlineNavigationTitleOnIOS() .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Close") { dismiss() } } } } } private var compactLayout: Bool { #if os(iOS) horizontalSizeClass == .compact #else false #endif } private func passcode(at date: Date) -> String { let timeSlot = Int(date.timeIntervalSince1970 / 30) let digest = SHA256.hash(data: Data("\(session.pairingCode)|\(timeSlot)".utf8)) let value = digest.prefix(4).reduce(UInt32(0)) { partialResult, byte in (partialResult << 8) | UInt32(byte) } return String(format: "%06d", locale: Locale(identifier: "en_US_POSIX"), Int(value % 1_000_000)) } private func renewalCountdown(at date: Date) -> Int { let elapsed = Int(date.timeIntervalSince1970) % 30 return elapsed == 0 ? 30 : 30 - elapsed } } private struct EmptyStateCopy: View { let title: String let systemImage: String let message: String var body: some View { ContentUnavailableView( title, systemImage: systemImage, description: Text(message) ) .frame(maxWidth: .infinity) .padding(.vertical, 10) } }