Giter Site home page Giter Site logo

coffeequest's Introduction

CoffeeQuest

Run app

1. Refister(※Use Safari) And Get yelp Api Key

https://www.yelp.com/developers/v3/manage_app

2. Set api key

https://github.com/YamamotoDesu/CoffeeQuest/blob/main/CoffeeQuest/Resources/APIKeys.swift

3. Delete Podfile.lock

rm Podfile.lock 

4. Update cocoapods

pod deintegrate && pod install

5. Set Location on iOS Simulator

Under the Debug menu in the Simulator, Choose "Custom Location".
Set latitude and longitude.
location: Shinjuku
longitude: 139.710007
latitude: 35.685001

Code Example

BusinessMapViewModel

import UIKit
import MapKit

public class BusinessMapViewModel: NSObject {
  
  // MARK: - Properties
  public let coordinate: CLLocationCoordinate2D
  public let name: String
  public let rating: Double
  
  public let image: UIImage
  public let ratingDescription: String
  
  // MARK: - Object Lifecycle
  public init(coordinate: CLLocationCoordinate2D,
              name: String,
              rating: Double,
              image: UIImage) {
    self.coordinate = coordinate
    self.name = name
    self.rating = rating
    self.image = image
    self.ratingDescription = "\(rating) stars"
  }
}

// MARK: - MKAnnotation
extension BusinessMapViewModel: MKAnnotation {
  
  public var title: String? {
    return name
  }
  
  public var subtitle: String? {
    return ratingDescription
  }
}

AnnotationFactory

import MapKit
import YelpAPI

public class AnnotationFactory {
  public func createBusinessMapViewModel(for business: Business) -> BusinessMapViewModel {
    let coordinate = business.location
    let name = business.name
    let rating = business.rating
    let image: UIImage
    switch rating {
    case 0.0..<3.0: image = UIImage(named: "terrible")!
    case 3.0..<3.5:  image = UIImage(named: "bad")!
    case 3.5..<4.0: image = UIImage(named: "meh")!
    case 4.0..<4.75: image = UIImage(named: "good")!
    case 4.75...5.0: image = UIImage(named: "great")!
    default: image = UIImage(named: "bad")!
    }
    return BusinessMapViewModel(coordinate: coordinate,
                                name: name,
                                rating: rating,
                                image: image)
  }
}

Protocol

BusinessSearchClient

public protocol BusinessSearchClient {
  func search(with coordinate: CLLocationCoordinate2D,
              term: String,
              limit: UInt,
              offset: UInt,
              success: @escaping (([Business]) -> Void),
              failure: @escaping ((Error?) -> Void))
}

Model

Business

import MapKit

public struct Business {
  var name: String
  var rating: Double
  var location: CLLocationCoordinate2D
}

YLPClient+2BBusinessSerachClient

import MapKit
import YelpAPI

extension YLPClient: BusinessSearchClient {
  public func search(with coordinate: CLLocationCoordinate2D,
                     term: String,
                     limit: UInt,
                     offset: UInt,
                     success: @escaping (([Business]) -> Void),
                     failure: @escaping ((Error?) -> Void)) {
    let yelpCoordinate = YLPCoordinate(latitude: coordinate.latitude,
                                       longitude: coordinate.longitude)
    search(with: yelpCoordinate,
           term: term,
           limit: limit,
           offset: offset,
           sort: .bestMatched) { (searchResult, error) in
            guard let searchResult = searchResult, error == nil else {
              failure(error)
              return
            }
            let businesses = searchResult.businesses.adaptToBusinesses()
            success(businesses)
    }
  }
}

extension Array where Element: YLPBusiness {
  func adaptToBusinesses() -> [Business] {
    return compactMap { yelpBusiness in
      guard let yelpCoordinate = yelpBusiness.location.coordinate else {
        return nil
      }
      let coordinate = CLLocationCoordinate2D(latitude: yelpCoordinate.latitude,
                                              longitude: yelpCoordinate.longitude)
      return Business(name: yelpBusiness.name,
                      rating: yelpBusiness.rating,
                      location: coordinate)
    }
  }
}

Controller

ViewController

import MapKit
import YelpAPI

public class ViewController: UIViewController {
  
  // MARK: - Properties
  public let annotationFactory = AnnotationFactory()
  private var businesses: [Business] = []
  public var client: BusinessSearchClient = YLPClient(apiKey: YelpAPIKey)
  private let locationManager = CLLocationManager()
  
  // MARK: - Outlets
  @IBOutlet public var mapView: MKMapView! {
    didSet {
      mapView.showsUserLocation = true
    }
  }
  
  // MARK: - View Lifecycle
  public override func viewDidLoad() {
    super.viewDidLoad()
    DispatchQueue.main.async { [weak self] in
      self?.locationManager.requestWhenInUseAuthorization()
    }
  }
  
  // MARK: - Actions
  @IBAction func businessFilterToggleChanged(_ sender: UISwitch) {
    
  }
}

// MARK: - MKMapViewDelegate
extension ViewController: MKMapViewDelegate {
  
  public func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
    centerMap(on: userLocation.coordinate)
  }
  
  private func centerMap(on coordinate: CLLocationCoordinate2D) {
    let regionRadius: CLLocationDistance = 3000
    let coordinateRegion = MKCoordinateRegion(center: coordinate,
                                              latitudinalMeters: regionRadius,
                                              longitudinalMeters: regionRadius)
    mapView.setRegion(coordinateRegion, animated: true)
    searchForBusinesses()
  }
  
  private func searchForBusinesses() {
    client.search(with: mapView.userLocation.coordinate,
                  term: "coffee",
                  limit: 35,
                  offset: 0,
                  success: { [weak self] (businesses) in
                    guard let self = self else { return }
                    self.businesses = businesses
                    DispatchQueue.main.async {
                      self.addAnnotations()
                    }
    }, failure: { error in
      print("Search failed: \(String(describing: error))")
    })
  }
  
  private func addAnnotations() {
    for business in businesses {
      let viewModel = annotationFactory.createBusinessMapViewModel(for: business)
      mapView.addAnnotation(viewModel)
    }
  }
  
  public func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    guard let viewModel = annotation as? BusinessMapViewModel else { return nil }
    let identifier = "business"
    let annotationView: MKAnnotationView
    if let existingView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) {
      annotationView = existingView
    } else {
      annotationView = MKAnnotationView(annotation: viewModel, reuseIdentifier: identifier)
    }
    annotationView.image = viewModel.image
    annotationView.canShowCallout = true
    return annotationView
  }
}

coffeequest's People

Contributors

japanesedesu avatar yamamotodesu avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.