// // SyncStatusBanner.swift // Workouts // // Copyright 2026 Rouslan Zenetl. All Rights Reserved. // import SwiftUI /// Surfaces the write queue's banner tiers at the bottom of the main screen. /// Tier 0 (fresh writes, silent retries) shows nothing; tier 1 is a calm /// "changes pending" capsule that clears itself on success; tier 2 is a /// prominent fault that opens Diagnostics. struct SyncStatusBanner: View { @Environment(SyncEngine.self) private var sync @State private var showingDiagnostics = false var body: some View { Group { switch sync.writeQueueState { case .idle, .pending: EmptyView() case .retrying: HStack(spacing: 8) { ProgressView() .controlSize(.small) Text("Changes pending — retrying…") .font(.footnote) .foregroundStyle(.secondary) } .padding(.horizontal, 14) .padding(.vertical, 8) .background(.regularMaterial, in: Capsule()) .padding(.bottom, 6) case .fault(let message): Button { showingDiagnostics = true } label: { HStack(alignment: .firstTextBaseline, spacing: 10) { Image(systemName: "exclamationmark.icloud.fill") .foregroundStyle(.white) VStack(alignment: .leading, spacing: 2) { Text(message) .font(.footnote.weight(.semibold)) .foregroundStyle(.white) .multilineTextAlignment(.leading) Text("Your changes are safe on this iPhone. Tap for diagnostics.") .font(.caption2) .foregroundStyle(.white.opacity(0.85)) } } .padding(.horizontal, 14) .padding(.vertical, 10) .background(.red.gradient, in: RoundedRectangle(cornerRadius: 14)) } .buttonStyle(.plain) .padding(.horizontal, 16) .padding(.bottom, 6) .sheet(isPresented: $showingDiagnostics) { NavigationStack { DiagnosticsView() } } } } .animation(.default, value: sync.writeQueueState) } }