Skip to content

Commit 908ad6b

Browse files
committed
feat(app): vehicles annotations
1 parent 1dd205c commit 908ad6b

File tree

12 files changed

+380
-78
lines changed

12 files changed

+380
-78
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
2+
import MapKit
3+
import SwiftUI
4+
5+
struct StopAnnotation: View {
6+
let routes: [String]
7+
var stopIcon: String
8+
let isMetro: Bool
9+
10+
init(routes: [String]) {
11+
isMetro = routes.allSatisfy { METRO_LINES.contains($0) }
12+
self.routes = routes
13+
14+
guard !isMetro else {
15+
stopIcon = "tram.circle.fill"
16+
return
17+
}
18+
19+
let transportTypes = Set(routes.map {
20+
getVehicleType($0)
21+
})
22+
23+
if transportTypes.contains(.bus) {
24+
stopIcon = "bus"
25+
} else {
26+
stopIcon = transportTypes.first!.rawValue
27+
}
28+
}
29+
30+
var body: some View {
31+
if isMetro {
32+
MetroAnnotationStack(metroLines: routes)
33+
} else {
34+
Image(
35+
systemName: stopIcon
36+
)
37+
.imageScale(.small)
38+
.padding(3)
39+
.font(.system(size: 16))
40+
.foregroundStyle(.white)
41+
.background(
42+
LinearGradient(
43+
gradient: Gradient(colors: getBgColors(routes)
44+
45+
),
46+
startPoint: .topLeading,
47+
endPoint: .bottomTrailing
48+
)
49+
)
50+
.clipShape(.rect(cornerRadius: 4))
51+
.overlay(
52+
RoundedRectangle(cornerRadius: 6)
53+
.stroke(.white, lineWidth: 2)
54+
)
55+
}
56+
}
57+
}
58+
59+
#Preview("Metro") {
60+
Map {
61+
Annotation(
62+
"Random place on map", coordinate: CLLocationCoordinate2D(
63+
latitude: 50.113680, longitude: 14.449520)
64+
) {
65+
StopAnnotation(
66+
routes: ["A"]
67+
)
68+
}
69+
}
70+
}
71+
72+
#Preview("Metro Stack") {
73+
Map {
74+
Annotation(
75+
"Random place on map", coordinate: CLLocationCoordinate2D(
76+
latitude: 50.113680, longitude: 14.449520)
77+
) {
78+
StopAnnotation(
79+
routes: ["A", "C"]
80+
)
81+
}
82+
}
83+
}
84+
85+
#Preview("Tram") {
86+
Map {
87+
Annotation(
88+
"Random place on map", coordinate: CLLocationCoordinate2D(
89+
latitude: 50.113680, longitude: 14.449520)
90+
) {
91+
StopAnnotation(
92+
routes: ["78"]
93+
)
94+
}
95+
}
96+
}
97+
98+
#Preview("Night Tram") {
99+
Map {
100+
Annotation(
101+
"Random place on map", coordinate: CLLocationCoordinate2D(
102+
latitude: 50.113680, longitude: 14.449520)
103+
) {
104+
StopAnnotation(
105+
routes: ["90"]
106+
)
107+
}
108+
}
109+
}
110+
111+
#Preview("Bus") {
112+
Map {
113+
Annotation(
114+
"Random place on map", coordinate: CLLocationCoordinate2D(
115+
latitude: 50.113680, longitude: 14.449520)
116+
) {
117+
StopAnnotation(
118+
routes: ["700"]
119+
)
120+
}
121+
}
122+
}
123+
124+
#Preview("Bus & Tram") {
125+
Map {
126+
Annotation(
127+
"Random place on map", coordinate: CLLocationCoordinate2D(
128+
latitude: 50.113680, longitude: 14.449520)
129+
) {
130+
StopAnnotation(
131+
routes: ["60", "700"]
132+
)
133+
}
134+
}
135+
}
136+
137+
#Preview("Night Bus") {
138+
Map {
139+
Annotation(
140+
"Random place on map", coordinate: CLLocationCoordinate2D(
141+
latitude: 50.113680, longitude: 14.449520)
142+
) {
143+
StopAnnotation(
144+
routes: ["900"]
145+
)
146+
}
147+
}
148+
}
149+
150+
#Preview("Detour") {
151+
Map {
152+
Annotation(
153+
"Random place on map", coordinate: CLLocationCoordinate2D(
154+
latitude: 50.113680, longitude: 14.449520)
155+
) {
156+
StopAnnotation(
157+
routes: ["X700"]
158+
)
159+
}
160+
}
161+
}
162+
163+
#Preview("Ferry") {
164+
Map {
165+
Annotation(
166+
"Random place on map", coordinate: CLLocationCoordinate2D(
167+
latitude: 50.113680, longitude: 14.449520)
168+
) {
169+
StopAnnotation(
170+
routes: ["P4"]
171+
)
172+
}
173+
}
174+
}
175+
176+
#Preview("Cable car") {
177+
Map {
178+
Annotation(
179+
"Random place on map", coordinate: CLLocationCoordinate2D(
180+
latitude: 50.113680, longitude: 14.449520)
181+
) {
182+
StopAnnotation(
183+
routes: ["LD"]
184+
)
185+
}
186+
}
187+
}
188+
189+
#Preview("Train") {
190+
Map {
191+
Annotation(
192+
"Random place on map", coordinate: CLLocationCoordinate2D(
193+
latitude: 50.113680, longitude: 14.449520)
194+
) {
195+
StopAnnotation(
196+
routes: ["S42"]
197+
)
198+
}
199+
}
200+
}

