Skip to content

Commit

Permalink
Merge pull request #267 from IFTTT/bugfix/duplicate_region_identifier…
Browse files Browse the repository at this point in the history
…_fix

Region registration fixes
  • Loading branch information
ssathy2 committed Mar 10, 2021
2 parents 6e12071 + a0be09b commit 8fa7e53
Show file tree
Hide file tree
Showing 9 changed files with 708 additions and 18 deletions.
9 changes: 8 additions & 1 deletion Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
DE01068022D54D5E00B2CB47 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE01067622D54D5E00B2CB47 /* SettingsViewController.swift */; };
DE3BF62E2576E1B300F12D24 /* UIView+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3BF62D2576E1B300F12D24 /* UIView+Helpers.swift */; };
DE3BF6312576E1DA00F12D24 /* UIImageView+NetworkLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3BF6302576E1DA00F12D24 /* UIImageView+NetworkLoading.swift */; };
DE717A5A25F7C5C4002A00C6 /* AddressUpdateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE717A5925F7C5C4002A00C6 /* AddressUpdateViewController.swift */; };
DE717A5D25F7C9B7002A00C6 /* AddressSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE717A5C25F7C9B7002A00C6 /* AddressSelectionViewController.swift */; };
DE8839DD25769AB000D76161 /* DisplayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8839D925769A7B00D76161 /* DisplayViewController.swift */; };
/* End PBXBuildFile section */

Expand All @@ -38,6 +40,8 @@
DE01067622D54D5E00B2CB47 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
DE3BF62D2576E1B300F12D24 /* UIView+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Helpers.swift"; sourceTree = "<group>"; };
DE3BF6302576E1DA00F12D24 /* UIImageView+NetworkLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+NetworkLoading.swift"; sourceTree = "<group>"; };
DE717A5925F7C5C4002A00C6 /* AddressUpdateViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressUpdateViewController.swift; sourceTree = "<group>"; };
DE717A5C25F7C9B7002A00C6 /* AddressSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressSelectionViewController.swift; sourceTree = "<group>"; };
DE7B730B22CAACD8000F4023 /* Grocery Express.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Grocery Express.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DE8839D925769A7B00D76161 /* DisplayViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -79,6 +83,8 @@
DE01067622D54D5E00B2CB47 /* SettingsViewController.swift */,
DE3BF62D2576E1B300F12D24 /* UIView+Helpers.swift */,
DE3BF6302576E1DA00F12D24 /* UIImageView+NetworkLoading.swift */,
DE717A5925F7C5C4002A00C6 /* AddressUpdateViewController.swift */,
DE717A5C25F7C9B7002A00C6 /* AddressSelectionViewController.swift */,
);
path = GroceryExpress;
sourceTree = "<group>";
Expand Down Expand Up @@ -224,13 +230,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DE717A5A25F7C5C4002A00C6 /* AddressUpdateViewController.swift in Sources */,
DE01067822D54D5E00B2CB47 /* ConnectionCredentials.swift in Sources */,
DE8839DD25769AB000D76161 /* DisplayViewController.swift in Sources */,
DE3BF6312576E1DA00F12D24 /* UIImageView+NetworkLoading.swift in Sources */,
DE01067722D54D5E00B2CB47 /* TokenRequest.swift in Sources */,
DE01067D22D54D5E00B2CB47 /* Settings.swift in Sources */,
DE01067E22D54D5E00B2CB47 /* AppDelegate.swift in Sources */,
DE01067C22D54D5E00B2CB47 /* ConnectionViewController.swift in Sources */,
DE717A5D25F7C9B7002A00C6 /* AddressSelectionViewController.swift in Sources */,
DE3BF62E2576E1B300F12D24 /* UIView+Helpers.swift in Sources */,
DE01068022D54D5E00B2CB47 /* SettingsViewController.swift in Sources */,
);
Expand Down Expand Up @@ -384,7 +392,6 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.ifttt.sdk.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "SDK Example Dev";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
Expand Down
195 changes: 195 additions & 0 deletions Examples/GroceryExpress/AddressSelectionViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
//
// AddressSelectionViewController.swift
// Grocery Express
//
// Copyright © 2021 IFTTT. All rights reserved.
//

