Skip to content

Instantly share code, notes, and snippets.

@NeilsUltimateLab
Last active February 3, 2019 08:15
Show Gist options
  • Select an option

  • Save NeilsUltimateLab/682da922b31f186b33412de0dee8ba79 to your computer and use it in GitHub Desktop.

Select an option

Save NeilsUltimateLab/682da922b31f186b33412de0dee8ba79 to your computer and use it in GitHub Desktop.
Generate URL with type-safe way for /Google maps.
import Foundation
import CoreLocation
extension Int {
func queryItem(for name: String) -> URLQueryItem {
return URLQueryItem(name: name, value: "\(self)")
}
}
extension String {
func queryItem(for name: String) -> URLQueryItem {
return URLQueryItem(name: name, value: self)
}
}
extension Float {
func queryItem(for name: String) -> URLQueryItem {
return URLQueryItem(name: name, value: "\(self)")
}
}
extension Bool {
func queryItem(for name: String) -> URLQueryItem {
return URLQueryItem(name: name, value: "\(self)")
}
}
extension CLLocationCoordinate2D {
func queryItem(for name: String) -> URLQueryItem {
return URLQueryItem(name: name, value: "\(self.latitude),\(self.longitude)")
}
func distance(from destinationCoords: CLLocationCoordinate2D) -> CLLocationDistance {
let destination = CLLocation(latitude: destinationCoords.latitude, longitude: destinationCoords.longitude)
let source = CLLocation(latitude: self.latitude, longitude: self.longitude)
return source.distance(from: destination)
}
}
struct AppleMapURLGenerator {
/// The map type.
/// If you don’t specify one of the documented values,
/// the current map type is used.
enum MapType: String {
case standardView = "m"
case satelliteView = "k"
case hybridView = "h"
case transitView = "r"
var queryItem: URLQueryItem {
return URLQueryItem(name: "t", value: self.rawValue)
}
}
/// The transport type.
/// A complete directions request includes the `"saddr"`, `"daddr"`, and `"dirflg"` parameters,
/// but only the `"daddr"` parameter is required.
///
/// If you don’t specify one of the documented transport type values,
/// the `"dirflg"` parameter is ignored;
///
/// if you don’t specify any value,
/// Maps uses the user’s preferred transport type or the previous setting.
enum TransportType: String {
case byCar = "d"
case byFoot = "w"
case byPublicTrasit = "r"
var queryItem: URLQueryItem {
return self.rawValue.queryItem(for: "dirflg")
}
}
/// The zoom level.
///
/// You can use the z parameter only when you also use the `"sll"` parameter;
///
/// in particular, you can’t use "z" in combination with the `"spn"` or `"sspn"` parameters.
enum ZoomType {
/// Zoom level should be in range of 2 to 21
case zoom(Float?)
case span(CLLocationCoordinate2D?)
var queryItem: URLQueryItem? {
switch self {
case .zoom(let floats):
if let float = floats {
return float.queryItem(for: "z")
}
return nil
case .span(let location):
if let propertLocation = location {
return propertLocation.queryItem(for: "spn")
}
return nil
}
}
}
enum AddressType {
case coords(CLLocationCoordinate2D?)
case string(String?)
func queryItem(for key: String) -> URLQueryItem? {
switch self {
case .coords(let coords):
return coords?.queryItem(for: key)
case .string(let query):
return query?.queryItem(for: key)
}
}
}
let mapURLScheme = "https"
let mapURLHost = "maps.apple.com"
var mapType: MapType?
/// The query.
///
/// This parameter is treated as if its value had been typed into the Maps search field by the user.
///
/// Note that q=* is not supported
///
/// The q parameter can also be used as a label
/// if the location is explicitly defined in the ll or address parameters.
var query: String?
/// The address.
///
/// Using the address parameter simply displays the specified location,
/// it does not perform a search for the location.
var address: String?
/// A hint used during search.
///
/// If the sll parameter is missing or its value is incomplete,
/// the value of near is used instead.
var nearLatLong: CLLocationCoordinate2D?
/// The location around which the map should be centered.
///
/// The ll parameter can also represent a pin location
/// when you use the q parameter to specify a name.
var centeredLocation: CLLocationCoordinate2D?
/// The zoom level.
///
/// You can use the z parameter only when you also use the sll parameter;
///
/// in particular, you can’t use z in combination with the spn or sspn parameters.
var zoom: ZoomType?
/// The source address to be used as the starting point for directions.
///
/// A complete directions request includes the `saddr`, `daddr`, and `dirflg` parameters,
/// but only the `daddr` parameter is required.
///
/// If you don’t specify a value for `saddr`, the starting point is “here.”
var sourceAddress: AddressType?
/// The destination address to be used as the destination point for directions.
///
/// A complete directions request includes the `saddr`, `daddr`, and `dirflg` parameters,
/// but only the `daddr` parameter is required.
var destinationAddress: AddressType?
/// The transport type.
///
/// A complete directions request includes the `saddr`, `daddr`, and `dirflg` parameters, but only the `daddr` parameter is required.
///
/// If you don’t specify one of the documented transport type values,
/// the dirflg parameter is ignored;
///
/// if you don’t specify any value,
/// Maps uses the user’s preferred transport type or the previous setting.
var transportType: TransportType?
/// The search location.
///
/// You can specify the sll parameter by itself or in combination with the q parameter.
///
/// For example,
/// ```
/// http://maps.apple.com/?sll=50.894967,4.341626&z=10&t=s
/// ```
/// is a valid query.
var sourceLocation: CLLocationCoordinate2D?
/// The screen span.
///
/// Use the sspn parameter to specify a span around the search location specified by
/// the `sll` parameter.
var screenSpan: CLLocationCoordinate2D?
var queryItems: [URLQueryItem]? {
var items: [URLQueryItem] = []
if let mapType = self.mapType {
items.append(mapType.queryItem)
}
if let queryString = self.query {
items.append(queryString.queryItem(for: "q"))
}
if let address = self.address {
items.append(address.queryItem(for: "address"))
}
if let near = self.nearLatLong {
items.append(near.queryItem(for: "near"))
}
if let pinLocation = self.centeredLocation {
items.append(pinLocation.queryItem(for: "ll"))
}
if let zoomQuery = self.zoom?.queryItem {
items.append(zoomQuery)
}
if let queryItem = self.sourceAddress?.queryItem(for: "saddr") {
items.append(queryItem)
}
if let queryItem = self.destinationAddress?.queryItem(for: "daddr") {
items.append(queryItem)
}
if let transportQuery = self.transportType?.queryItem {
items.append(transportQuery)
}
if let sourceLoc = self.sourceLocation {
items.append(sourceLoc.queryItem(for: "sll"))
}
if let screenSpan = self.screenSpan {
items.append(screenSpan.queryItem(for: "sspn"))
}
return items
}
var url: URL? {
var component = URLComponents()
component.scheme = mapURLScheme
component.host = mapURLHost
component.path = "/"
component.queryItems = self.queryItems
return component.url
}
}
import Foundation
import CoreLocation
struct GoogleMapURLGenerator {
/// Turns specific views on/off.
enum MapType: String {
case satellite
case traffic
case transit
var queryItem: URLQueryItem {
return URLQueryItem(name: "views", value: self.rawValue)
}
}
/// Sets the kind of map shown.
enum MapMode: String {
case standard
case streetView = "streetview"
var queryItem: URLQueryItem {
return URLQueryItem(name: "mapmode", value: self.rawValue)
}
}
enum DirectionMode: String {
case driving
case transit
case bicycling
case walking
var queryItem: URLQueryItem {
return URLQueryItem(name: "directionsmode", value: self.rawValue)
}
}
enum AddressType {
case coords(CLLocationCoordinate2D?)
case string(String?)
func queryItem(for key: String) -> URLQueryItem? {
switch self {
case .coords(let coords):
return coords?.queryItem(for: key)
case .string(let query):
return query?.queryItem(for: key)
}
}
}
let urlScheme = "comgooglemaps"
let path = ""
// Display
/// This is the map viewport center point.
///
/// Formatted as a comma separated string of latitude,longitude.
var center: CLLocationCoordinate2D?
/// Specifies the zoom level of the map.
var zoom: Float?
/// Turns specific views on/off.
///
/// Can be set to: `satellite`, `traffic`, or `transit`.
///
/// Multiple values can be set using a comma-separator.
///
/// If the parameter is specified with no value,
/// then it will clear all views.
var mapType: MapType?
/// Sets the kind of map shown.
///
/// Can be set to: standard or streetview.
///
/// If not specified, the current application settings will be used.
var mapMode: MapMode?
// Search
/// The query string for your search.
var query: String?
// Display Directions
/// Sets the starting point for directions searches.
///
/// This can be a `latitude`, `longitude` or a query formatted address.
///
/// If it is a query string that returns more than one result,
/// the first result will be selected.
///
/// If the value is left blank,
/// then the user’s current location will be used.
var sourceAddress: AddressType?
/// Sets the end point for directions searches.
///
/// Has the same format and behavior as saddr.
var destinationAddress: AddressType?
/// Method of transportation.
///
/// Can be set to: `driving`, `transit`, `bicycling` or `walking`.
var directionMode: DirectionMode?
var queryItems: [URLQueryItem] {
var items = [URLQueryItem]()
if let center = self.center {
items.append(center.queryItem(for: "center"))
}
if let zoom = self.zoom {
items.append(zoom.queryItem(for: "zoom"))
}
if let mapTypeQuery = self.mapType?.queryItem {
items.append(mapTypeQuery)
}
if let mapModeQuery = self.mapMode?.queryItem {
items.append(mapModeQuery)
}
if let query = self.query {
items.append(query.queryItem(for: "q"))
}
if let queryItem = self.sourceAddress?.queryItem(for: "saddr") {
items.append(queryItem)
}
if let queryItem = self.destinationAddress?.queryItem(for: "daddr") {
items.append(queryItem)
}
if let directionModeQuery = self.directionMode?.queryItem {
items.append(directionModeQuery)
}
return items
}
var url: URL? {
var urlComponents = URLComponents()
urlComponents.scheme = urlScheme
urlComponents.host = ""
urlComponents.path = path
urlComponents.queryItems = self.queryItems
return urlComponents.url
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment