From 0f1b93c074ea21bab70c2e2b0a628de618a7630c Mon Sep 17 00:00:00 2001 From: Krystof Date: Sat, 16 Nov 2024 20:29:30 +0100 Subject: [PATCH] refactor(app): file structure --- .../components/countdown-view/countdown.swift | 51 +++++++++++ .../countdown-view/countdown.utils.swift | 25 ++++++ .../common/components/countdown.view.swift | 54 ----------- .../get-color-by-route-name.utils.swift | 52 +++++++++++ .../route-name.view.swift | 32 +++---- .../route-label-view/route-type.enum.swift | 48 ++++++++++ .../{api-const.swift => endpoint.const.swift} | 1 - .../metro-now/common/types/metro-line.swift | 8 -- .../utils/get-color-by-route-name.swift | 77 ---------------- .../pages/platform/platform-detail.view.swift | 6 +- .../pages/stop/stop-detail.view.swift | 4 +- .../metro-now.xcodeproj/project.pbxproj | 11 +-- .../metro-now/metro-now/ContentView.swift | 46 +--------- ...departure-list-item-placeholder.view.swift | 16 ++-- .../closest-stop-page-view-model.swift} | 3 +- .../closest-stop/closest-stop-page.view.swift | 48 ++++++++++ .../{metro => }/metro-departures.view.swift | 27 +----- .../non-metro/non-metro-departures.view.swift | 90 ------------------- .../closest-stop/other-departures.view.swift | 72 +++++++++++++++ 19 files changed, 338 insertions(+), 333 deletions(-) create mode 100644 apps/mobile/metro-now/common/components/countdown-view/countdown.swift create mode 100644 apps/mobile/metro-now/common/components/countdown-view/countdown.utils.swift delete mode 100644 apps/mobile/metro-now/common/components/countdown.view.swift create mode 100644 apps/mobile/metro-now/common/components/route-label-view/get-color-by-route-name.utils.swift rename apps/mobile/metro-now/common/components/{ => route-label-view}/route-name.view.swift (67%) create mode 100644 apps/mobile/metro-now/common/components/route-label-view/route-type.enum.swift rename apps/mobile/metro-now/common/const/{api-const.swift => endpoint.const.swift} (67%) delete mode 100644 apps/mobile/metro-now/common/types/metro-line.swift delete mode 100644 apps/mobile/metro-now/common/utils/get-color-by-route-name.swift rename apps/mobile/metro-now/metro-now/{departure-view-model.swift => pages/closest-stop/closest-stop-page-view-model.swift} (97%) create mode 100644 apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page.view.swift rename apps/mobile/metro-now/metro-now/pages/closest-stop/{metro => }/metro-departures.view.swift (61%) delete mode 100644 apps/mobile/metro-now/metro-now/pages/closest-stop/non-metro/non-metro-departures.view.swift create mode 100644 apps/mobile/metro-now/metro-now/pages/closest-stop/other-departures.view.swift diff --git a/apps/mobile/metro-now/common/components/countdown-view/countdown.swift b/apps/mobile/metro-now/common/components/countdown-view/countdown.swift new file mode 100644 index 00000000..feded454 --- /dev/null +++ b/apps/mobile/metro-now/common/components/countdown-view/countdown.swift @@ -0,0 +1,51 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import SwiftUI + +struct CountdownView: View { + typealias CustomFormatFunctionType = (_ formattedTime: String) -> String + + let targetDate: Date + let customFunction: CustomFormatFunctionType + @State private var timeRemaining: TimeInterval = 0 + private let timer = Timer.publish( + every: 0.1, + on: .main, + in: .common + ) + .autoconnect() + + init(targetDate: Date, customFunction: CustomFormatFunctionType? = nil) { + self.targetDate = targetDate + self.customFunction = customFunction ?? { $0 } + updateRemainingTime() + } + + var body: some View { + Text( + customFunction( + getRemainingTime( + timeRemaining + ) + ) + ) + .onReceive(timer) { _ in + updateRemainingTime() + } + } + + private func updateRemainingTime() { + timeRemaining = targetDate.timeIntervalSinceNow + } +} + +#Preview { + VStack { + CountdownView(targetDate: .now) + CountdownView(targetDate: .now + 60) + CountdownView(targetDate: .now + 10 * 60) + CountdownView(targetDate: .now + 2 * 60 * 60) + CountdownView(targetDate: .now + 10 * 60) { "Also in \($0)" } + } +} diff --git a/apps/mobile/metro-now/common/components/countdown-view/countdown.utils.swift b/apps/mobile/metro-now/common/components/countdown-view/countdown.utils.swift new file mode 100644 index 00000000..17563e1e --- /dev/null +++ b/apps/mobile/metro-now/common/components/countdown-view/countdown.utils.swift @@ -0,0 +1,25 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import Foundation + +func getRemainingTime(_ remainingSeconds: TimeInterval) -> String { + let remainingSecondsAbs = abs(remainingSeconds) + + let hours = Int(remainingSecondsAbs) / 3600 + let minutes = Int(remainingSecondsAbs) % 3600 / 60 + let seconds = Int(remainingSecondsAbs) % 60 + let isNegative = Bool(remainingSeconds < 0) + + var res = isNegative ? "-" : "" + + if hours > 0 { + res += "\(hours)h \(minutes)m" + } else if minutes > 0 { + res += "\(minutes)m \(seconds)s" + } else { + res += "\(seconds)s" + } + + return res +} diff --git a/apps/mobile/metro-now/common/components/countdown.view.swift b/apps/mobile/metro-now/common/components/countdown.view.swift deleted file mode 100644 index a631e22e..00000000 --- a/apps/mobile/metro-now/common/components/countdown.view.swift +++ /dev/null @@ -1,54 +0,0 @@ -// metro-now -// https://github.com/krystxf/metro-now - -import SwiftUI - -struct CountdownView: View { - typealias CustomFormatFunctionType = (_ formattedTime: String) -> String - - let targetDate: Date - let customFunction: CustomFormatFunctionType - - init(targetDate: Date, customFunction: CustomFormatFunctionType? = nil) { - self.targetDate = targetDate - self.customFunction = customFunction ?? { $0 } - } - - @State private var timeRemaining: TimeInterval = 0 - - private let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect() - - var body: some View { - Text(formattedTime) - .onAppear { - updateRemainingTime() - } - .onReceive(timer) { _ in - updateRemainingTime() - } - } - - private var formattedTime: String { - let remainingTime = abs(timeRemaining) - let hours = Int(remainingTime) / 3600 - let minutes = Int(remainingTime) % 3600 / 60 - let seconds = Int(remainingTime) % 60 - let isNegative = Bool(timeRemaining < 0) - - var res = isNegative ? "-" : "" - - if hours > 0 { - res += "\(hours)h \(minutes)m" - } else if minutes > 0 { - res += "\(minutes)m \(seconds)s" - } else { - res += "\(seconds)s" - } - - return customFunction(res) - } - - private func updateRemainingTime() { - timeRemaining = targetDate.timeIntervalSinceNow - } -} diff --git a/apps/mobile/metro-now/common/components/route-label-view/get-color-by-route-name.utils.swift b/apps/mobile/metro-now/common/components/route-label-view/get-color-by-route-name.utils.swift new file mode 100644 index 00000000..42e4696f --- /dev/null +++ b/apps/mobile/metro-now/common/components/route-label-view/get-color-by-route-name.utils.swift @@ -0,0 +1,52 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import SwiftUI + +func getRouteType(_ routeName: String?) -> RouteType { + guard let routeName else { + return RouteType.fallback + } + + // metro + if let metroLine = MetroLine(rawValue: routeName.uppercased()) { + return RouteType.metro(metroLine) + } + // train + else if routeName.hasPrefix("S") || routeName.hasPrefix("R") { + return RouteType.train + } + // ferry + else if routeName.hasPrefix("P") { + return RouteType.ferry + } + // funicular + else if routeName.hasPrefix("LD") { + return RouteType.funicular + } + // bus or tram + else if let routeNumber = Int(routeName) { + // tram + if routeNumber < 90 { + return RouteType.tram + } + // night tram + else if routeNumber < 100 { + return RouteType.night + } + // bus + else if routeNumber < 900 { + return RouteType.bus + } + // night bus + else if routeNumber < 1000 { + return RouteType.night + } + // fallback + else { + return RouteType.bus + } + } + + return RouteType.fallback +} diff --git a/apps/mobile/metro-now/common/components/route-name.view.swift b/apps/mobile/metro-now/common/components/route-label-view/route-name.view.swift similarity index 67% rename from apps/mobile/metro-now/common/components/route-name.view.swift rename to apps/mobile/metro-now/common/components/route-label-view/route-name.view.swift index 79e82b42..cf78d7f7 100644 --- a/apps/mobile/metro-now/common/components/route-name.view.swift +++ b/apps/mobile/metro-now/common/components/route-label-view/route-name.view.swift @@ -22,85 +22,85 @@ struct RouteNameIconView: View { HStack { RouteNameIconView( label: "a", - background: getColorByRouteName("a") + background: getRouteType("a").color ) RouteNameIconView( label: "b", - background: getColorByRouteName("b") + background: getRouteType("b").color ) RouteNameIconView( label: "c", - background: getColorByRouteName("c") + background: getRouteType("c").color ) } HStack { RouteNameIconView( label: "2", - background: getColorByRouteName("28") + background: getRouteType("28").color ) RouteNameIconView( label: "23", - background: getColorByRouteName("28") + background: getRouteType("28").color ) RouteNameIconView( label: "28", - background: getColorByRouteName("28") + background: getRouteType("28").color ) RouteNameIconView( label: "99", - background: getColorByRouteName("99") + background: getRouteType("99").color ) } HStack { RouteNameIconView( label: "149", - background: getColorByRouteName("149") + background: getRouteType("149").color ) RouteNameIconView( label: "912", - background: getColorByRouteName("912") + background: getRouteType("912").color ) } HStack { RouteNameIconView( label: "P2", - background: getColorByRouteName("P2") + background: getRouteType("P2").color ) RouteNameIconView( label: "P4", - background: getColorByRouteName("P2") + background: getRouteType("P2").color ) RouteNameIconView( label: "P6", - background: getColorByRouteName("P2") + background: getRouteType("P2").color ) } HStack { RouteNameIconView( label: "S9", - background: getColorByRouteName("S49") + background: getRouteType("S49").color ) RouteNameIconView( label: "S88", - background: getColorByRouteName("S49") + background: getRouteType("S49").color ) RouteNameIconView( label: "R19", - background: getColorByRouteName("S49") + background: getRouteType("S49").color ) } HStack { RouteNameIconView( label: "LD", - background: getColorByRouteName("LD") + background: getRouteType("LD").color ) } } diff --git a/apps/mobile/metro-now/common/components/route-label-view/route-type.enum.swift b/apps/mobile/metro-now/common/components/route-label-view/route-type.enum.swift new file mode 100644 index 00000000..a5e8838c --- /dev/null +++ b/apps/mobile/metro-now/common/components/route-label-view/route-type.enum.swift @@ -0,0 +1,48 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import SwiftUI + +enum MetroLine: String { + case A + case B + case C + + var color: Color { + switch self { + case .A: .green + case .B: .yellow + case .C: .red + } + } +} + +let METRO_LINES = [ + MetroLine.A.rawValue, + MetroLine.B.rawValue, + MetroLine.C.rawValue, +] + +enum RouteType { + case fallback + case metro(MetroLine) + case night + case bus + case tram + case ferry + case funicular + case train + + var color: Color { + switch self { + case .fallback: .black + case let .metro(line): line.color + case .night: .black + case .bus: .blue + case .tram: .indigo + case .ferry: .cyan + case .funicular: .brown + case .train: .gray + } + } +} diff --git a/apps/mobile/metro-now/common/const/api-const.swift b/apps/mobile/metro-now/common/const/endpoint.const.swift similarity index 67% rename from apps/mobile/metro-now/common/const/api-const.swift rename to apps/mobile/metro-now/common/const/endpoint.const.swift index 170fb630..3b51616a 100644 --- a/apps/mobile/metro-now/common/const/api-const.swift +++ b/apps/mobile/metro-now/common/const/endpoint.const.swift @@ -2,4 +2,3 @@ // https://github.com/krystxf/metro-now let ENDPOINT: String = "https://api.metronow.dev" -// let ENDPOINT: String = "http://localhost:3001" diff --git a/apps/mobile/metro-now/common/types/metro-line.swift b/apps/mobile/metro-now/common/types/metro-line.swift deleted file mode 100644 index 9b9e6f6a..00000000 --- a/apps/mobile/metro-now/common/types/metro-line.swift +++ /dev/null @@ -1,8 +0,0 @@ -// metro-now -// https://github.com/krystxf/metro-now - -enum MetroLine: String { - case A - case B - case C -} diff --git a/apps/mobile/metro-now/common/utils/get-color-by-route-name.swift b/apps/mobile/metro-now/common/utils/get-color-by-route-name.swift deleted file mode 100644 index 01763bfd..00000000 --- a/apps/mobile/metro-now/common/utils/get-color-by-route-name.swift +++ /dev/null @@ -1,77 +0,0 @@ -// metro-now -// https://github.com/krystxf/metro-now - -import SwiftUI - -private let FALLBACK_COLOR: Color = .black - -private let METRO_A_COLOR: Color = .green -private let METRO_B_COLOR: Color = .yellow -private let METRO_C_COLOR: Color = .red - -private let NIGHT_COLOR: Color = .black -private let BUS_COLOR: Color = .blue -private let TRAM_COLOR: Color = .indigo -private let FERRY_COLOR: Color = .cyan -private let FUNICULAR_COLOR: Color = .brown -private let TRAIN_COLOR: Color = .gray - -func getColorByRouteName(_ metroLine: MetroLine?) -> Color { - switch metroLine { - case .A: METRO_A_COLOR - case .B: METRO_B_COLOR - case .C: METRO_C_COLOR - default: FALLBACK_COLOR - } -} - -func getColorByRouteName(_ routeNumber: Int?) -> Color { - guard let routeNumber else { - return FALLBACK_COLOR - } - - // tram - if routeNumber < 100 { - if routeNumber >= 90 { - return NIGHT_COLOR - } - - return TRAM_COLOR - } - - // bus - if routeNumber >= 900 { - return NIGHT_COLOR - } - - return BUS_COLOR -} - -func getColorByRouteName(_ routeName: String?) -> Color { - guard let routeName else { - return FALLBACK_COLOR - } - - if let routeNumber = Int(routeName) { - return getColorByRouteName(routeNumber) - } else if let metroLine = MetroLine(rawValue: routeName.uppercased()) { - return getColorByRouteName(metroLine) - } - - // train - if routeName.hasPrefix("S") || routeName.hasPrefix("R") { - return TRAIN_COLOR - } - - // ferry - if routeName.hasPrefix("P") { - return FERRY_COLOR - } - - // funicular - if routeName.hasPrefix("LD") { - return FUNICULAR_COLOR - } - - return FALLBACK_COLOR -} diff --git a/apps/mobile/metro-now/metro-now Watch App/pages/platform/platform-detail.view.swift b/apps/mobile/metro-now/metro-now Watch App/pages/platform/platform-detail.view.swift index 0e9dc0bc..f0433690 100644 --- a/apps/mobile/metro-now/metro-now Watch App/pages/platform/platform-detail.view.swift +++ b/apps/mobile/metro-now/metro-now Watch App/pages/platform/platform-detail.view.swift @@ -23,9 +23,9 @@ struct PlatformDetailView: View { var body: some View { TabView { if let departures, departures.count > 0 { - let backgroundColor = getColorByRouteName( - metroLine ?? MetroLine(rawValue: departures[0].route) - ) + let backgroundColor = getRouteType( + metroLine?.rawValue ?? departures.first?.route + ).color let hasNextDeparture = departures.count > 1 PlatformDetailNextDepartureView( diff --git a/apps/mobile/metro-now/metro-now Watch App/pages/stop/stop-detail.view.swift b/apps/mobile/metro-now/metro-now Watch App/pages/stop/stop-detail.view.swift index 2518af6b..a3d4ec2f 100644 --- a/apps/mobile/metro-now/metro-now Watch App/pages/stop/stop-detail.view.swift +++ b/apps/mobile/metro-now/metro-now Watch App/pages/stop/stop-detail.view.swift @@ -23,7 +23,9 @@ struct StopDeparturesView: View { var body: some View { NavigationSplitView { List(platforms, id: \.id, selection: $selectedPlatformId) { platform in - let itemColor = getColorByRouteName(platform.metroLine) + let itemColor = getRouteType( + platform.metroLine?.rawValue + ).color if let departures = platform.departures, departures.count > 0 { let hasNextDeparture = departures.count > 1 diff --git a/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj b/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj index af8dfc82..95ff0aff 100644 --- a/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj +++ b/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj @@ -44,14 +44,15 @@ 2D9601C92CC812EF000EF3D5 /* Exceptions for "common" folder in "metro-now Watch App" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( - components/countdown.view.swift, - "components/route-name.view.swift", - "const/api-const.swift", + "components/countdown-view/countdown.swift", + "components/countdown-view/countdown.utils.swift", + "components/route-label-view/get-color-by-route-name.utils.swift", + "components/route-label-view/route-name.view.swift", + "components/route-label-view/route-type.enum.swift", + const/endpoint.const.swift, "deprecated/managers/network-manager.swift", "managers/location-manager.swift", "types/api-types.swift", - "types/metro-line.swift", - "utils/get-color-by-route-name.swift", utils/station.utils.swift, ); target = 2D001BB72CC8099C00C6B4F8 /* metro-now Watch App */; diff --git a/apps/mobile/metro-now/metro-now/ContentView.swift b/apps/mobile/metro-now/metro-now/ContentView.swift index 716049f5..6dc80005 100644 --- a/apps/mobile/metro-now/metro-now/ContentView.swift +++ b/apps/mobile/metro-now/metro-now/ContentView.swift @@ -4,51 +4,9 @@ import SwiftUI struct ContentView: View { - @StateObject private var viewModel = DepartureViewModel() - var body: some View { - if viewModel.metroStops != nil || viewModel.allStops != nil { - NavigationStack { - List { - if let closestMetroStop = viewModel.closestMetroStop { - Section(header: Text("Metro")) { - ClosestMetroStopSectionView( - closestStop: closestMetroStop, - departures: viewModel.departures - ) - } - } - - if let closestStop = viewModel.closestStop { - let platforms = closestStop.platforms - .filter { platform in - platform.routes - .contains( - where: { - !["A", "B", "C"].contains( - $0.name.uppercased() - ) - } - ) - } - .sorted(by: { - getPlatformLabel($0) < getPlatformLabel($1) - }) - - ForEach(platforms, id: \.id) { - platform in - - PlatformSectionView( - platform: platform, - departures: viewModel.departures - ) - } - } - } - .navigationTitle(viewModel.closestMetroStop?.name ?? "") - } - } else { - ProgressView() + NavigationStack { + ClosestStopPageView() } } } diff --git a/apps/mobile/metro-now/metro-now/components/departure-list-item/departure-list-item-placeholder.view.swift b/apps/mobile/metro-now/metro-now/components/departure-list-item/departure-list-item-placeholder.view.swift index 1e3b6074..d4e184f1 100644 --- a/apps/mobile/metro-now/metro-now/components/departure-list-item/departure-list-item-placeholder.view.swift +++ b/apps/mobile/metro-now/metro-now/components/departure-list-item/departure-list-item-placeholder.view.swift @@ -65,35 +65,35 @@ struct ClosestStopPageListItemPlaceholderView: View { List { ClosestStopPageListItemPlaceholderView( routeLabel: "A", - routeLabelBackground: getColorByRouteName("A") + routeLabelBackground: getRouteType("A").color ) ClosestStopPageListItemPlaceholderView( routeLabel: "A", - routeLabelBackground: getColorByRouteName("A") + routeLabelBackground: getRouteType("A").color ) ClosestStopPageListItemPlaceholderView( routeLabel: "C", - routeLabelBackground: getColorByRouteName("C") + routeLabelBackground: getRouteType("C").color ) ClosestStopPageListItemPlaceholderView( routeLabel: "C", - routeLabelBackground: getColorByRouteName("C") + routeLabelBackground: getRouteType("C").color ) ClosestStopPageListItemPlaceholderView( routeLabel: nil, - routeLabelBackground: getColorByRouteName("49") + routeLabelBackground: getRouteType("49").color ) ClosestStopPageListItemPlaceholderView( routeLabel: nil, - routeLabelBackground: getColorByRouteName("149") + routeLabelBackground: getRouteType("149").color ) ClosestStopPageListItemPlaceholderView( routeLabel: nil, - routeLabelBackground: getColorByRouteName("P2") + routeLabelBackground: getRouteType("P2").color ) ClosestStopPageListItemPlaceholderView( routeLabel: nil, - routeLabelBackground: getColorByRouteName("LD") + routeLabelBackground: getRouteType("LD").color ) } } diff --git a/apps/mobile/metro-now/metro-now/departure-view-model.swift b/apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page-view-model.swift similarity index 97% rename from apps/mobile/metro-now/metro-now/departure-view-model.swift rename to apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page-view-model.swift index 17aa4d94..6dbb5a57 100644 --- a/apps/mobile/metro-now/metro-now/departure-view-model.swift +++ b/apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page-view-model.swift @@ -8,7 +8,7 @@ import SwiftUI private let REFETCH_INTERVAL: TimeInterval = 3 // seconds private let SECONDS_BEFORE: TimeInterval = 3 // how many seconds after departure will it still be visible -class DepartureViewModel: NSObject, ObservableObject, CLLocationManagerDelegate { +class ClosestStopPageViewModel: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() @Published var location: CLLocation? @@ -144,7 +144,6 @@ class DepartureViewModel: NSObject, ObservableObject, CLLocationManagerDelegate "stop": stopsIds, "platform": platformsIds, "limit": 4, - "totalLimit": 200, "minutesBefore": 1, ] ) diff --git a/apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page.view.swift b/apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page.view.swift new file mode 100644 index 00000000..09cf1851 --- /dev/null +++ b/apps/mobile/metro-now/metro-now/pages/closest-stop/closest-stop-page.view.swift @@ -0,0 +1,48 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import SwiftUI + +struct ClosestStopPageView: View { + @StateObject private var viewModel = ClosestStopPageViewModel() + + var body: some View { + if viewModel.metroStops != nil || viewModel.allStops != nil { + List { + if let closestMetroStop = viewModel.closestMetroStop { + Section(header: Text("Metro")) { + MetroDeparturesListView( + closestStop: closestMetroStop, + departures: viewModel.departures + ) + } + } + + if let closestStop = viewModel.closestStop { + let platforms = closestStop.platforms + .filter { platform in + platform.routes.contains(where: { + let routeName = $0.name.uppercased() + let containsMetro = METRO_LINES.contains(routeName) + + return !containsMetro + }) + } + .sorted(by: { + getPlatformLabel($0) < getPlatformLabel($1) + }) + + ForEach(platforms, id: \.id) { platform in + PlatformDeparturesListView( + platform: platform, + departures: viewModel.departures + ) + } + } + } + .navigationTitle(viewModel.closestMetroStop?.name ?? "") + } else { + ProgressView() + } + } +} diff --git a/apps/mobile/metro-now/metro-now/pages/closest-stop/metro/metro-departures.view.swift b/apps/mobile/metro-now/metro-now/pages/closest-stop/metro-departures.view.swift similarity index 61% rename from apps/mobile/metro-now/metro-now/pages/closest-stop/metro/metro-departures.view.swift rename to apps/mobile/metro-now/metro-now/pages/closest-stop/metro-departures.view.swift index e8fd327b..95440fb2 100644 --- a/apps/mobile/metro-now/metro-now/pages/closest-stop/metro/metro-departures.view.swift +++ b/apps/mobile/metro-now/metro-now/pages/closest-stop/metro-departures.view.swift @@ -3,7 +3,7 @@ import SwiftUI -struct ClosestMetroStopSectionView: View { +struct MetroDeparturesListView: View { let closestStop: ApiStop let departures: [ApiDeparture]? @@ -21,7 +21,7 @@ struct ClosestMetroStopSectionView: View { ClosestStopPageListItemView( routeLabel: routeLabel, - routeLabelBackground: getColorByRouteName(routeLabel), + routeLabelBackground: getRouteType(routeLabel).color, headsign: platformDepartures[0].headsign, departure: platformDepartures[0].departure.predicted, nextHeadsign: nextDeparture?.headsign, @@ -32,30 +32,9 @@ struct ClosestMetroStopSectionView: View { ClosestStopPageListItemPlaceholderView( routeLabel: routeLabel, - routeLabelBackground: getColorByRouteName(routeLabel) + routeLabelBackground: getRouteType(routeLabel).color ) } } } } - -struct PlatformDeparturesView: View { - private let departures: [ApiDeparture] - - init(departures: [ApiDeparture]) { - self.departures = departures - } - - var body: some View { - ForEach(departures, id: \.headsign) { departure in - ClosestStopPageListItemView( - routeLabel: departure.route, - routeLabelBackground: getColorByRouteName(departure.route), - headsign: departure.headsign, - departure: departure.departure.predicted, - nextHeadsign: nil, - nextDeparture: nil - ) - } - } -} diff --git a/apps/mobile/metro-now/metro-now/pages/closest-stop/non-metro/non-metro-departures.view.swift b/apps/mobile/metro-now/metro-now/pages/closest-stop/non-metro/non-metro-departures.view.swift deleted file mode 100644 index 84c7cc47..00000000 --- a/apps/mobile/metro-now/metro-now/pages/closest-stop/non-metro/non-metro-departures.view.swift +++ /dev/null @@ -1,90 +0,0 @@ -// metro-now -// https://github.com/krystxf/metro-now - -import SwiftUI - -struct PlatformSectionListView: View { - let departures: [[ApiDeparture]] - - var body: some View { - ForEach(departures, id: \.first?.id) { deps in - let departure = deps.count > 0 ? deps[0] : nil - let nextDeparture = deps.count > 1 ? deps[1] : nil - - if let departure { - ClosestStopPageListItemView( - routeLabel: departure.route, - routeLabelBackground: getColorByRouteName(departure.route), - headsign: departure.headsign, - departure: departure.departure.predicted, - nextHeadsign: nextDeparture?.headsign, - nextDeparture: nextDeparture?.departure.predicted - ) - } else { - Text("Loading") - } - } - } -} - -struct PlatformSectionListPlaceholderView: View { - let routes: [ApiRoute] - let maxItems: Int = 3 - - var body: some View { - ForEach(routes.prefix(maxItems), id: \.id) { route in - ClosestStopPageListItemPlaceholderView( - routeLabel: nil, - routeLabelBackground: getColorByRouteName(route.name) - ) - } - } -} - -struct PlatformSectionView: View { - let platform: ApiPlatform - let departures: [[ApiDeparture]]? - - init(platform: ApiPlatform, departures: [ApiDeparture]?) { - self.platform = platform - - guard let departures else { - self.departures = nil - return - } - - let filteredDepartures = departures - .filter { - platform.id == $0.platformId - } - - let departuresByRoute = Dictionary( - grouping: filteredDepartures, - by: { $0.route } - ) - - self.departures = Array( - departuresByRoute - .map(\.value) - .sorted(by: { - $0.first!.departure.predicted < $1.first!.departure.predicted - } - ) - ) - } - - var body: some View { - if departures == nil || departures!.count > 0 { - Section(header: Text(getPlatformLabel(platform))) { - if let departures { - PlatformSectionListView(departures: departures) - } else { - PlatformSectionListPlaceholderView(routes: platform.routes) - .redacted(reason: .placeholder) - } - } - } else { - EmptyView() - } - } -} diff --git a/apps/mobile/metro-now/metro-now/pages/closest-stop/other-departures.view.swift b/apps/mobile/metro-now/metro-now/pages/closest-stop/other-departures.view.swift new file mode 100644 index 00000000..62bee4b0 --- /dev/null +++ b/apps/mobile/metro-now/metro-now/pages/closest-stop/other-departures.view.swift @@ -0,0 +1,72 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import SwiftUI + +struct PlatformDeparturesListView: View { + let platform: ApiPlatform + let departures: [[ApiDeparture]]? + + init(platform: ApiPlatform, departures: [ApiDeparture]?) { + self.platform = platform + + guard let departures else { + self.departures = nil + return + } + + let filteredDepartures = departures + .filter { + platform.id == $0.platformId + } + + let departuresByRoute = Dictionary( + grouping: filteredDepartures, + by: { $0.route } + ) + + self.departures = Array( + departuresByRoute + .map(\.value) + .sorted(by: { + $0.first!.departure.predicted < $1.first!.departure.predicted + } + ) + ) + } + + var body: some View { + if departures == nil || departures!.count > 0 { + Section(header: Text(getPlatformLabel(platform))) { + if let departures { + ForEach(departures, id: \.first?.id) { deps in + let departure = deps.count > 0 ? deps[0] : nil + let nextDeparture = deps.count > 1 ? deps[1] : nil + + if let departure { + ClosestStopPageListItemView( + routeLabel: departure.route, + routeLabelBackground: getRouteType(departure.route).color, + headsign: departure.headsign, + departure: departure.departure.predicted, + nextHeadsign: nextDeparture?.headsign, + nextDeparture: nextDeparture?.departure.predicted + ) + } else { + Text("Loading") + } + } + } else { + ForEach(platform.routes.prefix(3), id: \.id) { route in + ClosestStopPageListItemPlaceholderView( + routeLabel: nil, + routeLabelBackground: getRouteType(route.name).color + ) + } + } + } + } else { + EmptyView() + } + } +}