Last active
February 3, 2019 08:15
-
-
Save NeilsUltimateLab/682da922b31f186b33412de0dee8ba79 to your computer and use it in GitHub Desktop.
Generate URL with type-safe way for /Google maps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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