app/Common/Components/MapAnnotation/BusAnnotation/BusAnnotation.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.

app/Common/Components/MapAnnotation/AnnotationStack/MetroAnnotationStack.swift renamed to app/Common/Components/MapAnnotation/MetroAnnotationStack.swift

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,3 @@ struct MetroAnnotationStack: View {
3131
}
3232
}
3333
}
34-
35-
#Preview("Two stations annotation") {
36-
Map {
37-
Annotation(
38-
"Random place on map", coordinate: CLLocationCoordinate2D(
39-
latitude: 50.113680, longitude: 14.449520)
40-
) {
41-
MetroAnnotationStack(
42-
metroLines: ["A", "B"]
43-
)
44-
}
45-
}
46-
}
47-
48-
// this is not very valid for Prague, but might be useful in the future
49-
#Preview("Multiple stations annotation") {
50-
Map {
51-
Annotation(
52-
"Random place on map", coordinate: CLLocationCoordinate2D(
53-
latitude: 50.113680, longitude: 14.449520)
54-
) {
55-
MetroAnnotationStack(
56-
metroLines: ["A", "B", "C", "A", "B", "C"]
57-
)
58-
}
59-
}
60-
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
import SwiftUI
3+
4+
func getBgColors(_ routes: [String]) -> [Color] {
5+
let vehicleTypes: [VehicleType] = routes.map { getVehicleType($0) }
6+
7+
if vehicleTypes.count == 1, vehicleTypes[0] == .metro {
8+
return [getMetroLineColor(routes[0])]
9+
}
10+
11+
if routes.allSatisfy({ isNightService($0) }) {
12+
return [.gray]
13+
} else if routes.allSatisfy({ $0.starts(with: "X") }) {
14+
return [.orange]
15+
}
16+
17+
var res: [Color] = []
18+
if vehicleTypes.contains(.bus) {
19+
res.append(.blue)
20+
}
21+
22+
if vehicleTypes.contains(.tram) {
23+
res.append(.indigo)
24+
} else if vehicleTypes.contains(.lightrail) {
25+
res.append(.gray)
26+
} else if vehicleTypes.contains(.cablecar) {
27+
res.append(.brown)
28+
} else if vehicleTypes.contains(.ferry) {
29+
res.append(.mint)
30+
}
31+
32+
return res
33+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
// https://pid.cz/jizdni-rady-podle-linek/metro/
3+
func getVehicleType(_ nameAnyCased: String) -> VehicleType {
4+
let name = nameAnyCased.uppercased()
5+
6+
if name.hasPrefix("LD") {
7+
return .cablecar
8+
}
9+
10+
if name.hasPrefix("R") ||
11+
name.hasPrefix("S") ||
12+
name.hasPrefix("T") ||
13+
name.hasPrefix("U")
14+
{
15+
return .lightrail
16+
}
17+
18+
if name.hasPrefix("P") {
19+
return .ferry
20+
}
21+
22+
let number = Int(name)
23+
guard let number else {
24+
return .bus
25+
}
26+
27+
// trolley bus
28+
if number == 58 || number == 59 {
29+
return .bus
30+
} else if number < 100 {
31+
return .tram
32+
}
33+
34+
return .bus
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
3+
func isNightService(_ name: String) -> Bool {
4+
let number = Int(name)
5+
guard let number else {
6+
return false
7+
}
8+
9+
return number >= 900 || (number >= 90 && number < 100)
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
enum VehicleType: String {
3+
case bus
4+
case tram
5+
case cablecar
6+
case ferry
7+
case metro
8+
case lightrail
9+
}

app/Common/Utils/metroUtils.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import Foundation
99
import MapKit
1010
import SwiftUI
1111

12+
let METRO_LINES: [String] = ["A", "B", "C"]
13+
1214
enum MetroLine: String {
1315
case A
1416
case B
@@ -73,4 +75,20 @@ func getClosestStationFromGeoJSON(location: CLLocation) -> MetroStationsGeoJSONF
7375
return stations.features[closestStationIndex]
7476
}
7577

76-
func getSortedStationsByDistance() {}
78+
func shortenStopName(_ name: String) -> String {
79+
if name == "Depo Hostivař" {
80+
return "D. Hostivař"
81+
} else if name == "Nemocnice Motol" {
82+
return "N. Motol"
83+
} else if name == "Pražského povstání" {
84+
return "P. povstání"
85+
}
86+
87+
let shorten: String = name
88+
.replacingOccurrences(of: "Náměstí", with: "Nám.")
89+
.replacingOccurrences(of: "náměstí", with: "Nád.")
90+
.replacingOccurrences(of: "Nádraží", with: "Nád.")
91+
.replacingOccurrences(of: "nádraží", with: "nád.")
92+
93+
return shorten
94+
}

app/metro-now-widgets/Core/Views/small/SmallWidgetView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct SmallWidgetView: View {
1818
ForEach(0 ..< 2) { index in
1919
if entry.departures.count > index {
2020
DepartureView(
21-
direction: entry.departures[index].direction,
21+
direction: shortenStopName(entry.departures[index].direction),
2222
departureDate: entry.departures[index].departureDate,
2323
metroLine: entry.departures[index].metroLine
2424
)

0 commit comments

Comments
 (0)