· 5 years ago · Jan 23, 2021, 02:06 PM
1//
2// MainController.swift
3// inert-ios
4//
5// Created by Nikita Benin on 10.11.2020.
6//
7
8import UIKit
9import Mapbox
10import MapboxCoreNavigation
11import MapboxNavigation
12import MapboxDirections
13
14protocol SelectOrderTypeDelegate {
15 func didSelectOrderType(indexPath: IndexPath)
16}
17protocol PointDataForItemDelegate {
18 func updateElements(id: Int, comment: String, type: String)
19}
20
21protocol ShowRouteDelegate {
22 func showRoute()
23}
24
25class MainController: BaseController {
26 // MARK: - UI Elements
27 var pointId: Int = 0
28 var popup: UIView?
29 //var dataDelegate: PointDataForItemDelegate?
30 let defaults = UserDefaults.standard
31 var userChoice = [1,2,3,4]
32 private let topBarView: MapTopBarView = MapTopBarView()
33 var mapView: MGLMapView!
34 var routeOptions: NavigationRouteOptions?
35 var route: Route?
36 var rasterLayer: MGLRasterStyleLayer?
37 let manager = CLLocationManager()
38 var latUser = 0.0
39 var lonUser = 0.0
40 let directions = Directions.shared
41 let orderPointController = OrderPointController()
42 var pointDataForRoute : PointData?
43 var coordinates = [[CLLocationCoordinate2D]]()
44 var polyline = [MGLPolylineFeature]()
45 let alert = UIAlertController(title: nil, message: "Загрузка...", preferredStyle: .alert)
46 let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
47
48 let showSearchButton: UIButton = {
49 let button = UIButton()
50 button.layer.addShadow(backgroundColor: .white, shadowColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.15), cornerRadius: 35/2, shadowRadius: 3)
51 button.setTitle("Показать список", for: .normal)
52 button.setTitleColor(.black, for: .normal)
53 button.titleLabel!.font = UIFont.customFont(ofSize: 14, type: .OpenSansSemiBold)
54 button.addTarget(self, action: #selector(showSearchButtonTapped), for: .touchUpInside)
55
56 return button
57 }()
58
59 private let filterButton: UIButton = {
60 let button = UIButton()
61 button.setImage(ImageAssets.sliders.image, for: .normal)
62 button.layer.addShadow(backgroundColor: .white, shadowColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.15), cornerRadius: 45/2, shadowRadius: 3)
63 return button
64 }()
65 private let geoButton: UIButton = {
66 let button = UIButton()
67 button.setImage(ImageAssets.geo.image, for: .normal)
68 //button.layer.addShadow(backgroundColor: .white, shadowColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.15), cornerRadius: 45/2, shadowRadius: 3)
69 button.addTarget(self, action: #selector(myLocationButton), for: .touchUpInside)
70 return button
71 }()
72
73 // MARK: - Variables
74 var currentTopBarItem : MapTopBarItem = MapTopBarItem.orders //установка дефолтного значения
75 var pointAnnotations = [MGLPointAnnotation]()
76 private var searchItems: [SearchOrderItem] = []
77 var constraint = NSLayoutConstraint()
78
79 // MARK: - Lifecycle
80 override func viewDidLoad() {
81 super.viewDidLoad()
82 setupViews()
83 setupConstraints()
84 loadOrder()
85 saveWhenChangeItem()
86 manager.delegate = self
87 print(userChoice)
88 manager.requestWhenInUseAuthorization()
89 manager.startUpdatingLocation()
90 manager.requestLocation()
91 // mapView.showsUserLocation = true
92
93 orderPointController.orderPointView.routeDelegate = self
94 orderPointController.delegate = self
95
96 let tabBarController = self.tabBarController as! TabBarController
97 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
98 overlayContainer.searchViewController.popupHeaderView.delegate = self
99
100 mapView.setUserTrackingMode(.follow, animated: false, completionHandler: nil)
101 if CLLocationManager.locationServicesEnabled() {
102 switch CLLocationManager.authorizationStatus() {
103 case .notDetermined, .restricted, .denied:
104 latUser = 55.75
105 lonUser = 37.61
106 print("No access")
107 case .authorizedAlways, .authorizedWhenInUse:
108 print("Access")
109 @unknown default:
110 break
111 }
112 } else {
113 print("Location services are not enabled")
114 }
115 let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTapCluster(sender:)))
116 doubleTap.numberOfTapsRequired = 2
117 doubleTap.delegate = self
118 for recognizer in mapView.gestureRecognizers!
119 where (recognizer as? UITapGestureRecognizer)?.numberOfTapsRequired == 2 {
120 recognizer.require(toFail: doubleTap)
121 }
122 mapView.addGestureRecognizer(doubleTap)
123 //
124 // // Add a single tap gesture recognizer. This gesture requires the built-in
125 // // MGLMapView tap gestures (such as those for zoom and annotation selection)
126 // // to fail (this order differs from the double tap above).
127 // let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleMapTap(sender:)))
128 // for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
129 // singleTap.require(toFail: recognizer)
130 // }
131 // mapView.addGestureRecognizer(singleTap)
132
133 let singleTap2 = UITapGestureRecognizer(target: self, action: #selector(handleMapTap2(sender:)))
134 for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
135 singleTap2.require(toFail: recognizer)
136 }
137 mapView.addGestureRecognizer(singleTap2)
138 }
139
140 @objc func showSearchButtonTapped() {
141 showSearchController()
142 }
143
144 @objc func handleMapTap2(sender: UITapGestureRecognizer) {
145 //changeOpacity()
146 let spot = sender.location(in: mapView)
147 let features = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["route-style"])
148 let secondFeature = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["polyline-case"])
149 let thirdFeauture = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["polyline-case2"])
150 let cluster = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["port"])
151 let cluster2 = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["clusteredPorts"])
152 let cluster3 = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["1"])
153 let cluster4 = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["2"])
154 let cluster5 = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["3"])
155 let cluster6 = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["4"])
156 let cluster7 = mapView.visibleFeatures(at: spot, styleLayerIdentifiers: ["clusteredPortsNumbers"])
157
158
159 if let feature = cluster.first {
160 print("asfkjgasuygctvysaaxasya 1")
161 }
162
163 if let feature = cluster2.first {
164 print("asfkjgasuygctvysaaxasya 2")
165 }
166
167 if let feature = cluster3.first {
168 print("asfkjgasuygctvysaaxasya 3")
169 }
170
171 if let feature = cluster4.first {
172 print("asfkjgasuygctvysaaxasya 4")
173 }
174
175 if let feature = cluster5.first {
176 print("asfkjgasuygctvysaaxasya 5")
177 }
178 if let feature = cluster6.first {
179 print("asfkjgasuygctvysaaxasya 6")
180 }
181 if let feature = cluster7.first {
182 print("asfkjgasuygctvysaaxasya 7")
183 }
184
185 let state = mapView.style?.layer(withIdentifier: "route-style") as? MGLLineStyleLayer
186 let stateTwo = mapView.style?.layer(withIdentifier: "polyline-case") as? MGLLineStyleLayer
187 let stateThree = mapView.style?.layer(withIdentifier: "polyline-case2") as? MGLLineStyleLayer
188
189 // Get the name of the selected state.
190 if let state = state, let feature = features.first {
191 if state.lineColor == NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)) {
192
193 self.mapView.style?.removeLayer(state)
194 if let stateTwo = stateTwo {
195 self.mapView.style?.insertLayer(state, above: stateTwo)
196 }
197
198 if let stateThree = stateThree {
199 self.mapView.style?.removeLayer(state)
200 self.mapView.style?.removeLayer(stateTwo!)
201 self.mapView.style?.insertLayer(state, above: stateThree)
202 self.mapView.style?.insertLayer(stateTwo!, below: stateThree)
203 }
204
205 state.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
206 stateTwo?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
207 stateThree?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
208 }
209 } else if let stateTwo = stateTwo, let feature = secondFeature.first {
210 if stateTwo.lineColor == NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)) {
211
212 self.mapView.style?.removeLayer(stateTwo)
213 self.mapView.style?.insertLayer(stateTwo, above: state!)
214 if let stateThree = stateThree {
215 self.mapView.style?.removeLayer(stateTwo)
216 self.mapView.style?.removeLayer(stateThree)
217 self.mapView.style?.insertLayer(stateTwo, above: state!)
218 self.mapView.style?.insertLayer(stateThree, below: state!)
219 }
220
221 state?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
222 stateTwo.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
223 stateThree?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
224 }
225 } else if let stateThree = stateThree, let feauture = thirdFeauture.first {
226 if stateThree.lineColor == NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)) {
227
228 self.mapView.style?.removeLayer(stateThree)
229 self.mapView.style?.removeLayer(stateTwo!)
230 self.mapView.style?.insertLayer(stateThree, above: state!)
231 self.mapView.style?.insertLayer(stateTwo!, below: state!)
232
233 state?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
234 stateTwo?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
235 stateThree.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
236 }
237 }
238 }
239 // MARK - LOCATION UPDATE API
240 func updateLocation(){
241
242 let request = LocationRequest(lat: latUser, lon: lonUser)
243 LocationAPI.updateLocation(request: request, completion: { result in
244 switch result {
245 case .success(let result) :
246 print("Success")
247 case .failure(let error) :
248 print("200 OK")
249 }
250
251 })
252 }
253 //// // Calculate route to be used for navigation
254 // func calculateRoute(from origin: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
255 // // Coordinate accuracy is how close the route must come to the waypoint in order to be considered viable. It is measured in meters. A negative value indicates that the route is viable regardless of how far the route is from the waypoint.
256 // let origin = Waypoint(coordinate: origin, coordinateAccuracy: -1, name: "Start")
257 // let destination = Waypoint(coordinate: destination, coordinateAccuracy: -1, name: "Finish")
258 //
259 // // Specify that the route is intended for automobiles avoiding traffic
260 // let routeOptions = NavigationRouteOptions(waypoints: [origin, destination], profileIdentifier: .automobileAvoidingTraffic)
261 // // Generate the route object and draw it on the map
262 // Directions.shared.calculate(routeOptions) { [weak self] (session, result) in
263 // switch result {
264 // case .failure(let error):
265 // print(error.localizedDescription)
266 // case .success(let response):
267 // print("route is calculated")
268 // guard let route = response.routes?.first, let strongSelf = self else {
269 // return
270 // }
271 // strongSelf.route = route
272 // strongSelf.routeOptions = routeOptions
273 //
274 // // Draw the route on the map after creating it
275 // //strongSelf.drawRoute(route: route)
276 //
277 // // Show destination waypoint on the map
278 // //strongSelf.mapView.showWaypoints(on: route)
279 // // Display callout view on destination annotation
280 // if let annotation = strongSelf.mapView.annotations as? MGLPointAnnotation {
281 // annotation.title = "Start navigation"
282 // strongSelf.mapView.selectAnnotation(annotation, animated: true, completionHandler: nil)
283 // }
284 // }
285 // }
286 // }
287
288 // func drawRoute(route: Route) {
289 // guard let routeShape = route.shape, routeShape.coordinates.count > 0 else { return }
290 // // Convert the route’s coordinates into a polyline
291 // var routeCoordinates = routeShape.coordinates
292 // let polyline = MGLPolylineFeature(coordinates: &routeCoordinates, count: UInt(routeCoordinates.count))
293 //
294 // // If there's already a route line on the map, reset its shape to the new route
295 // if let source = mapView.style?.source(withIdentifier: "route-source") as? MGLShapeSource {
296 // source.shape = polyline
297 // } else {
298 // let source = MGLShapeSource(identifier: "route-source", features: [polyline], options: nil)
299 //
300 // // Customize the route line color and width
301 // let lineStyle = MGLLineStyleLayer(identifier: "route-style", source: source)
302 // lineStyle.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
303 // lineStyle.lineWidth = NSExpression(forConstantValue: 3)
304 //
305 // // Add the source and style layer of the route line to the map
306 // print("route is drawn")
307 // mapView.style?.addSource(source)
308 // mapView.style?.addLayer(lineStyle)
309 // }
310 // }
311
312
313 func drawRouteFromAdress() {
314 guard let mapAPIroutes = self.pointDataForRoute?.data.routes else {return}
315 if mapAPIroutes.count != 0 {
316
317 for index in mapAPIroutes.indices {
318 var coordinators = [CLLocationCoordinate2D]()
319
320 for lonlat in mapAPIroutes[index].latlng! {
321 if lonlat.count >= 2 {
322 coordinators.append(CLLocationCoordinate2D(latitude: lonlat[0], longitude: lonlat[1]))
323 }
324 }
325
326 coordinates.append(coordinators)
327 }
328 for polylines in coordinates.indices {
329 polyline.append(MGLPolylineFeature(coordinates: (self.coordinates[polylines]), count: UInt(((self.coordinates[polylines].count)))))
330 }
331 switch polyline.count {
332
333 case 2:
334 if let source = self.mapView.style?.source(withIdentifier: "route-source") as? MGLShapeSource {
335 source.shape = polyline[0]
336 } else {
337 let source = MGLShapeSource(identifier: "route-source", features: [polyline[0]], options: nil)
338 let lineStyle = MGLLineStyleLayer(identifier: "route-style", source: source)
339 lineStyle.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
340 lineStyle.lineWidth = NSExpression(forConstantValue: 12)
341 lineStyle.lineOpacity = NSExpression(forConstantValue: 0.7)
342 self.mapView.style?.addSource(source)
343 self.mapView.style?.addLayer(lineStyle)
344 }
345
346 if let source = self.mapView.style?.source(withIdentifier: "route-source2") as? MGLShapeSource {
347 source.shape = polyline[1]
348 } else {
349 let source2 = MGLShapeSource(identifier: "route-source2", features: [polyline[1]], options: nil)
350 let casingLayer = MGLLineStyleLayer(identifier: "polyline-case", source: source2)
351 casingLayer.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
352 casingLayer.lineWidth = NSExpression(forConstantValue: 12)
353 casingLayer.lineOpacity = NSExpression(forConstantValue: 0.7)
354 self.mapView.style?.insertLayer(casingLayer, below: (self.mapView.style?.layers.last)!)
355 self.mapView.style?.addSource(source2)
356 }
357
358 case 3:
359 if let source = self.mapView.style?.source(withIdentifier: "route-source") as? MGLShapeSource {
360 source.shape = polyline[0]
361 let state = mapView.style?.layer(withIdentifier: "route-style") as? MGLLineStyleLayer
362 state!.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
363
364 } else {
365 let source = MGLShapeSource(identifier: "route-source", features: [polyline[0]], options: nil)
366 let lineStyle = MGLLineStyleLayer(identifier: "route-style", source: source)
367 lineStyle.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
368 lineStyle.lineWidth = NSExpression(forConstantValue: 12)
369 lineStyle.lineOpacity = NSExpression(forConstantValue: 0.7)
370 self.mapView.style?.addSource(source)
371 self.mapView.style?.addLayer(lineStyle)
372 }
373
374 if let source = self.mapView.style?.source(withIdentifier: "route-source2") as? MGLShapeSource {
375 source.shape = polyline[1]
376 } else {
377 let source2 = MGLShapeSource(identifier: "route-source2", features: [polyline[1]], options: nil)
378 let casingLayer = MGLLineStyleLayer(identifier: "polyline-case", source: source2)
379 casingLayer.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
380 casingLayer.lineWidth = NSExpression(forConstantValue: 12)
381 casingLayer.lineOpacity = NSExpression(forConstantValue: 0.7)
382 self.mapView.style?.insertLayer(casingLayer, below: (self.mapView.style?.layers.last)!)
383 self.mapView.style?.addSource(source2)
384 }
385
386 if let source = self.mapView.style?.source(withIdentifier: "route-source3") as? MGLShapeSource {
387 source.shape = polyline[2]
388 } else {
389 let source3 = MGLShapeSource(identifier: "route-source3", features: [polyline[2]], options: nil)
390 let casingLayer2 = MGLLineStyleLayer(identifier: "polyline-case2", source: source3)
391 casingLayer2.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
392 casingLayer2.lineWidth = NSExpression(forConstantValue: 12)
393 casingLayer2.lineOpacity = NSExpression(forConstantValue: 0.7)
394 self.mapView.style?.insertLayer(casingLayer2, below: (self.mapView.style?.layers.last)!)
395 self.mapView.style?.addSource(source3)
396 }
397
398 default:
399 if let source = self.mapView.style?.source(withIdentifier: "route-source") as? MGLShapeSource {
400 source.shape = polyline[0]
401 let state = mapView.style?.layer(withIdentifier: "route-style") as? MGLLineStyleLayer
402 state?.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
403
404 } else {
405 let source = MGLShapeSource(identifier: "route-source", features: [polyline[0]], options: nil)
406 let lineStyle = MGLLineStyleLayer(identifier: "route-style", source: source)
407 lineStyle.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
408 lineStyle.lineWidth = NSExpression(forConstantValue: 12)
409 lineStyle.lineOpacity = NSExpression(forConstantValue: 0.7)
410 self.mapView.style?.addSource(source)
411 self.mapView.style?.addLayer(lineStyle)
412 }
413 if let source = self.mapView.style?.source(withIdentifier: "route-source2") as? MGLShapeSource {
414 source.shape = nil
415 }
416 if let source = self.mapView.style?.source(withIdentifier: "route-source3") as? MGLShapeSource {
417 source.shape = nil
418 }
419 }
420 }
421 }
422
423 override func viewWillAppear(_ animated: Bool) {
424
425 }
426 override func viewWillDisappear(_ animated: Bool) {
427 manager.stopUpdatingLocation()
428 }
429
430 override func viewDidAppear(_ animated: Bool) {
431 super.viewDidAppear(animated)
432 }
433
434 // MARK: - Setup views
435 private func setupViews() {
436 // mapView.register(ClusterAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)
437 mapView = MGLMapView(frame: view.bounds)
438 mapView.logoView.isHidden = true
439 mapView.isRotateEnabled = false
440 mapView.compassView.isHidden = true
441 mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
442 mapView.setCenter(CLLocationCoordinate2D(latitude: 55.75, longitude: 37.61), zoomLevel: 8, animated: false)
443 mapView.delegate = self
444 self.view.addSubview(mapView)
445
446 let constraintMap = NSLayoutConstraint(item: mapView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
447 constraint = constraintMap
448 view.addConstraint(constraint)
449 topBarView.delegate = self
450 view.addSubview(topBarView)
451
452 filterButton.addTap {
453 self.router?.showFilters(currentTopBarItem: self.currentTopBarItem, searchItems: self.searchItems, latUser:self.latUser, lonUser: self.lonUser, delegate: self)
454 }
455
456 let tabBarController = self.tabBarController as! TabBarController
457 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
458 overlayContainer.searchViewController.popupHeaderView.filterButton.isHidden = false
459 overlayContainer.searchViewController.popupHeaderView.filterButton.addTap {
460 self.router?.showFilters(currentTopBarItem: self.currentTopBarItem, searchItems: self.searchItems, latUser:self.latUser, lonUser: self.lonUser, delegate: self)
461 }
462
463 view.addSubview(filterButton)
464 view.addSubview(geoButton)
465 view.addSubview(showSearchButton)
466 }
467
468 private func setupConstraints() {
469 switch UIScreen.main.nativeBounds.height {
470 case 1334:
471 topBarView.snp.makeConstraints { (make) in
472 make.top.equalToSuperview().offset(GlobalConstants.topSafeArea - 20)
473 make.left.right.equalToSuperview()
474 make.height.equalTo(60)
475 }
476 default:
477 topBarView.snp.makeConstraints { (make) in
478 make.top.equalToSuperview().offset(GlobalConstants.topSafeArea - 10)
479 make.left.right.equalToSuperview()
480 make.height.equalTo(60)
481 }
482 }
483
484 filterButton.snp.makeConstraints { (make) in
485 make.top.equalTo(topBarView.snp.bottom).offset(16)
486 make.right.equalToSuperview().inset(16)
487 make.height.width.equalTo(45)
488 }
489 geoButton.snp.makeConstraints { (make) in
490 make.bottom.equalToSuperview().offset(-90)
491 make.right.equalToSuperview().inset(14)
492 make.height.width.equalTo(48)
493 }
494 mapView.snp.makeConstraints { (make) in
495 make.height.equalToSuperview()
496 make.width.equalToSuperview()
497 }
498
499 showSearchButton.snp.makeConstraints { (make) in
500 make.height.equalTo(35)
501 make.centerX.equalToSuperview()
502 make.width.equalTo(135)
503 make.bottom.equalToSuperview().offset(-60)
504 }
505 }
506 @objc func myLocationButton(sender: UIButton!){
507 manager.requestWhenInUseAuthorization()
508 manager.startUpdatingLocation()
509 manager.requestLocation()
510 let userCenter = CLLocationCoordinate2D(latitude: latUser, longitude: lonUser)
511 print("geo lat:\(latUser),lon:\(lonUser)")
512
513 mapView.showsUserLocation = true
514 mapView.setCenter(userCenter, zoomLevel: 12, animated: true)
515 let point = MGLPointAnnotation()
516 print(" annotation lat:\(latUser),lon:\(lonUser)")
517 point.coordinate = CLLocationCoordinate2D(latitude: latUser, longitude: lonUser)
518
519 if let source = self.mapView.style?.source(withIdentifier: "marker-source") as? MGLShapeSource {
520
521 } else {
522 let shapeSource = MGLShapeSource(identifier: "marker-source", shape: point, options: nil)
523 let shapeLayer = MGLSymbolStyleLayer(identifier: "marker-style", source: shapeSource)
524 if let image = ImageAssets.location.image {
525 mapView.style?.setImage(image, forName: "home-symbol")
526 }
527
528 // Tell the layer to use the image in the sprite
529 shapeLayer.iconImageName = NSExpression(forConstantValue: "home-symbol")
530
531 // Add the source and style layer to the map
532 mapView.style?.addSource(shapeSource)
533 mapView.style?.addLayer(shapeLayer)
534 }
535
536 // Create a style layer for the symbol
537 }
538
539 private func setMapAnnotations(searchOrderItems: [SearchOrderItem]) {
540 pointAnnotations.removeAll()
541 for orderItem in searchOrderItems {
542 let point = INPointAnnotation()
543 let coordinate = CLLocationCoordinate2D(latitude: orderItem.lat, longitude: orderItem.lon)
544 point.coordinate = coordinate
545 point.typeId = orderItem.item.typeId
546 point.id = orderItem.item.id
547 point.title = "\(coordinate.latitude), \(coordinate.longitude)"
548 pointAnnotations.append(point)
549 }
550 mapView.reloadStyle(nil)
551 mapView.addAnnotations(pointAnnotations)
552 }
553}
554// MARK: - User Defaults
555extension MainController {
556 func saveWhenChangeItem(){
557
558 self.userChoice.append(2)
559 self.defaults.set(self.userChoice, forKey: "choice")
560 }
561}
562
563// MARK: - MGLMapViewDelegate
564extension MainController: MGLMapViewDelegate {
565
566 // Implement the delegate method that allows annotations to show callouts when tapped
567 func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
568 return false
569 }
570 // Present the navigation view controller when the callout is selected
571 func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation) {
572 guard let route = route, let routeOptions = routeOptions else {
573 return
574 }
575 let navigationViewController = NavigationViewController(for: route, routeIndex: 0, routeOptions: routeOptions)
576 navigationViewController.modalPresentationStyle = .fullScreen
577 self.present(navigationViewController, animated: true, completion: nil)
578 }
579
580 func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
581
582 if annotation is MGLUserLocation && mapView.userLocation != nil {
583 return CustomUserLocationAnnotationView()
584 }
585 return nil
586 }
587 func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
588 let tileSource = MGLRasterTileSource(identifier: "inert-tilesource", tileURLTemplates: ["https://inert.su/osm_tiles/{z}/{x}/{y}.png"], options: [.tileSize: 256])
589 let rasterLayer = MGLRasterStyleLayer(identifier: "inert-layer", source: tileSource)
590 style.addSource(tileSource)
591 style.addLayer(rasterLayer)
592 self.rasterLayer = rasterLayer
593
594 // let point = MGLPointAnnotation()
595 // print(" annotation lat:\(latUser),lon:\(lonUser)")
596 // point.coordinate = CLLocationCoordinate2D(latitude: latUser, longitude: lonUser)
597 //
598 // // Create a data source to hold the point data
599 // let shapeSource = MGLShapeSource(identifier: "marker-source", shape: point, options: nil)
600 //
601 // // Create a style layer for the symbol
602 // let shapeLayer = MGLSymbolStyleLayer(identifier: "marker-style", source: shapeSource)
603 // if let image = ImageAssets.location.image {
604 // style.setImage(image, forName: "home-symbol")
605 // }
606 //
607 // // Tell the layer to use the image in the sprite
608 // shapeLayer.iconImageName = NSExpression(forConstantValue: "home-symbol")
609
610 // Add the source and style layer to the map
611 //style.addSource(shapeSource)
612 //style.addLayer(shapeLayer)
613 let icon = ImageAssets.geo.image!
614
615 print("clusterRadius:", icon.size.width)
616 let feature = NSMutableDictionary()
617 let features: [MGLPointFeature] = pointAnnotations.map({
618 let point = $0 as! INPointAnnotation
619 let f = MGLPointFeature()
620 let type = String(point.typeId ?? 0)
621 if let array = feature.value(forKey: type) as? NSMutableArray {
622 array.add(f)
623 feature.setValue(array, forKey: type)
624 }
625 else
626 {
627 let array = NSMutableArray()
628 array.add(f)
629 feature.setValue(array, forKey: type)
630 }
631 f.coordinate = $0.coordinate
632 return f
633 })
634 let source = MGLShapeSource(identifier: "clusteredPorts", features: features , options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
635 style.addSource(source)
636 style.setImage(ImageAssets.giveMarker.image!, forName: "giveMarker")
637 style.setImage(ImageAssets.transporationMarker.image!, forName: "transporationMarker")
638 style.setImage(ImageAssets.callMarker.image!, forName: "callMarker")
639 style.setImage(ImageAssets.rentMarker.image!, forName: "rentMarker")
640 style.setImage(ImageAssets.clusterMarker.image!, forName: "clusterMarker")
641 style.setImage(ImageAssets.quarryMarker.image!, forName: "quarryMarker")
642 style.setImage(ImageAssets.sandMarker.image!, forName: "sandMarker")
643 style.setImage(ImageAssets.dumpMarker.image!, forName: "dumpMarker")
644 style.setImage(ImageAssets.snowMarker.image!, forName: "snowMarker")
645 style.setImage(ImageAssets.ce.image!, forName: "ce")
646 let types = feature.allKeys
647 types.forEach { (key) in
648
649 let k = key as! String
650 switch currentTopBarItem {
651 case .orders:
652 orderPointController.orderPointView.setHeaderView(title: "Заказы", hideSortLabel: true, hideDistanceLabel: true, hidePriceLabel: true)
653 // orderPointView.mapPopupHeaderView.titleLabel.text = "Заказы"
654 // orderPointView.mapPopupHeaderView.sortLabel.isHidden = true
655 // orderPointView.mapPopupHeaderView.distanceLabel.isHidden = true
656 // orderPointView.mapPopupHeaderView.priceLabel.isHidden = true
657 switch k {
658 case "1":
659 let source = MGLShapeSource(identifier: "1", features: feature.value(forKey: "1") as! [MGLShape & MGLFeature], options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
660 style.addSource(source)
661 let ports = MGLSymbolStyleLayer(identifier: "1", source: source)
662 ports.iconImageName = NSExpression(forConstantValue: "giveMarker")
663 ports.predicate = NSPredicate(format: "cluster != YES")
664 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
665 style.addLayer(ports)
666 case "2":
667 let source = MGLShapeSource(identifier: "2", features: feature.value(forKey: "2") as! [MGLShape & MGLFeature], options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
668 style.addSource(source)
669 let ports = MGLSymbolStyleLayer(identifier: "2", source: source)
670 ports.iconImageName = NSExpression(forConstantValue: "transporationMarker")
671 ports.predicate = NSPredicate(format: "cluster != YES")
672 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
673 style.addLayer(ports)
674 case "3":
675 let source = MGLShapeSource(identifier: "3", features: feature.value(forKey: "3") as! [MGLShape & MGLFeature], options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
676 style.addSource(source)
677 let ports = MGLSymbolStyleLayer(identifier: "3", source: source)
678 ports.iconImageName = NSExpression(forConstantValue: "callMarker")
679 ports.predicate = NSPredicate(format: "cluster != YES")
680 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
681 style.addLayer(ports)
682 case "4":
683 let source = MGLShapeSource(identifier: "4", features: feature.value(forKey: "4") as! [MGLShape & MGLFeature], options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
684 style.addSource(source)
685 let ports = MGLSymbolStyleLayer(identifier: "4", source: source)
686 ports.iconImageName = NSExpression(forConstantValue: "rentMarker")
687 ports.predicate = NSPredicate(format: "cluster != YES")
688 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
689 style.addLayer(ports)
690 default:
691 let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
692 ports.iconImageName = NSExpression(forConstantValue: "emptyMarker")
693 ports.predicate = NSPredicate(format: "cluster != YES")
694 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
695 style.addLayer(ports)
696 }
697 case .techinics:
698 orderPointController.orderPointView.setHeaderTitle(title: "Спецтехника")
699 // orderPointView.mapPopupHeaderView.titleLabel.text = "Спецтехника"
700 let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
701 ports.iconImageName = NSExpression(forConstantValue: "ce")
702 ports.predicate = NSPredicate(format: "cluster != YES")
703 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
704 style.addLayer(ports)
705 case .cariers:
706 orderPointController.orderPointView.setHeaderTitle(title: "Карьеры")
707 // orderPointView.mapPopupHeaderView.titleLabel.text = "Карьеры"
708 switch k {
709 case "1":
710 let source = MGLShapeSource(identifier: "1", features: feature.value(forKey: "1") as! [MGLShape & MGLFeature], options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
711 style.addSource(source)
712 let ports = MGLSymbolStyleLayer(identifier: "1", source: source)
713 ports.iconImageName = NSExpression(forConstantValue: "quarryMarker")
714 ports.predicate = NSPredicate(format: "cluster != YES")
715 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
716 style.addLayer(ports)
717 default:
718 print("k cariers")
719 }
720
721 case .sand:
722 orderPointController.orderPointView.setHeaderTitle(title: "Котлованный песок")
723 // orderPointView.mapPopupHeaderView.titleLabel.text = "Котлованный песок"
724 switch k {
725 case "2":
726 let source = MGLShapeSource(identifier: "2", features: feature.value(forKey: "2") as! [MGLShape & MGLFeature], options: [.clustered : true, .clusterRadius : icon.size.width, .maximumZoomLevelForClustering: 16])
727 style.addSource(source)
728 let ports = MGLSymbolStyleLayer(identifier: "2", source: source)
729 ports.iconImageName = NSExpression(forConstantValue: "sandMarker")
730 ports.predicate = NSPredicate(format: "cluster != YES")
731 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
732 style.addLayer(ports)
733 default:
734 print("k cariers")
735 }
736 case .snow:
737 orderPointController.orderPointView.setHeaderTitle(title: "Снег")
738 // orderPointView.mapPopupHeaderView.titleLabel.text = "Снег"
739 let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
740 ports.iconImageName = NSExpression(forConstantValue: "snowMarker")
741 ports.predicate = NSPredicate(format: "cluster != YES")
742 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
743 style.addLayer(ports)
744 case .trash:
745 orderPointController.orderPointView.setHeaderTitle(title: "Свалки")
746 // orderPointView.mapPopupHeaderView.titleLabel.text = "Свалки"
747 let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
748 ports.iconImageName = NSExpression(forConstantValue: "dumpMarker")
749 ports.predicate = NSPredicate(format: "cluster != YES")
750 ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
751 style.addLayer(ports)
752
753 // default:break
754 // let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
755 // ports.iconImageName = NSExpression(forConstantValue: "emptyMarker")
756 // ports.predicate = NSPredicate(format: "cluster != YES")
757 // ports.iconAllowsOverlap = NSExpression(forConstantValue: true)
758 // style.addLayer(ports)
759 // print("error in switch top bar item")
760 }
761 }
762
763 let circlesLayer = MGLSymbolStyleLayer(identifier: "clusteredPorts", source: source)
764 circlesLayer.predicate = NSPredicate(format: "cluster == YES")
765 circlesLayer.iconImageName = NSExpression(forConstantValue: "clusterMarker")
766// circlesLayer.iconAllowsOverlap = NSExpression(forConstantValue: true)
767 style.addLayer(circlesLayer)
768
769 let layer = MGLSymbolStyleLayer(identifier: "clusteredPortsNumbers", source: source)
770 layer.textColor = NSExpression(forConstantValue: UIColor.black)
771 layer.textFontSize = NSExpression(forConstantValue: NSNumber(value: Double(icon.size.width) / 4))
772 layer.iconImageName = NSExpression(forConstantValue: "clusterMarker")
773 layer.iconAllowsOverlap = NSExpression(forConstantValue: true)
774 layer.text = NSExpression(format: "CAST(point_count, 'NSString')")
775 layer.predicate = NSPredicate(format: "cluster == YES")
776 style.addLayer(layer)
777 }
778
779 // MARK: - tap on marker methods
780 func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
781
782 mapView.setCenter(CLLocationCoordinate2D(latitude: annotation.coordinate.latitude - 0.15, longitude: annotation.coordinate.longitude), animated: true)
783
784 // Удаление линий маршрутов
785 if let source = self.mapView.style?.source(withIdentifier: "route-source") as? MGLShapeSource {
786 source.shape = nil
787 }
788
789 if let source = self.mapView.style?.source(withIdentifier: "route-source2") as? MGLShapeSource {
790 source.shape = nil
791 }
792
793 if let source = self.mapView.style?.source(withIdentifier: "route-source3") as? MGLShapeSource {
794 source.shape = nil
795 }
796
797 let pointAnnotation = annotation as? INPointAnnotation
798 switch self.currentTopBarItem {
799 case .orders:
800 if let id = pointAnnotation?.id {
801 loadPoinData(id: id)
802 loadingIndicator.hidesWhenStopped = true
803 loadingIndicator.style = UIActivityIndicatorView.Style.gray
804 loadingIndicator.startAnimating();
805 alert.view.addSubview(loadingIndicator)
806 guard presentedViewController != alert else { return }
807 present(alert, animated: true, completion: nil)
808 NotificationCenter.default.post(name: Notification.Name("Close"), object: nil)
809 // constraint.constant = -200
810
811 } else {
812 print("Error in loading point data didSelect annotation method")
813 }
814 default:
815 if let id = pointAnnotation?.id {
816 loadPoinDataForPoint(id: id)
817 loadingIndicator.hidesWhenStopped = true
818 loadingIndicator.style = UIActivityIndicatorView.Style.gray
819 loadingIndicator.startAnimating();
820 alert.view.addSubview(loadingIndicator)
821 guard presentedViewController != alert else { return }
822 present(alert, animated: true, completion: nil)
823 NotificationCenter.default.post(name: Notification.Name("Close"), object: nil)
824
825// constraint.constant = -200
826 //var constraint = NSLayoutConstraint(item: mapView, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: -200)
827
828 // self.view.addConstraint(constraint)
829
830 // mapView.snp.makeConstraints { (make) in
831 // make.bottom.equalToSuperview().offset(-200)
832 // }
833
834
835 } else {
836 print("Error in loading point data didSelect annotation method")
837 }
838 }
839
840
841 // Calculating route
842 // if let coordinate = pointAnnotation?.coordinate{
843 // calculateRoute(from: CLLocationCoordinate2D(latitude: latUser, longitude: lonUser), to: coordinate)
844 // } else {
845 // print("Error in calculateRoute")
846 // }
847
848 mapView.removeAnnotation(annotation)
849 mapView.addAnnotation(annotation)
850 }
851
852 func loadPoinData(id: Int){
853
854 let request = PointRequest(centerLat: 55.751701, centerLon: 37.618790)
855 PointAPI.annotationData(request: request , id: id , completion: { [weak self] result in
856 guard let strongSelf = self else { return }
857 switch result {
858 case .success(let annotation):
859 self?.dismiss(animated: false, completion: nil)
860
861 strongSelf.orderPointController.orderPointView.reloadData()
862 strongSelf.orderPointController.orderPointView.pointData = annotation
863// strongSelf.orderPointController.orderPointView.delegate = self
864 strongSelf.orderPointController.router = strongSelf.router
865
866 let tabBarController = strongSelf.tabBarController as! TabBarController
867 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
868 overlayContainer.viewControllers.remove(at: 1)
869 overlayContainer.viewControllers.insert(strongSelf.orderPointController, at: 1)
870 let targetNotch: ViewSize = .medium
871 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
872
873 self?.pointDataForRoute = annotation
874 self?.coordinates = []
875 self?.polyline = []
876 self?.dismiss(animated: false, completion: nil)
877 case .failure(let error):
878 print("PointAPI error", error.message as Any)
879 self?.dismiss(animated: false, completion: nil)
880 strongSelf.showNetworkError(networkError: error)
881 }
882 })
883 }
884 func loadPoinDataForPoint(id: Int){
885
886 let request = PointRequest(centerLat: 55.751701, centerLon: 37.618790)
887
888 let tabBarController = self.tabBarController as! TabBarController
889 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
890 overlayContainer.viewControllers.remove(at: 1)
891 overlayContainer.viewControllers.insert(self.orderPointController, at: 1)
892 let targetNotch: ViewSize = .minimum
893 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
894
895
896 PointAPI.annotationDataForPoint(request: request , id: id , completion: { [weak self] result in
897 switch result {
898 case .success(let annotation):
899 guard let strongSelf = self else { return }
900 self?.dismiss(animated: false, completion: nil)
901
902 strongSelf.orderPointController.orderPointView.reloadData()
903 strongSelf.orderPointController.orderPointView.pointData = annotation
904// strongSelf.orderPointController.orderPointView.delegate = self
905 strongSelf.orderPointController.router = strongSelf.router
906
907 let targetNotch: ViewSize = .medium
908 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
909
910 self?.pointDataForRoute = annotation
911 self?.coordinates = []
912 self?.polyline = []
913
914 case .failure(let error):
915 print("PointAPI error", error.message as Any)
916 self?.dismiss(animated: false, completion: nil)
917 self?.showNetworkError(networkError: error)
918 }
919 })
920 }
921
922 func removeMapConstraint(){
923 constraint.constant = 0
924 //self.view.addConstraint(constraint)
925 }
926 private func imageForMarker(typeId: Int, currentTopBarItem: MapTopBarItem ) -> UIImage? {
927 // MARK: - typeId for orders
928 switch currentTopBarItem {
929 case .orders:
930 switch typeId {
931 case 1: return ImageAssets.giveMarker.image//поставка
932 case 2: return ImageAssets.transporationMarker.image//перевозка
933 case 3: return ImageAssets.callMarker.image//вызов
934 case 4: return ImageAssets.rentMarker.image// аренда
935 default: return ImageAssets.emptyMarker.image
936 }
937 case .techinics:
938 return ImageAssets.ce.image//единственный тип который я нашел
939 case .snow:
940 return ImageAssets.snowMarker.image
941 case .trash:
942 return ImageAssets.dumpMarker.image//свалка
943 case .cariers:
944 return ImageAssets.quarryMarker.image//карьер
945 case .sand:
946 return ImageAssets.sandMarker.image
947 // default:
948 // print("problem in imageForMarker function")
949 // return ImageAssets.emptyMarker.image
950 }
951
952 }
953
954 func mapViewRegionIsChanging(_ mapView: MGLMapView) {
955 showPopup(false, animated: false)
956 }
957
958 private func firstCluster(with gestureRecognizer: UIGestureRecognizer) -> MGLPointFeatureCluster? {
959 let point = gestureRecognizer.location(in: gestureRecognizer.view)
960 let width: CGFloat = 44
961 let rect = CGRect(x: point.x - width / 2, y: point.y - width / 2, width: width, height: width)
962
963 // This example shows how to check if a feature is a cluster by
964 // checking for that the feature is a `MGLPointFeatureCluster`. Alternatively, you could
965 // also check for conformance with `MGLCluster` instead.
966 let features = mapView.visibleFeatures(in: rect, styleLayerIdentifiers: ["clusteredPorts", "ports"])
967 let clusters = features.compactMap { $0 as? MGLPointFeatureCluster }
968
969 // Pick the first cluster, ideally selecting the one nearest nearest one to
970 // the touch point.
971 return clusters.first
972 }
973
974 @objc func handleDoubleTapCluster(sender: UITapGestureRecognizer) {
975
976 guard let source = mapView.style?.source(withIdentifier: "clusteredPorts") as? MGLShapeSource else {
977 return
978 }
979
980 guard sender.state == .ended else {
981 return
982 }
983
984 showPopup(false, animated: false)
985
986 guard let cluster = firstCluster(with: sender) else {
987 return
988 }
989
990 let zoom = source.zoomLevel(forExpanding: cluster)
991
992 if zoom > 0 {
993 mapView.setCenter(cluster.coordinate, zoomLevel: zoom, animated: true)
994 }
995 }
996
997 // @objc func handleMapTap(sender: UITapGestureRecognizer) {
998 //
999 // guard let source = mapView.style?.source(withIdentifier: "clusteredPorts") as? MGLShapeSource else {
1000 // return
1001 // }
1002 //
1003 // guard sender.state == .ended else {
1004 // return
1005 // }
1006 //
1007 // showPopup(false, animated: false)
1008 //
1009 // let point = sender.location(in: sender.view)
1010 // let width: CGFloat = 46
1011 // let rect = CGRect(x: point.x - width / 2, y: point.y - width / 2, width: width, height: width)
1012 //
1013 //// let rectView = UIView()
1014 //// rectView.removeFromSuperview()
1015 //// rectView.frame = rect
1016 //// rectView.backgroundColor = .red
1017 //// view.addSubview(rectView)
1018 //
1019 // let features = mapView.visibleFeatures(in: rect, styleLayerIdentifiers: ["clusteredPorts", "ports"])
1020 //
1021 // // Pick the first feature (which may be a port or a cluster), ideally selecting
1022 // // the one nearest nearest one to the touch point.
1023 // guard let feature = features.first else {
1024 // return
1025 // }
1026 //
1027 // let description: String
1028 // let color: UIColor
1029 //
1030 // if let cluster = feature as? MGLPointFeatureCluster {
1031 // // Tapped on a cluster.
1032 // let children = source.children(of: cluster)
1033 // description = "Cluster #\(cluster.clusterIdentifier)\n\(children.count) children"
1034 // color = .blue
1035 // } else if let featureName = feature.attribute(forKey: "name") as? String?,
1036 // // Tapped on a port.
1037 // let portName = featureName {
1038 // description = portName
1039 // color = .black
1040 // } else {
1041 // // Tapped on a port that is missing a name.
1042 // description = "No port name"
1043 // color = .red
1044 // }
1045 //
1046 // print("description:", description)
1047 //
1048 // popup = popup(at: feature.coordinate, with: description, textColor: color)
1049 //
1050 // showPopup(true, animated: true)
1051 // }
1052
1053 // Convenience method to create a reusable popup view.
1054 private func popup(at coordinate: CLLocationCoordinate2D, with description: String, textColor: UIColor) -> UIView {
1055 let popup = UILabel()
1056
1057 popup.backgroundColor = UIColor.white.withAlphaComponent(0.9)
1058 popup.layer.cornerRadius = 4
1059 popup.layer.masksToBounds = true
1060 popup.textAlignment = .center
1061 popup.lineBreakMode = .byTruncatingTail
1062 popup.numberOfLines = 0
1063 popup.font = .systemFont(ofSize: 16)
1064 popup.textColor = textColor
1065 popup.alpha = 0
1066 popup.text = description
1067
1068 popup.sizeToFit()
1069
1070 // Expand the popup.
1071 popup.bounds = popup.bounds.insetBy(dx: -10, dy: -10)
1072 let point = mapView.convert(coordinate, toPointTo: mapView)
1073 popup.center = CGPoint(x: point.x, y: point.y - 50)
1074
1075 return popup
1076 }
1077
1078 func showPopup(_ shouldShow: Bool, animated: Bool) {
1079 guard let popup = self.popup else {
1080 return
1081 }
1082
1083 if shouldShow {
1084 view.addSubview(popup)
1085 }
1086
1087 let alpha: CGFloat = (shouldShow ? 1 : 0)
1088
1089 let animation = {
1090 popup.alpha = alpha
1091 }
1092
1093 let completion = { (_: Bool) in
1094 if !shouldShow {
1095 popup.removeFromSuperview()
1096 }
1097 }
1098
1099 if animated {
1100 UIView.animate(withDuration: 0.25, animations: animation, completion: completion)
1101 } else {
1102 animation()
1103 completion(true)
1104 }
1105 }
1106}
1107
1108extension MainController: SelectOrderTypeDelegate {
1109 func didSelectOrderType(indexPath: IndexPath) {
1110
1111 let tabBarController = self.tabBarController as! TabBarController
1112 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
1113 let targetNotch: ViewSize = .minimum
1114 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
1115
1116 mapView.removeAnnotations(mapView.annotations ?? [])
1117// orderPointView.didTapClose()
1118 switch MapTopBarItem(rawValue: indexPath.item) {
1119 case .orders: loadOrder()
1120 case .techinics: loadTech()
1121 case .snow: loadSnow()
1122 case .trash: loadDump()
1123 case .cariers: loadQuarry()
1124 case .sand: loadQuarry()
1125 default: print("Problem didSelectOrderType!")
1126 }
1127 currentTopBarItem = MapTopBarItem(rawValue: indexPath.item) ?? .orders
1128 }
1129}
1130
1131// MARK: - Internal API
1132extension MainController {
1133 func loadTech(){
1134 showSpinner()
1135 let request = SearchOrderRequest(centerLat: 55.751701, centerLon: 37.618790)
1136 SearchAPI.ce(request: request, completion: { [weak self] result in
1137 guard let strongSelf = self else { return }
1138 strongSelf.hideSpinner()
1139 switch result {
1140 case .success(let data):
1141 print("ce:", data.items)
1142 strongSelf.searchItems = data.items
1143 strongSelf.hideSpinner()
1144 strongSelf.setMapAnnotations(searchOrderItems: data.items)
1145
1146 strongSelf.showSearchController()
1147 case .failure(let error):
1148 print("SearchAPI.ce error", error.message as Any)
1149 strongSelf.showNetworkError(networkError: error)
1150 }
1151 })
1152 }
1153
1154 public func loadQuarry(){
1155 let request = SearchOrderRequest(centerLat: 55.751701, centerLon: 37.618790)
1156 showSpinner()
1157 SearchAPI.quarry(request: request, completion: { [weak self] result in
1158 guard let strongSelf = self else { return }
1159 strongSelf.hideSpinner()
1160 switch result {
1161 case .success(let data):
1162 print("quarry:", data.items)
1163 strongSelf.searchItems = data.items
1164 strongSelf.setMapAnnotations(searchOrderItems: data.items)
1165
1166 strongSelf.showSearchController()
1167 case .failure(let error):
1168 print("SearchAPI.quarry error", error.message as Any)
1169 strongSelf.showNetworkError(networkError: error)
1170 }
1171 })
1172 }
1173
1174 func loadDump(){
1175 let request = SearchOrderRequest(centerLat: 55.751701, centerLon: 37.618790)
1176 showSpinner()
1177 SearchAPI.dump(request: request, completion: { [weak self] result in
1178 guard let strongSelf = self else { return }
1179 strongSelf.hideSpinner()
1180 switch result {
1181 case .success(let data):
1182 print("dump:", data.items)
1183 strongSelf.searchItems = data.items
1184 strongSelf.setMapAnnotations(searchOrderItems: data.items)
1185
1186 strongSelf.showSearchController()
1187 case .failure(let error):
1188 print("SearchAPI.dump error", error.message as Any)
1189 strongSelf.showNetworkError(networkError: error)
1190 }
1191 })
1192
1193 }
1194
1195 func loadSnow(){
1196 let request = SearchOrderRequest(centerLat: 55.751701, centerLon: 37.618790)
1197 showSpinner()
1198 SearchAPI.snow(request: request, completion: { [weak self] result in
1199 guard let strongSelf = self else { return }
1200 strongSelf.hideSpinner()
1201 switch result {
1202 case .success(let data):
1203 print("snow:", data.items)
1204 strongSelf.searchItems = data.items
1205 strongSelf.setMapAnnotations(searchOrderItems: data.items)
1206
1207 strongSelf.showSearchController()
1208 case .failure(let error):
1209 print("SearchAPI.snow error", error.message as Any)
1210 strongSelf.showNetworkError(networkError: error)
1211 }
1212 })
1213 }
1214
1215 func loadPit(){
1216 let request = SearchOrderRequest(centerLat: 55.751701, centerLon: 37.618790)
1217 showSpinner()
1218 SearchAPI.pit(request: request, completion: { [weak self] result in
1219 guard let strongSelf = self else { return }
1220 strongSelf.hideSpinner()
1221 switch result {
1222 case .success(let data):
1223 print("pit:", data.items)
1224 strongSelf.searchItems = data.items
1225 strongSelf.setMapAnnotations(searchOrderItems: data.items)
1226
1227 strongSelf.showSearchController()
1228 case .failure(let error):
1229 print("SearchAPI.pit error", error.message as Any)
1230 strongSelf.showNetworkError(networkError: error)
1231 }
1232 })
1233 }
1234
1235 private func loadOrder() {
1236 showSpinner()
1237 let request = SearchOrderRequest(centerLat: 55.751701, centerLon: 37.618790)
1238 SearchAPI.order(request: request, completion: { [weak self] result in
1239 guard let strongSelf = self else { return }
1240 strongSelf.hideSpinner()
1241 switch result {
1242 case .success(let data):
1243 strongSelf.searchItems = data.items
1244 strongSelf.setMapAnnotations(searchOrderItems: data.items)
1245
1246 strongSelf.showSearchController()
1247 case .failure(let error):
1248 print("SearchAPI.order error", error.message as Any)
1249 strongSelf.showNetworkError(networkError: error)
1250 }
1251 })
1252 }
1253
1254 private func showSearchController() {
1255 let tabBarController = self.tabBarController as! TabBarController
1256 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
1257 let targetNotch: ViewSize = .medium
1258 overlayContainer.viewControllers.remove(at: 1)
1259 overlayContainer.searchViewController.router = router
1260 overlayContainer.viewControllers.insert(overlayContainer.searchViewController, at: 1)
1261 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
1262 }
1263}
1264
1265// MGLAnnotationView subclass
1266class CustomAnnotationView: MGLAnnotationView {
1267 override func layoutSubviews() {
1268 super.layoutSubviews()
1269
1270 // Use CALayer’s corner radius to turn this view into a circle.
1271 layer.cornerRadius = bounds.width / 2
1272 layer.borderWidth = 2
1273 layer.borderColor = UIColor.white.cgColor
1274 }
1275
1276 override func setSelected(_ selected: Bool, animated: Bool) {
1277 super.setSelected(selected, animated: animated)
1278
1279 // Animate the border width in/out, creating an iris effect.
1280 let animation = CABasicAnimation(keyPath: "borderWidth")
1281 animation.duration = 0.1
1282 layer.borderWidth = selected ? bounds.width / 4 : 2
1283 layer.add(animation, forKey: "borderWidth")
1284 }
1285}
1286
1287extension MainController: UIGestureRecognizerDelegate {
1288 public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
1289 // This will only get called for the custom double tap gesture,
1290 // that should always be recognized simultaneously.
1291 return true
1292 }
1293
1294 public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
1295 // This will only get called for the custom double tap gesture.
1296 return firstCluster(with: gestureRecognizer) != nil
1297 }
1298}
1299extension MainController: CLLocationManagerDelegate{
1300 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
1301 if let location = locations.last {
1302 manager.stopUpdatingLocation()
1303 latUser = location.coordinate.latitude
1304 lonUser = location.coordinate.longitude
1305 updateLocation()
1306 print("Found user's location: \(location)")
1307 }
1308 }
1309
1310 func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
1311 print("Failed to find user's location: \(error.localizedDescription)")
1312 }
1313}
1314
1315class CustomUserLocationAnnotationView: MGLUserLocationAnnotationView {
1316
1317}
1318
1319// MARK: - FilterControllerDelegate
1320extension MainController: FilterControllerDelegate {
1321 func didFilterItems(items: [SearchOrderItem]) {
1322 self.searchItems = items
1323 self.setMapAnnotations(searchOrderItems: items)
1324 }
1325}
1326
1327extension MainController: ShowRouteDelegate {
1328 func showRoute() {
1329 drawRouteFromAdress()
1330 }
1331}
1332
1333extension MainController: OrderPointControllerNavigationDelegate {
1334 func hideController() {
1335 let tabBarController = self.tabBarController as! TabBarController
1336 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
1337 let targetNotch: ViewSize = .minimum
1338 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
1339 }
1340}
1341
1342extension MainController: MapPopupHeaderViewDelegate {
1343 func didTapClose() {
1344 let tabBarController = self.tabBarController as! TabBarController
1345 let overlayContainer = tabBarController.viewControllers?.first as! OverlayContainer
1346 let targetNotch: ViewSize = .minimum
1347 overlayContainer.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
1348 }
1349}
1350