import Foundation
import UIKit
import MapKit
import Contacts

/// Displays a map and a textfield to search for locations.
final class AddressSelectionViewController: UIViewController {

/// The result of the search
struct Result {
let placemark: MKPlacemark
let formattedAddress: String
}

// MARK: - Public
var onAddressSelect: ((Result) -> Void)?

// MARK: - Private IBOutlets
@IBOutlet private weak var mapView: MKMapView!

// MARK: - Private variables
private var resultSearchController: UISearchController? = nil
private let locationManager = CLLocationManager()
private var selectedItem: Result? = nil

static func instantiate() -> AddressSelectionViewController {
guard let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AddressSelectionViewController") as? AddressSelectionViewController else {
fatalError("Missing view controller with identifier AddressSelectionViewController in Main storyboard.")
}
return viewController
}

override func viewDidLoad() {
super.viewDidLoad()

locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()

let locationSearchTable = LocationSearchTableViewController()
locationSearchTable.delegate = self
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable

if let searchBar = resultSearchController?.searchBar {
searchBar.sizeToFit()
searchBar.placeholder = "Enter a place"
navigationItem.titleView = searchBar
}

resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.dimsBackgroundDuringPresentation = true
definesPresentationContext = true

let continueButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
navigationItem.rightBarButtonItem = continueButton
continueButton.isEnabled = false
}

@objc func doneTapped() {
guard let selectedItem = selectedItem else { return }
onAddressSelect?(selectedItem)
}
}

extension AddressSelectionViewController: LocationSearchSelectable {
func didSelect(_ placemark: MKPlacemark, formattedAddress: String) {
dismiss(animated: true, completion: { [weak self] in
guard let self = self else { return }

self.navigationItem.rightBarButtonItem?.isEnabled = true
self.selectedItem = .init(placemark: placemark, formattedAddress: formattedAddress)
self.mapView.removeAnnotations(self.mapView.annotations)
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let city = placemark.locality,
let state = placemark.administrativeArea {
annotation.subtitle = "\(city) \(state)"
}
self.mapView.addAnnotation(annotation)
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: placemark.coordinate, span: span)
self.mapView.setRegion(region, animated: true)
})
}
}

protocol LocationSearchSelectable: class {
func didSelect(_ placemark: MKPlacemark, formattedAddress: String)
}

class LocationSearchTableViewController : UITableViewController {

var delegate: LocationSearchSelectable?

private var selectedRegion: MKCoordinateRegion = .init()
private var items: [MKMapItem] = []
private var postalAddressFormatter = CNPostalAddressFormatter()
private var currentSearch: MKLocalSearch? = nil

override func viewDidLoad() {
super.viewDidLoad()
postalAddressFormatter.style = .mailingAddress
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
}

extension LocationSearchTableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
guard let searchBarText = searchController.searchBar.text else { return }
currentSearch?.cancel()

let request = MKLocalSearch.Request()
request.naturalLanguageQuery = searchBarText
request.region = selectedRegion
currentSearch = MKLocalSearch(request: request)
currentSearch?.start { response, _ in
guard let response = response else {
return
}
self.items = response.mapItems
self.tableView.reloadData()
}
}
}

extension LocationSearchTableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if cell.detailTextLabel == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
}

let item = items[indexPath.row]
let selectedItem = item.placemark
cell.textLabel?.text = selectedItem.name

var addressString = ""

if #available(iOS 11.0, *) {
if let postalAddress = selectedItem.postalAddress {
addressString = postalAddressFormatter.string(from: postalAddress)
}
} else {
// Fallback on earlier versions
}
cell.detailTextLabel?.text = addressString
return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedItem = items[indexPath.row].placemark

var formattedAddress = ""
if #available(iOS 11.0, *) {
if let postalAddress = selectedItem.postalAddress {
formattedAddress = postalAddressFormatter.string(from: postalAddress)
}
}
delegate?.didSelect(selectedItem, formattedAddress: formattedAddress)
}
}

extension AddressSelectionViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
}
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.setRegion(region, animated: true)
}
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Manager failed with error: \(error)")
}
}
Loading

0 comments on commit 8fa7e53

Please sign in to comment.