Settings About: data source section (connection, station count, GOV.UK update time)

- Relay envelope now carries source (api|csv), stations_count, and
  data_updated (freshest price_last_updated the GOV.UK server reports,
  independent of relay sync time).
- App decodes the new envelope metadata (RelayMeta), persists it after
  each full fetch, and shows it in Settings → About → Data source:
  Connection (API/CSV), Stations count, Data updated (local-formatted).
- Older relays without the fields decode cleanly (nil meta → em-dash).
- 2 new tests for meta decode + absent-meta tolerance; 37/37 pass.
This commit is contained in:
FuelBoard Contributor
2026-08-12 16:23:41 +01:00
parent a5a95cbb03
commit fccd0c07ef
5 changed files with 162 additions and 1 deletions
+5
View File
@@ -293,6 +293,11 @@ struct ContentView: View {
stations = fetched
FuelStore.saveStations(fetched)
FuelStore.saveLastRefresh()
// Persist relay envelope metadata (source, station count, GOV.UK
// dataset update time) for the Settings About section.
if let meta = RelayFuelProvider.latestMeta {
FuelStore.saveRelayMeta(meta)
}
// Keep the keychain favourites fresh with the new prices the
// widget's Favourites mode reads them from keychain (the only
// channel shared on SideStore free), so stale star-time snapshots
+61
View File
@@ -121,6 +121,33 @@ struct SettingsView: View {
Text("A small tip helps keep the data relay and app development going. Thank you!")
}
Section {
HStack {
Text("Connection")
Spacer()
Text(connectionText)
.foregroundStyle(.secondary)
}
HStack {
Text("Stations")
Spacer()
Text(stationCountText)
.foregroundStyle(.secondary)
.monospacedDigit()
}
HStack {
Text("Data updated")
Spacer()
Text(dataUpdatedText)
.foregroundStyle(.secondary)
.monospacedDigit()
}
} header: {
Text("Data source")
} footer: {
Text("Connection shows whether prices come from the official Fuel Finder API or the CSV mirror. Data updated is the latest price change reported by the GOV.UK server itself.")
}
Section {
HStack {
Text("Version")
@@ -252,6 +279,40 @@ struct SettingsView: View {
return "\(version) (\(build))"
}
/// "API" when the relay is serving the official Fuel Finder API, "CSV"
/// when it fell back to the public mirror, "" when unknown/never fetched.
private var connectionText: String {
switch FuelStore.loadRelaySource()?.lowercased() {
case "api": return "API"
case "csv": return "CSV"
default: return ""
}
}
private var stationCountText: String {
guard let count = FuelStore.loadStationCount() else { return "" }
return count.formatted()
}
/// GOV.UK server's own dataset update timestamp (ISO 8601 from the API,
/// e.g. 2026-08-12T10:23:00.000Z). Shown as a local date/time it is the
/// data's own freshness, not the relay's sync time.
private var dataUpdatedText: String {
guard let raw = FuelStore.loadDataUpdated(), !raw.isEmpty else { return "" }
let iso = ISO8601DateFormatter()
iso.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
if let date = iso.date(from: raw) {
return date.formatted(date: .abbreviated, time: .shortened)
}
// Some sources send "YYYY-MM-DDTHH:MM:SS" without fractional seconds
// or timezone try the plain form before showing the raw string.
iso.formatOptions = [.withInternetDateTime]
if let date = iso.date(from: raw) {
return date.formatted(date: .abbreviated, time: .shortened)
}
return raw
}
/// Hidden debug-mode toggle: five taps on the Version row flips the flag.
/// Nothing in the UI advertises this the Debug section simply appears or
/// disappears. Deliberately NOT a visible switch so end users never see it.