← Back to index

WatchBusView

Spots Watch App
CodeWhat It DoesHow It Does It
▶ IMPORTS
import SwiftUI import CoreLocationFramework importsImports SwiftUI, CoreLocation.
▶ SUB-VIEWS
private struct BusRouteBadge: View { let route: String var body: some View { Text(route) .font(.system(size: 9, weight: .bold)) .foregroundColor(.white) .padding(.horizontal, 5) .padding(.vertical, 3) .background(watchBusRouteColor(for: route), in: RoundedRectangle(cornerRadius: 5)) } }`BusRouteBadge` structDefines the `BusRouteBadge` struct. Conforms to View.
private struct BusArrivalRow: View { let arrival: WatchBusArrival var body: some View { HStack(spacing: 6) { BusRouteBadge(route: arrival.route) Text(arrival.headsign) .font(.system(size: 11)) .foregroundColor(.white.opacity(0.85)) .lineLimit(1) Spacer(minLength: 2) Text(arrival.label) .font(.system(size: 13, weight: .semibold)) .foregroundColor(.white) .frame(minWidth: 28, alignment: .trailing) Text("min") .font(.system(size: 10)) .foregroundColor(.white.opacity(0.6)) } } }`BusArrivalRow` structDefines the `BusArrivalRow` struct. Conforms to View.
private struct BusStopBlock: View { let stop: WatchNearbyBusStop var body: some View { VStack(alignment: .leading, spacing: 6) { Text(stop.name) .font(.system(size: 13, weight: .bold)) .foregroundColor(.white) .lineLimit(2) .fixedSize(horizontal: false, vertical: true) VStack(spacing: 4) { ForEach(stop.arrivals.prefix(4)) { arrival in BusArrivalRow(arrival: arrival) } } } .padding(.horizontal, 10) .padding(.vertical, 8) .background(RoundedRectangle(cornerRadius: 10).fill(Color.white.opacity(0.08))) } }`BusStopBlock` structDefines the `BusStopBlock` struct. Conforms to View.
▶ MAIN VIEW
struct WatchBusView: View { @EnvironmentObject var store: WatchEntryStore @StateObject private var service = WatchBusArrivalsService.shared var body: some View { Group { if service.isLoading && service.stops.isEmpty { VStack(spacing: 8) { ProgressView() Text("Finding nearby buses…") .font(.caption2) .foregroundColor(.secondary) .multilineTextAlignment(.center) } } else if let err = service.errorMessage { VStack(spacing: 6) { Image(systemName: "exclamationmark.triangle").foregroundColor(.orange) Text(err).font(.caption2).foregroundColor(.secondary) .multilineTextAlignment(.center) Button("Retry") { Task { await fetchIfLocation() } }.font(.caption2) } } else if service.stops.isEmpty { VStack(spacing: 6) { Image(systemName: "location.slash").foregroundColor(.secondary) Text("No nearby bus stops found") .font(.caption2).foregroundColor(.secondary) .multilineTextAlignment(.center) } } else { ScrollView { VStack(alignment: .leading, spacing: 12) { ForEach(service.stops) { stop in BusStopBlock(stop: stop) } } .padding(.horizontal, 4) .padding(.vertical, 6) } } } .navigationTitle("Buses") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button { Task { await fetchIfLocation() } } label: { Image(systemName: "arrow.clockwise") .font(.system(size: 14, weight: .medium)) } } } .task { while !Task.isCancelled { let start = Date() await fetchIfLocation() let elapsed = Date().timeIntervalSince(start) let remaining = max(0, 30 - elapsed) try? await Task.sleep(for: .seconds(remaining)) } } } private func fetchIfLocation() async { store.startLocationIfNeeded() var waited = 0 while store.userLocation == nil && waited < 10 { try? await Task.sleep(nanoseconds: 500_000_000) waited += 1 } let loc = store.userLocation ?? CLLocation(latitude: 40.7128, longitude: -74.0060) await service.refresh(near: loc) } }`WatchBusView` structDefines the `WatchBusView` struct. Conforms to View.
#Preview { NavigationStack { WatchBusView() } .environmentObject(WatchEntryStore()) }Code blockSee source code for full implementation.