import RastrilloNative import SwiftUI /// A compact save status for a toolbar or title bar. Silent when saved, but /// the accessibility element stays present while silent, so the first /// failure is announced from a region that already exists (estilo /// savestatus). Entering offline, needs-sign-in and failed is announced; a /// saving flicker never is. public struct NativeSyncStatusView: View { private let status: SyncStatus private let strings: NativeSyncStrings public init(status: SyncStatus, strings: NativeSyncStrings = .kit) { self.status = status self.strings = strings } public var body: some View { let text = strings.text(for: status) ?? "" Text(text) .font(.callout) .fontWeight(status.saveState == .failed ? .semibold : .regular) .foregroundStyle(status.saveState == .failed ? AnyShapeStyle(.red) : AnyShapeStyle(.secondary)) .lineLimit(2) .frame(minWidth: 8) .accessibilityElement(children: .ignore) .accessibilityLabel(text) .accessibilityAddTraits(.updatesFrequently) .onChange(of: status) { old, new in guard new.isAnnounced, !Self.sameKind(old, new), let text = strings.text(for: new) else { return } AccessibilityNotification.Announcement(text).post() } } /// A count changing inside the same state is not news. static func sameKind(_ a: SyncStatus, _ b: SyncStatus) -> Bool { switch (a, b) { case (.offline, .offline), (.needsSignIn, .needsSignIn), (.retrying, .retrying): return true case (.failed(_, let x), .failed(_, let y)): return x == y default: return a == b } } }