@capgo/capacitor-launch-navigator 8.0.20 → 8.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,29 +2,44 @@ import Foundation
2
2
  import UIKit
3
3
  import MapKit
4
4
 
5
+ struct NavigationAppInfo {
6
+ let name: String
7
+ let urlScheme: String
8
+ let url: String
9
+ }
10
+
11
+ // swiftlint:disable type_body_length
5
12
  @objc public class LaunchNavigator: NSObject {
6
13
 
7
- private let navigationApps: [String: (name: String, urlScheme: String)] = [
8
- "apple_maps": ("Apple Maps", "maps://"),
9
- "google_maps": ("Google Maps", "comgooglemaps://"),
10
- "waze": ("Waze", "waze://"),
11
- "citymapper": ("Citymapper", "citymapper://"),
12
- "garmin_navigon": ("Garmin Navigon", "navigon://"),
13
- "transit_app": ("Transit App", "transit://"),
14
- "yandex": ("Yandex Navigator", "yandexnavi://"),
15
- "uber": ("Uber", "uber://"),
16
- "tomtom": ("TomTom", "tomtomgo://"),
17
- "sygic": ("Sygic", "com.sygic.aura://"),
18
- "here": ("HERE Maps", "here-route://"),
19
- "moovit": ("Moovit", "moovit://"),
20
- "lyft": ("Lyft", "lyft://"),
21
- "mapsme": ("MAPS.ME", "mapsme://"),
22
- "cabify": ("Cabify", "cabify://"),
23
- "baidu": ("Baidu Maps", "baidumap://"),
24
- "gaode": ("Gaode Maps", "iosamap://"),
25
- "99taxi": ("99 Taxi", "99app://")
14
+ public var webPathResolver: ((URL) -> String?)?
15
+
16
+ let navigationApps: [String: NavigationAppInfo] = [
17
+ "apple_maps": NavigationAppInfo(name: "Apple Maps", urlScheme: "maps://", url: "https://www.apple.com/maps/"),
18
+ "google_maps": NavigationAppInfo(name: "Google Maps", urlScheme: "comgooglemaps://", url: "https://www.google.com/maps"),
19
+ "waze": NavigationAppInfo(name: "Waze", urlScheme: "waze://", url: "https://www.waze.com"),
20
+ "citymapper": NavigationAppInfo(name: "Citymapper", urlScheme: "citymapper://", url: "https://citymapper.com"),
21
+ "garmin_navigon": NavigationAppInfo(name: "Garmin Navigon", urlScheme: "navigon://", url: "https://www.garmin.com"),
22
+ "transit_app": NavigationAppInfo(name: "Transit App", urlScheme: "transit://", url: "https://transitapp.com"),
23
+ "yandex": NavigationAppInfo(name: "Yandex Navigator", urlScheme: "yandexnavi://", url: "https://yandex.com/maps"),
24
+ "uber": NavigationAppInfo(name: "Uber", urlScheme: "uber://", url: "https://www.uber.com"),
25
+ "tomtom": NavigationAppInfo(name: "TomTom", urlScheme: "tomtomgo://", url: "https://www.tomtom.com"),
26
+ "sygic": NavigationAppInfo(name: "Sygic", urlScheme: "com.sygic.aura://", url: "https://www.sygic.com/gps-navigation"),
27
+ "here": NavigationAppInfo(name: "HERE Maps", urlScheme: "here-route://", url: "https://wego.here.com"),
28
+ "moovit": NavigationAppInfo(name: "Moovit", urlScheme: "moovit://", url: "https://moovitapp.com"),
29
+ "lyft": NavigationAppInfo(name: "Lyft", urlScheme: "lyft://", url: "https://www.lyft.com"),
30
+ "mapsme": NavigationAppInfo(name: "MAPS.ME", urlScheme: "mapsme://", url: "https://maps.me"),
31
+ "guru_maps": NavigationAppInfo(name: "Guru Maps", urlScheme: "guru://", url: "https://gurumaps.app"),
32
+ "organic_maps": NavigationAppInfo(name: "Organic Maps", urlScheme: "om://", url: "https://organicmaps.app"),
33
+ "yandex_maps": NavigationAppInfo(name: "Yandex Maps", urlScheme: "yandexmaps://", url: "https://yandex.com/maps"),
34
+ "2gis": NavigationAppInfo(name: "2GIS", urlScheme: "dgis://", url: "https://2gis.com"),
35
+ "cabify": NavigationAppInfo(name: "Cabify", urlScheme: "cabify://", url: "https://cabify.com"),
36
+ "baidu": NavigationAppInfo(name: "Baidu Maps", urlScheme: "baidumap://", url: "https://map.baidu.com"),
37
+ "gaode": NavigationAppInfo(name: "Gaode Maps", urlScheme: "iosamap://", url: "https://www.amap.com"),
38
+ "tesla": NavigationAppInfo(name: "Tesla", urlScheme: "tesla://", url: "https://www.tesla.com"),
39
+ "99taxi": NavigationAppInfo(name: "99 Taxi", urlScheme: "99app://", url: "https://99app.com")
26
40
  ]
27
41
 
42
+ // swiftlint:disable:next cyclomatic_complexity function_body_length function_parameter_count
28
43
  public func navigate(
29
44
  app: String,
30
45
  destination: CLLocationCoordinate2D,
@@ -32,6 +47,7 @@ import MapKit
32
47
  startName: String?,
33
48
  destinationName: String?,
34
49
  transportMode: String,
50
+ viewController: UIViewController? = nil,
35
51
  completion: @escaping (Bool, String?) -> Void
36
52
  ) {
37
53
  switch app {
@@ -106,6 +122,34 @@ import MapKit
106
122
  destination: destination,
107
123
  completion: completion
108
124
  )
125
+ case "guru_maps":
126
+ launchGuruMaps(
127
+ destination: destination,
128
+ start: start,
129
+ transportMode: transportMode,
130
+ completion: completion
131
+ )
132
+ case "organic_maps":
133
+ launchOrganicMaps(
134
+ destination: destination,
135
+ start: start,
136
+ destinationName: destinationName,
137
+ transportMode: transportMode,
138
+ completion: completion
139
+ )
140
+ case "yandex_maps":
141
+ launchYandexMaps(
142
+ destination: destination,
143
+ start: start,
144
+ completion: completion
145
+ )
146
+ case "2gis":
147
+ launch2Gis(
148
+ destination: destination,
149
+ start: start,
150
+ transportMode: transportMode,
151
+ completion: completion
152
+ )
109
153
  case "cabify":
110
154
  launchCabify(
111
155
  destination: destination,
@@ -124,6 +168,13 @@ import MapKit
124
168
  start: start,
125
169
  completion: completion
126
170
  )
171
+ case "tesla":
172
+ shareToTesla(
173
+ destination: destination,
174
+ destinationName: destinationName,
175
+ viewController: viewController,
176
+ completion: completion
177
+ )
127
178
  default:
128
179
  completion(false, "Unsupported navigation app: \(app)")
129
180
  }
@@ -300,6 +351,103 @@ import MapKit
300
351
  openURL(urlString, completion: completion)
301
352
  }
302
353
 
354
+ private func launchGuruMaps(
355
+ destination: CLLocationCoordinate2D,
356
+ start: CLLocationCoordinate2D?,
357
+ transportMode: String,
358
+ completion: @escaping (Bool, String?) -> Void
359
+ ) {
360
+ var urlString = "guru://nav?finish=\(destination.latitude),\(destination.longitude)&mode=\(guruMapsMode(transportMode))&start_navigation=true"
361
+
362
+ if let startCoord = start {
363
+ urlString += "&start=\(startCoord.latitude),\(startCoord.longitude)"
364
+ }
365
+
366
+ openURL(urlString, completion: completion)
367
+ }
368
+
369
+ private func guruMapsMode(_ transportMode: String) -> String {
370
+ switch transportMode {
371
+ case "walking":
372
+ return "pedestrian"
373
+ case "bicycling":
374
+ return "bicycle"
375
+ default:
376
+ return "auto"
377
+ }
378
+ }
379
+
380
+ private func launchOrganicMaps(
381
+ destination: CLLocationCoordinate2D,
382
+ start: CLLocationCoordinate2D?,
383
+ destinationName: String?,
384
+ transportMode: String,
385
+ completion: @escaping (Bool, String?) -> Void
386
+ ) {
387
+ let origin = start.map { "\($0.latitude),\($0.longitude)" } ?? "currentLocation"
388
+ var urlString = "om://v2/nav?origin=\(encoded(origin))&destination=\(destination.latitude),\(destination.longitude)&mode=\(organicMapsMode(transportMode))"
389
+
390
+ if let destinationName = destinationName, !destinationName.isEmpty {
391
+ urlString += "&destination_name=\(encoded(destinationName))"
392
+ }
393
+
394
+ openURL(urlString, completion: completion)
395
+ }
396
+
397
+ private func organicMapsMode(_ transportMode: String) -> String {
398
+ switch transportMode {
399
+ case "walking":
400
+ return "pedestrian"
401
+ case "bicycling":
402
+ return "bicycle"
403
+ case "transit":
404
+ return "transit"
405
+ default:
406
+ return "drive"
407
+ }
408
+ }
409
+
410
+ private func launchYandexMaps(
411
+ destination: CLLocationCoordinate2D,
412
+ start: CLLocationCoordinate2D?,
413
+ completion: @escaping (Bool, String?) -> Void
414
+ ) {
415
+ var urlString = "yandexmaps://build_route_on_map/?lat_to=\(destination.latitude)&lon_to=\(destination.longitude)"
416
+
417
+ if let startCoord = start {
418
+ urlString += "&lat_from=\(startCoord.latitude)&lon_from=\(startCoord.longitude)"
419
+ }
420
+
421
+ openURL(urlString, completion: completion)
422
+ }
423
+
424
+ private func launch2Gis(
425
+ destination: CLLocationCoordinate2D,
426
+ start: CLLocationCoordinate2D?,
427
+ transportMode: String,
428
+ completion: @escaping (Bool, String?) -> Void
429
+ ) {
430
+ var urlString = "dgis://2gis.ru/routeSearch/rsType/\(twoGisMode(transportMode))"
431
+
432
+ if let startCoord = start {
433
+ urlString += "/from/\(startCoord.longitude),\(startCoord.latitude)"
434
+ }
435
+
436
+ urlString += "/to/\(destination.longitude),\(destination.latitude)"
437
+ openURL(urlString, completion: completion)
438
+ }
439
+
440
+ private func twoGisMode(_ transportMode: String) -> String {
441
+ switch transportMode {
442
+ case "walking":
443
+ return "pedestrian"
444
+ case "transit":
445
+ return "ctx"
446
+ default:
447
+ return "car"
448
+ }
449
+ }
450
+
303
451
  private func launchCabify(
304
452
  destination: CLLocationCoordinate2D,
305
453
  start: CLLocationCoordinate2D?,
@@ -342,6 +490,66 @@ import MapKit
342
490
  openURL(urlString, completion: completion)
343
491
  }
344
492
 
493
+ private func shareToTesla(
494
+ destination: CLLocationCoordinate2D,
495
+ destinationName: String?,
496
+ viewController: UIViewController?,
497
+ completion: @escaping (Bool, String?) -> Void
498
+ ) {
499
+ guard let viewController = viewController else {
500
+ completion(false, "Unable to present share sheet")
501
+ return
502
+ }
503
+
504
+ let activityViewController = UIActivityViewController(
505
+ activityItems: [teslaShareText(destination: destination, destinationName: destinationName)],
506
+ applicationActivities: nil
507
+ )
508
+ activityViewController.popoverPresentationController?.sourceView = viewController.view
509
+ activityViewController.completionWithItemsHandler = { _, completed, _, error in
510
+ if let error = error {
511
+ completion(false, error.localizedDescription)
512
+ } else if completed {
513
+ completion(true, nil)
514
+ } else {
515
+ completion(false, "Share cancelled")
516
+ }
517
+ }
518
+
519
+ viewController.present(activityViewController, animated: true)
520
+ }
521
+
522
+ func teslaShareText(destination: CLLocationCoordinate2D, destinationName: String?) -> String {
523
+ "\(teslaShareLabel(destinationName))\n\n\(googleMapsPositionURLString(destination: destination))"
524
+ }
525
+
526
+ func googleMapsPositionURLString(destination: CLLocationCoordinate2D) -> String {
527
+ let coordinates = String(
528
+ format: "%.6f,%.6f",
529
+ locale: Locale(identifier: "en_US_POSIX"),
530
+ destination.latitude,
531
+ destination.longitude
532
+ )
533
+ return "https://maps.google.com/?q=\(coordinates)"
534
+ }
535
+
536
+ private func teslaShareLabel(_ destinationName: String?) -> String {
537
+ guard let destinationName = destinationName else {
538
+ return "Dropped pin"
539
+ }
540
+
541
+ let normalizedName = destinationName
542
+ .trimmingCharacters(in: .whitespacesAndNewlines)
543
+ .replacingOccurrences(of: "[\\r\\n]+", with: " ", options: .regularExpression)
544
+ return normalizedName.isEmpty ? "Dropped pin" : normalizedName
545
+ }
546
+
547
+ private func encoded(_ value: String) -> String {
548
+ var allowed = CharacterSet.urlQueryAllowed
549
+ allowed.remove(charactersIn: "&=+/?#")
550
+ return value.addingPercentEncoding(withAllowedCharacters: allowed) ?? value
551
+ }
552
+
345
553
  private func openURL(_ urlString: String, completion: @escaping (Bool, String?) -> Void) {
346
554
  guard let url = URL(string: urlString) else {
347
555
  completion(false, "Invalid URL")
@@ -392,3 +600,4 @@ import MapKit
392
600
  return Array(navigationApps.keys)
393
601
  }
394
602
  }
603
+ // swiftlint:enable type_body_length