import SwiftUI /// Simple load state for screen view models. enum LoadPhase: Equatable { case idle case loading case loaded case failed(String) } // MARK: - State / severity badges struct StateBadge: View { let text: String let color: Color var body: some View { Text(text) .font(.caption2.weight(.semibold)) .padding(.horizontal, 8) .padding(.vertical, 3) .background(color.opacity(0.18)) .foregroundStyle(color) .clipShape(Capsule()) } } extension ONULifecycleState { var color: Color { switch self { case .registered: return .green case .unspecified: return .mint // also "online" (dev guide Procedure 2) case .unprovisioned: return .blue case .deregistered: return .gray case .dyingGasp, .disallowedError: return .red case .disabled, .disallowedAdmin, .disallowedRegID: return .orange case .unknown: return .secondary } } var label: String { self == .unknown ? "Unknown" : rawValue } } extension DeviceState { var color: Color { switch self { case .online: return .green case .offline: return .gray case .unattached: return .orange case .preProvisioned: return .blue case .unknown: return .secondary } } var label: String { self == .unknown ? "Unknown" : rawValue } } extension AlarmSeverity { var color: Color { switch self { case .emergency, .alert, .critical: return .red case .error: return .orange case .warning: return .yellow case .notice, .info: return .blue case .debug: return .gray case .unknown: return .secondary } } var label: String { self == .unknown ? "unknown" : rawValue } } struct SeverityBadge: View { let severity: AlarmSeverity var body: some View { StateBadge(text: severity.label, color: severity.color) } } // MARK: - Count tile (dashboard) struct CountTile: View { let title: String let value: Int var systemImage: String? = nil var tint: Color = .accentColor var body: some View { VStack(alignment: .leading, spacing: 6) { HStack(spacing: 6) { if let systemImage { Image(systemName: systemImage).foregroundStyle(tint) } Text(title).font(.caption).foregroundStyle(.secondary) } Text("\(value)").font(.system(.title, design: .rounded).weight(.semibold)) } .frame(maxWidth: .infinity, alignment: .leading) .padding() .background(Color(.secondarySystemBackground)) .clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous)) } } // MARK: - Loading / error struct LoadingView: View { var label: String = "Loading…" var body: some View { VStack(spacing: 12) { ProgressView() Text(label).font(.subheadline).foregroundStyle(.secondary) } .frame(maxWidth: .infinity, maxHeight: .infinity) } } struct ErrorStateView: View { let message: String var retry: (() -> Void)? = nil var body: some View { ContentUnavailableView { Label("Something went wrong", systemImage: "exclamationmark.triangle") } description: { Text(message) } actions: { if let retry { Button("Retry", action: retry).buttonStyle(.borderedProminent) } } } }