Let the switcher icon say how the account is doing

Only the non-tvOS toolbar menu computed a health-aware glyph; the
settings row and the tvOS button hardcoded the plain outline, so on
tvOS the icon never changed no matter what broke (TV7). One shared
icon now serves all three: outline for Local, filled for a signed-in
account, and an orange exclamation badge when the context needs a
person — credentials rejected, instance disabled, or unreachable.
Transient states like checking stay unbadged so launch doesn't flash
a false alarm.
This commit is contained in:
Arkadiusz Fal
2026-09-10 22:40:44 +02:00
parent 026b5ffc90
commit b69fb7fb1f
2 changed files with 136 additions and 18 deletions

View File

@@ -322,6 +322,45 @@ struct AccountStatusBadgeTests {
}
}
// MARK: - Switcher glyph
@Suite("Data context switcher glyph")
struct DataContextSwitcherGlyphTests {
private let account = DataContext.account(UUID())
@Test("Local data and a signed-in account read differently")
func healthyStatesAreToldApart() {
#expect(DataContextSwitcherGlyph.systemImage(for: .local, validity: .valid) == "person.crop.circle")
#expect(DataContextSwitcherGlyph.systemImage(for: account, validity: .valid) == "person.crop.circle.fill")
#expect(DataContextSwitcherGlyph.tint(for: account, validity: .valid) == nil)
}
@Test("A state the user has to act on is badged, in the settings entry's colour")
func actionableStatesAreBadged() {
let actionable: [DataContextUnavailability] = [.instanceDisabled, .credentialRejected, .unreachable]
for reason in actionable {
let validity = DataContextValidity.temporarilyUnavailable(reason)
#expect(
DataContextSwitcherGlyph.systemImage(for: account, validity: validity)
== "person.crop.circle.badge.exclamationmark"
)
#expect(DataContextSwitcherGlyph.tint(for: account, validity: validity) == .orange)
}
}
@Test("A context that is still resolving is not a fault")
func pendingStatesAreNotBadged() {
let pending: [DataContextUnavailability] = [.checking, .instancePending, .credentialMissing]
for reason in pending {
let validity = DataContextValidity.temporarilyUnavailable(reason)
#expect(DataContextSwitcherGlyph.systemImage(for: account, validity: validity) == "person.crop.circle.fill")
#expect(DataContextSwitcherGlyph.tint(for: account, validity: validity) == nil)
}
}
}
// MARK: - Switcher labels
@Suite("Data context switcher labels")