Skip to content

Commit

Permalink
feat(ios): bus departures
Browse files Browse the repository at this point in the history
  • Loading branch information
krystxf committed Nov 15, 2024
1 parent cfada71 commit f6cb8b1
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,11 @@ struct PlatformDetailView: View {

func getDepartures() {
NetworkManager.shared
.getDepartures(stopIds: [], platformIds: [platformId]) { result in
.getDepartures(
includeVehicle: .METRO,
excludeMetro: false,
stopIds: [], platformIds: [platformId]
) { result in
DispatchQueue.main.async {
switch result {
case let .success(departures):
Expand Down
117 changes: 36 additions & 81 deletions apps/mobile/metro-now/metro-now/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,118 +6,73 @@ import SwiftUI

struct ContentView: View {
@StateObject private var locationManager = LocationManager()
@State var metroStops: [ApiStop]? = nil
@State var allStops: [ApiStop]? = nil
@State var departures: [ApiDeparture]? = nil
private let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()
@State var metroStops: [ApiStop]? = nil

var body: some View {
NavigationStack {
List {
if let location = locationManager.location,
let metroStops,
let closestMetroStop = findClosestStop(to: location, stops: metroStops)
{
Section(header: Text("Metro")) {
ClosestMetroStopSectionView(
closestStop: closestMetroStop,
departures: departures
)
.navigationTitle(closestMetroStop.name)
if let location = locationManager.location {
NavigationStack {
if let metroStops {
List {
Section(header: Text("Metro")) {
MetroDeparturesView(
location: location,
stops: metroStops
)
}

if let allStops {
NonMetroDeparturesView(
location: location,
stops: allStops
)
}
}
.navigationTitle(
findClosestStop(
to: location,
stops: metroStops
)?.name ??
"Loading..."
)
} else {
ProgressView()
}
}
}
.onAppear {
getAllMetroStops()
getAllStops()
}
.onReceive(timer) { _ in
getAllMetroStops()
getAllStops()
getStopDepartures()
}
}

func findClosestStop(to location: CLLocation, stops: [ApiStop]) -> ApiStop? {
var closestStop: ApiStop?
var closestDistance: CLLocationDistance?

for stop in stops {
let stopLocation = CLLocation(latitude: stop.avgLatitude, longitude: stop.avgLongitude)

let distance = location.distance(from: stopLocation)

guard closestDistance != nil else {
closestStop = stop
closestDistance = distance
continue
}

if distance < closestDistance! {
closestStop = stop
closestDistance = distance
.onAppear {
getMetroStops()
getAllStops()
}
} else {
NoLocationView()
}

return closestStop
}

func getAllMetroStops() {
NetworkManager.shared.getMetroStops { result in
func getAllStops() {
NetworkManager.shared.getStops(metroOnly: false) { result in
DispatchQueue.main.async {
switch result {
case let .success(stops):

metroStops = stops

allStops = stops
case let .failure(error):
print(error.localizedDescription)
}
}
}
}

func getAllStops() {
NetworkManager.shared.getAllStops { result in
func getMetroStops() {
NetworkManager.shared.getStops(metroOnly: true) { result in
DispatchQueue.main.async {
switch result {
case let .success(stops):

allStops = stops

metroStops = stops
case let .failure(error):
print(error.localizedDescription)
}
}
}
}

func getStopDepartures() {
guard
let location = locationManager.location,
let metroStops,
let closestStop = findClosestStop(to: location, stops: metroStops)
else {
return
}

NetworkManager.shared
.getDepartures(stopIds: [closestStop.id], platformIds: []) { result in
DispatchQueue.main.async {
switch result {
case let .success(departures):

self.departures = departures

case let .failure(error):
print(error.localizedDescription)
}
}
}
}
}

#Preview {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,48 @@
import SwiftUI

struct ClosestStopPageListItemPlaceholderView: View {
let routeLabel: String
let routeLabel: String?
let routeLabelBackground: Color

var body: some View {
ClosestStopPageListItemView(
routeLabel: routeLabel,
routeLabelBackground: routeLabelBackground,
headsign: "Loading...",
departure: .now + 10 * 60,
nextHeadsign: "Loading..",
nextDeparture: .now + 15 * 60
)
.redacted(reason: .placeholder)
HStack(
alignment: .top,
spacing: 8
) {
if let routeLabel {
RouteNameIconView(
label: routeLabel,
background: routeLabelBackground
)
} else {
RouteNameIconView(
label: "X",
background: routeLabelBackground
)
.redacted(reason: .placeholder)
}

VStack(alignment: .trailing, spacing: 4) {
HStack {
Text("Loading...")
Spacer()
CountdownView(targetDate: .now + 10 * 60)
}

HStack {
Spacer()
CountdownView(
targetDate: .now + 15 * 60
) {
"Also in \($0)"
}
}
.foregroundStyle(.secondary)
.font(.footnote)
}
.fontWeight(.semibold)
.redacted(reason: .placeholder)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// metro-now
// https://github.com/krystxf/metro-now

import CoreLocation
import SwiftUI

struct ClosestMetroStopSectionView: View {
Expand Down Expand Up @@ -56,3 +57,62 @@ struct PlatformDeparturesView: View {
}
}
}

struct MetroDeparturesView: View {
let location: CLLocation
let stops: [ApiStop]

init(
location: CLLocation,
stops: [ApiStop]

) {
self.location = location
self.stops = stops
}

@State var departures: [ApiDeparture]? = nil
private let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()

var body: some View {
if let closestMetroStop = findClosestStop(to: location, stops: stops) {
ClosestMetroStopSectionView(
closestStop: closestMetroStop,
departures: departures
)
} else {
ProgressView()
}

EmptyView()
.onAppear {
getStopDepartures()
}
.onReceive(timer) { _ in
getStopDepartures()
}
}

func getStopDepartures() {
guard let closestStop = findClosestStop(to: location, stops: stops) else {
return
}

NetworkManager.shared
.getDepartures(
includeVehicle: .METRO,
excludeMetro: false,
stopIds: [closestStop.id],
platformIds: []
) { result in
DispatchQueue.main.async {
switch result {
case let .success(departures):
self.departures = departures
case let .failure(error):
print(error.localizedDescription)
}
}
}
}
}
Loading

0 comments on commit f6cb8b1

Please sign in to comment.