Commit fc0ee1ad authored by Ariba Siddiqui's avatar Ariba Siddiqui
Browse files

Comments and otehr restrucuring

parent 1377bbc9
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// LocationFinder.swift // LocationFinder.swift
// MapKit Testing Search Functionality // MapKit Testing Search Functionality
// //
// Created by Brian Porumb on 25.11.21.
//
import Foundation import Foundation
import Combine import Combine
...@@ -11,7 +9,7 @@ import MapKit ...@@ -11,7 +9,7 @@ import MapKit
class LocationService: NSObject, ObservableObject { class LocationService: NSObject, ObservableObject {
// Differnt search states // Different search states
enum LocationStatus: Equatable { enum LocationStatus: Equatable {
case idle case idle
case noResults case noResults
...@@ -37,11 +35,11 @@ class LocationService: NSObject, ObservableObject { ...@@ -37,11 +35,11 @@ class LocationService: NSObject, ObservableObject {
self.searchCompleter.delegate = self self.searchCompleter.delegate = self
// receive a stream from the queryFragment in the view // receive a stream from the queryFragment in the view
// debounce (wait) for 250miliseconds before pushing the event further // debounce (wait) for 500 milliseconds before pushing the event further
// sink returns the updated string after waiting the specified amount of time // sink returns the updated string after waiting the specified amount of time
queryCancellable = $queryFragment queryCancellable = $queryFragment
.receive(on: DispatchQueue.main) .receive(on: DispatchQueue.main)
.debounce(for: .milliseconds(250), scheduler: RunLoop.main, options: nil) .debounce(for: .milliseconds(500), scheduler: RunLoop.main, options: nil)
.sink(receiveValue: { fragment in .sink(receiveValue: { fragment in
// if fragment isn't empty then set the queryFrament to the current updated string // if fragment isn't empty then set the queryFrament to the current updated string
......
// //
// ContentView.swift // MapSearchView.swift
// MapKit Testing Search Functionality // MapKit Testing Search Functionality
// //
// Created by Brian Porumb on 25.11.21.
//
import SwiftUI import SwiftUI
......
// //
// ViewController.swift // ViewController.swift
// Location Tutorial // MapKit Routing, Annotations and Location
//
// Created by Huang on 2021/11/25.
// //
import UIKit import UIKit
...@@ -14,26 +12,31 @@ class ViewController: UIViewController { ...@@ -14,26 +12,31 @@ class ViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView! @IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager() let locationManager = CLLocationManager()
var regionInMeters: Double = 10000 //scale of the map var regionInMeters: Double = 10000 //scale of the map
// ### code for directions start ###
var directionsArray: [MKDirections] = [] var directionsArray: [MKDirections] = []
// ### code for directions end ###
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
checkLocationServices() checkLocationServices()
setupMapView() setupMapView()
} }
func setupMapView(){
mapView.delegate=self
}
func setupLocationManager() { func setupLocationManager() {
locationManager.delegate = self locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.desiredAccuracy = kCLLocationAccuracyBest
} }
// helper function to display alerts to user
func displayAlert(alertTitle: String, alertMessage: String) {
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true)
}
func centerViewOnUserLocation() { func centerViewOnUserLocation() {
if let location = locationManager.location?.coordinate { if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters) let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
...@@ -41,18 +44,18 @@ class ViewController: UIViewController { ...@@ -41,18 +44,18 @@ class ViewController: UIViewController {
} }
} }
// check if user's location services are enabled
func checkLocationServices() { func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() { if CLLocationManager.locationServicesEnabled() {
setupLocationManager() setupLocationManager()
checkLocationAuthorization() checkLocationAuthorization()
} else { } else {
// Show alert letting the user know they have to turn this on. print("Location Services are not enabled")
displayAlert(alertTitle: "Location Services are not turned on", alertMessage: "You must enable your Location Services to perform this action")
} }
} }
// checking authorization status
func checkLocationAuthorization() { func checkLocationAuthorization() {
let manager = CLLocationManager() let manager = CLLocationManager()
switch manager.authorizationStatus { switch manager.authorizationStatus {
...@@ -76,29 +79,24 @@ class ViewController: UIViewController { ...@@ -76,29 +79,24 @@ class ViewController: UIViewController {
} }
} }
// ### code for directions start ### // action triggered on the "GO" button tap
func setupMapView(){
mapView.delegate=self
}
@IBAction func goButtonTapped(_ sender: Any) { @IBAction func goButtonTapped(_ sender: Any) {
print("GO button tapped") print("GO button tapped")
getDirections() getDirections()
} }
func getLocationCoordinates() -> CLLocationCoordinate2D { //to prevent throttling and multiple renders
let cologne = MKPointAnnotation() func resetMapView(withNew directions: MKDirections) {
cologne.title = "Cologne" mapView.removeOverlays(mapView.overlays)
cologne.coordinate = CLLocationCoordinate2D(latitude: 50.9375, longitude: 6.9603) directionsArray.append(directions)
mapView.addAnnotation(cologne) let _ = directionsArray.map { $0.cancel() }
return cologne.coordinate //hard coded coordinates for Cologne
} }
// main function for routing
func getDirections() { func getDirections() {
guard let location = locationManager.location?.coordinate else { guard let location = locationManager.location?.coordinate else {
//TODO: Inform user we don't have their current location print("Location not found")
displayAlert(alertTitle: "Location not found", alertMessage: "App cannot access your location")
return return
} }
...@@ -107,12 +105,21 @@ class ViewController: UIViewController { ...@@ -107,12 +105,21 @@ class ViewController: UIViewController {
resetMapView(withNew: directions) resetMapView(withNew: directions)
directions.calculate { [unowned self] (response, error) in directions.calculate { [unowned self] (response, error) in
//TODO: Handle error if needed if error != nil {
guard let response = response else { return } //TODO: Show response not available in an alert print("Directions couldn't be computed")
displayAlert(alertTitle: "Directions couldn't be computed", alertMessage: "App cannot find directions to the destination")
return
}
guard let response = response else {
print("Response not found")
displayAlert(alertTitle: "Directions couldn't be computed", alertMessage: "App cannot find directions to the destination")
return
}
print("total routes found: \(response.routes.count)") print("total routes found: \(response.routes.count)")
for route in response.routes { for route in response.routes {
self.mapView.addOverlay(route.polyline, level: .aboveRoads) self.mapView.addOverlay(route.polyline, level: .aboveRoads) //add an overlay for each route
var directionsRegion: MKCoordinateRegion = MKCoordinateRegion.init(route.polyline.boundingMapRect) //polyline: connected line segments that don't form a loop
var directionsRegion: MKCoordinateRegion = MKCoordinateRegion.init(route.polyline.boundingMapRect) // recenter
//to increase the span of the region in order to add some margin //to increase the span of the region in order to add some margin
directionsRegion.span.latitudeDelta *= 1.2 directionsRegion.span.latitudeDelta *= 1.2
directionsRegion.span.longitudeDelta *= 1.2 directionsRegion.span.longitudeDelta *= 1.2
...@@ -121,31 +128,30 @@ class ViewController: UIViewController { ...@@ -121,31 +128,30 @@ class ViewController: UIViewController {
} }
} }
// creates a new request by configuring different properties
func createDirectionsRequest(from coordinate: CLLocationCoordinate2D) -> MKDirections.Request { func createDirectionsRequest(from coordinate: CLLocationCoordinate2D) -> MKDirections.Request {
let destinationCoordinate = getLocationCoordinates() let destinationCoordinate = getLocationCoordinates()
let startingLocation = MKPlacemark(coordinate: coordinate) //user's location let startingLocation = MKPlacemark(coordinate: coordinate) //user's location
let destination = MKPlacemark(coordinate: destinationCoordinate) let destination = MKPlacemark(coordinate: destinationCoordinate)
let request = MKDirections.Request() let request = MKDirections.Request()
request.source = MKMapItem(placemark: startingLocation) request.source = MKMapItem(placemark: startingLocation)
request.destination = MKMapItem(placemark: destination) request.destination = MKMapItem(placemark: destination)
request.transportType = .automobile request.transportType = .automobile
request.requestsAlternateRoutes = true request.requestsAlternateRoutes = true
return request return request
} }
//to prevent throttling and multiple renders // hard-coded to return coordinates of Southampton
func resetMapView(withNew directions: MKDirections) { func getLocationCoordinates() -> CLLocationCoordinate2D {
mapView.removeOverlays(mapView.overlays) let southampton = MKPointAnnotation()
directionsArray.append(directions) southampton.title = "Southampton"
let _ = directionsArray.map { $0.cancel() } southampton.coordinate = CLLocationCoordinate2D(latitude: 50.9097, longitude: -1.4044)
mapView.addAnnotation(southampton) // add annotation(a pin) for Southampton
return southampton.coordinate
} }
// ### code for directions end ###
} }
extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate { extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
...@@ -158,7 +164,8 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate { ...@@ -158,7 +164,8 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
checkLocationAuthorization() checkLocationAuthorization()
} }
// ### code for directions start ### // called each time the bounding map rectangle of an overlay intersects the visible region of a map
// defines 'how' the overlay should look like -> renderer properties are specified here
func mapView(_ mapView: MKMapView, func mapView(_ mapView: MKMapView,
rendererFor overlay: MKOverlay) -> MKOverlayRenderer { rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay) let renderer = MKPolylineRenderer(overlay: overlay)
...@@ -168,22 +175,22 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate { ...@@ -168,22 +175,22 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
return renderer return renderer
} }
// Delegate method for annotations
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard annotation is MKPointAnnotation else { return nil } guard annotation is MKPointAnnotation else { return nil }
let identifier = "Annotation" let identifier = "Annotation"
// dequeue an existing annotation view before creating a new one as new annotations move on-screen
// (performance enhancement)
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil { if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true annotationView!.canShowCallout = true
} else { } else {
annotationView!.annotation = annotation annotationView!.annotation = annotation
} }
return annotationView return annotationView
} }
// ### code for directions end ###
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment