-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Starting on Coder integration and setting up proper swift error type
- Loading branch information
Jerrad Thramer
authored and
Jerrad Thramer
committed
Oct 1, 2019
1 parent
d2d54fc
commit 9e7e860
Showing
14 changed files
with
1,247 additions
and
785 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import Foundation | ||
import CoreLocation | ||
|
||
|
||
public enum DirectionsError: RawRepresentable { | ||
public init?(rawValue: String) { | ||
assertionFailure("Do not use init(rawValue:) for DirectionsError.") | ||
return nil | ||
} | ||
|
||
public var rawValue: String { | ||
return """ | ||
Error: \(String(describing: self)) | ||
Failure Reason: \(failureReason) | ||
Recovery Suggestion: \(recoverySuggestion) | ||
""" | ||
} | ||
public var failureReason: String { | ||
switch self { | ||
case .noData: | ||
return "No data was returned from the server." | ||
case .unableToRoute: | ||
return "No route could be found between the specified locations." | ||
case .unableToLocate: | ||
return "A specified location could not be associated with a roadway or pathway." | ||
case .profileNotFound: | ||
return "Unrecognized profile identifier." | ||
case .requestTooLarge: | ||
return "The request is too large." | ||
case let .rateLimited(rateLimitInterval: interval, rateLimit: limit, _): | ||
let intervalFormatter = DateComponentsFormatter() | ||
intervalFormatter.unitsStyle = .full | ||
guard let interval = interval, let limit = limit else { | ||
return "Too many requests." | ||
} | ||
let formattedInterval = intervalFormatter.string(from: interval) ?? "\(interval) seconds" | ||
let formattedCount = NumberFormatter.localizedString(from: NSNumber(value: limit), number: .decimal) | ||
return "More than \(formattedCount) requests have been made with this access token within a period of \(formattedInterval)" | ||
case let .unknown(response: response, underlying: error): | ||
return "Unknown Error. Response: \(response.debugDescription) Underlying Error: \(error.debugDescription)" | ||
|
||
} | ||
} | ||
|
||
public var recoverySuggestion: String { | ||
switch self { | ||
case .noData: | ||
return "Make sure you have an active internet connection." | ||
case .unableToRoute: | ||
return "Make sure it is possible to travel between the locations with the mode of transportation implied by the profileIdentifier option. For example, it is impossible to travel by car from one continent to another without either a land bridge or a ferry connection." | ||
case .unableToLocate: | ||
return "Make sure the locations are close enough to a roadway or pathway. Try setting the coordinateAccuracy property of all the waypoints to a negative value." | ||
case .profileNotFound: | ||
return "Make sure the profileIdentifier option is set to one of the provided constants, such as MBDirectionsProfileIdentifierAutomobile." | ||
case .requestTooLarge: | ||
return "Try specifying fewer waypoints or giving the waypoints shorter names." | ||
case let .rateLimited(rateLimitInterval: _, rateLimit: _, resetTime: reset): | ||
guard let reset = reset else { | ||
return "Wait a little while before retrying." | ||
} | ||
let formattedDate: String = DateFormatter.localizedString(from: reset, dateStyle: .long, timeStyle: .long) | ||
return "Wait until \(formattedDate) before retrying." | ||
case .unknown(_,_): | ||
return "Please contact Mapbox Support." | ||
} | ||
} | ||
public typealias RawValue = String | ||
|
||
|
||
case noData | ||
case unableToRoute | ||
case unableToLocate | ||
case profileNotFound | ||
case requestTooLarge | ||
case rateLimited(rateLimitInterval: TimeInterval?, rateLimit: UInt?, resetTime: Date?) | ||
case unknown(response: URLResponse?, underlying: Error?) | ||
|
||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import Foundation | ||
|
||
struct DirectionsResponse: Codable { | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case code | ||
case message | ||
case error | ||
case uuid | ||
case routes | ||
case waypoints | ||
} | ||
|
||
var code: String? | ||
var message: String? | ||
var error: String? | ||
let uuid: String? | ||
let routes: [Route]? | ||
let waypoints: [Waypoint]? | ||
|
||
init(code: String?, message: String?, error: String?) { | ||
self.code = code | ||
self.message = message | ||
self.error = error | ||
self.uuid = nil | ||
self.routes = nil | ||
self.waypoints = nil | ||
} | ||
|
||
init(from decoder: Decoder) throws { | ||
let container = try decoder.container(keyedBy: CodingKeys.self) | ||
|
||
let uuid = try container.decodeIfPresent(String.self, forKey: .uuid) | ||
self.uuid = uuid | ||
|
||
let waypoints = try container.decodeIfPresent([Waypoint].self, forKey: .waypoints) | ||
self.waypoints = waypoints | ||
|
||
let rawRoutes = try container.decodeIfPresent([Route].self, forKey: .routes) | ||
var routesWithDestinations: [Route]? = rawRoutes | ||
if let destinations = waypoints?.dropFirst() { | ||
routesWithDestinations = rawRoutes?.map({ (route) -> Route in | ||
for (leg, destination) in zip(route.legs, destinations) { | ||
if leg.destination?.name?.nonEmptyString == nil { | ||
leg.destination = destination | ||
} | ||
} | ||
return route | ||
}) | ||
} | ||
|
||
let routesWithIdentifiers = routesWithDestinations?.map({ (route) -> Route in | ||
route.routeIdentifier = uuid | ||
return route | ||
}) | ||
|
||
self.routes = routesWithIdentifiers | ||
|
||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import Foundation | ||
import Polyline | ||
import CoreLocation | ||
|
||
|
||
extension Decodable { | ||
static internal func from<T: Decodable>(json: String, using encoding: String.Encoding = .utf8) -> T? { | ||
guard let data = json.data(using: encoding) else { return nil } | ||
return from(data: data) as T? | ||
} | ||
|
||
static internal func from<T: Decodable>(data: Data) -> T? { | ||
let decoder = JSONDecoder() | ||
return try! decoder.decode(T.self, from: data) as T? | ||
} | ||
} | ||
|
||
struct UncertainCodable<T: Codable, U: Codable>: Codable { | ||
var t: T? | ||
var u: U? | ||
|
||
var value: Codable? { | ||
return t ?? u | ||
} | ||
|
||
var coordinates: [CLLocationCoordinate2D] { | ||
if let geo = value as? Geometry { | ||
return geo.coordinates | ||
} else if let geo = value as? String { | ||
return decodePolyline(geo, precision: 1e5)! | ||
} else { | ||
return [] | ||
} | ||
} | ||
|
||
init(from decoder: Decoder) throws { | ||
let container = try decoder.singleValueContainer() | ||
t = try? container.decode(T.self) | ||
if t == nil { | ||
u = try? container.decode(U.self) | ||
} | ||
} | ||
|
||
func encode(to encoder: Encoder) throws { | ||
var container = encoder.singleValueContainer() | ||
if let t = t { | ||
try? container.encode(t) | ||
} | ||
if let u = u { | ||
try? container.encode(u) | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import Foundation | ||
import CoreLocation | ||
|
||
extension CLLocationCoordinate2D: Codable { | ||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.unkeyedContainer() | ||
try container.encode(longitude) | ||
try container.encode(latitude) | ||
} | ||
|
||
public init(from decoder: Decoder) throws { | ||
var container = try decoder.unkeyedContainer() | ||
longitude = try container.decode(CLLocationDegrees.self) | ||
latitude = try container.decode(CLLocationDegrees.self) | ||
} | ||
|
||
static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool { | ||
return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude | ||
} | ||
} | ||
|
||
extension CLLocation { | ||
/** | ||
Initializes a CLLocation object with the given coordinate pair. | ||
*/ | ||
internal convenience init(coordinate: CLLocationCoordinate2D) { | ||
self.init(latitude: coordinate.latitude, longitude: coordinate.longitude) | ||
} | ||
} |
Oops, something went wrong.