← Back to index

WatchScheduleView

Spots Watch App
CodeWhat It DoesHow It Does It
▶ IMPORTS
import SwiftUI import CoreLocationFramework importsImports SwiftUI, CoreLocation.
▶ SUB-VIEWS
private struct SmallLineBadge: View { let line: String var body: some View { ZStack { Circle().fill(watchLineColor(for: line)).frame(width: 16, height: 16) Text(line).font(.system(size: 8, weight: .bold)).foregroundColor(watchLineTextColor(for: line)) } } }`SmallLineBadge` structDefines the `SmallLineBadge` struct. Conforms to View.
private struct ArrivalBadge: View { let arrival: WatchArrival var body: some View { VStack(spacing: 2) { ZStack { Circle().fill(watchLineColor(for: arrival.route)).frame(width: 34, height: 34) Text(arrival.route) .font(.system(size: 16, weight: .bold)) .foregroundColor(watchLineTextColor(for: arrival.route)) } Text(arrival.label) .font(.system(size: 12, weight: .semibold)) .foregroundColor(.white) } } }`ArrivalBadge` structDefines the `ArrivalBadge` struct. Conforms to View.
private struct DirectionCard: View { let direction: WatchDirectionArrivals var body: some View { VStack(alignment: .leading, spacing: 6) { Text(direction.headsign) .font(.system(size: 12, weight: .bold)) .foregroundColor(.white) .lineLimit(1) HStack(spacing: 8) { ForEach(direction.arrivals.prefix(4)) { a in ArrivalBadge(arrival: a) } Spacer(minLength: 0) } } .padding(.horizontal, 10) .padding(.vertical, 8) .background(RoundedRectangle(cornerRadius: 10).fill(Color.white.opacity(0.08))) } }`DirectionCard` structDefines the `DirectionCard` struct. Conforms to View.
private struct StationBlock: View { let station: WatchNearbyStation var body: some View { VStack(alignment: .leading, spacing: 6) { HStack(spacing: 4) { Text(station.name) .font(.system(size: 15, weight: .bold)) .foregroundColor(.white) ForEach(station.lines, id: \.self) { SmallLineBadge(line: $0) } } ForEach(station.directions) { dir in DirectionCard(direction: dir) } } } }`StationBlock` structDefines the `StationBlock` struct. Conforms to View.
▶ MAIN VIEW
struct WatchScheduleView: View { @EnvironmentObject var store: WatchEntryStore @StateObject private var service = WatchArrivalsService.shared var body: some View { Group { if service.isLoading && service.stations.isEmpty { VStack(spacing: 8) { ProgressView() Text("Finding nearby trains…") .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.stations.isEmpty { VStack(spacing: 6) { Image(systemName: "location.slash").foregroundColor(.secondary) Text("No nearby stations found") .font(.caption2).foregroundColor(.secondary) .multilineTextAlignment(.center) } } else { ScrollView { VStack(alignment: .leading, spacing: 14) { ForEach(service.stations) { station in StationBlock(station: station) } } .padding(.horizontal, 4) .padding(.vertical, 6) } } } .navigationTitle("Schedule") .navigationBarTitleDisplayMode(.inline) .task { await fetchIfLocation() } } 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) } }`WatchScheduleView` structDefines the `WatchScheduleView` struct. Conforms to View.
#Preview { NavigationStack { WatchScheduleView() } .environmentObject(WatchEntryStore()) }Code blockSee source code for full implementation.