watch: polish refresh status and compact live activity

This commit is contained in:
FuelBoard Contributor
2026-08-31 10:40:16 +01:00
parent 767080a983
commit 8bbcb0b4dc
2 changed files with 27 additions and 9 deletions
+16 -3
View File
@@ -112,6 +112,7 @@ private enum WatchRefreshState {
case stale(lastUpdated: String)
case checking
case requested(lastUpdated: String)
case checkedNoNewData(lastUpdated: String)
case needsPhone
case noData
@@ -120,7 +121,8 @@ private enum WatchRefreshState {
case .idle(let lastUpdated): return "Updated \(lastUpdated)"
case .stale(let lastUpdated): return "Cache from \(lastUpdated)"
case .checking: return "Checking…"
case .requested(let lastUpdated): return "Requested · \(lastUpdated)"
case .requested(let lastUpdated): return "Updated · \(lastUpdated)"
case .checkedNoNewData(let lastUpdated): return "No newer data · \(lastUpdated)"
case .needsPhone: return "Refresh on iPhone"
case .noData: return "No cached prices yet"
}
@@ -132,6 +134,7 @@ private enum WatchRefreshState {
case .stale: return .yellow
case .checking: return .yellow
case .requested: return .green
case .checkedNoNewData: return .secondary
case .needsPhone: return .orange
case .noData: return .secondary
}
@@ -143,6 +146,7 @@ private enum WatchRefreshState {
case .stale: return "exclamationmark.circle"
case .checking: return "arrow.triangle.2.circlepath"
case .requested: return "checkmark.circle"
case .checkedNoNewData: return "clock.badge.exclamationmark"
case .needsPhone: return "iphone"
case .noData: return "tray"
}
@@ -551,6 +555,7 @@ struct ContentView: View {
private func runCheckNow() {
refreshState = .checking
let previousLastRefresh = WatchFuelCache.loadLastRefresh()
let requestDate = Date()
WatchFuelCache.requestRefresh(requestDate)
WatchSyncManager.shared.requestRefresh(at: requestDate)
@@ -560,8 +565,16 @@ struct ContentView: View {
if WatchFuelCache.wasRefreshHandled(since: requestDate) {
await MainActor.run {
reloadFromCache()
let label = WatchFuelCache.loadLastRefresh().map(relativeRefreshText(for:)) ?? "just now"
refreshState = .requested(lastUpdated: label)
let currentLastRefresh = WatchFuelCache.loadLastRefresh()
if let currentLastRefresh,
currentLastRefresh >= requestDate,
currentLastRefresh > (previousLastRefresh ?? .distantPast) {
refreshState = .requested(lastUpdated: relativeRefreshText(for: currentLastRefresh))
} else if let currentLastRefresh {
refreshState = .checkedNoNewData(lastUpdated: relativeRefreshText(for: currentLastRefresh))
} else {
refreshState = .noData
}
}
return
}
@@ -147,9 +147,9 @@ private struct FuelBoardLiveActivityView: View {
}
/// Minimal strip for small space (CarPlay small / Watch smart stack):
/// fuel type + bold price on one line, station · distance below.
/// Deliberately no app name and no "Tap for directions" CarPlay is
/// display-only, and the user's asks here are just fuel + price + distance.
/// fuel type + distance + bold price on one line, station name below.
/// Deliberately no app name and no full address the watch-sized slot is
/// too tight, so the second line is reserved for the station name only.
private var compactBody: some View {
VStack(alignment: .leading, spacing: 3) {
HStack(spacing: 5) {
@@ -157,16 +157,21 @@ private struct FuelBoardLiveActivityView: View {
.font(.caption.bold())
.lineLimit(1)
Spacer(minLength: 4)
Text(context.state.distanceText)
.font(.caption2)
.foregroundStyle(.secondary)
.lineLimit(1)
Spacer(minLength: 4)
FuelStore.priceTextAttributed(context.state.pricePence,
style: context.state.priceDisplayStyle,
size: 15, weight: .bold)
.lineLimit(1)
}
Text("\(context.state.stationName) · \(context.state.distanceText)")
.font(.system(size: 9))
Text(context.state.stationName)
.font(.system(size: 10, weight: .medium))
.foregroundStyle(.secondary)
.lineLimit(1)
.minimumScaleFactor(0.7)
.minimumScaleFactor(0.75)
.truncationMode(.tail)
}
.padding(8)