Files
wristcode/watch/WristCode/API/Route.swift
T

67 lines
2.4 KiB
Swift

// Screens the app can open, and the `wristcode://` URLs the complication uses to open them.
import Foundation
enum Route: Hashable, Sendable {
case thread(hostId: String, threadId: String)
case newThread
/// Every thread in Recent, past the feed's first 10.
case recent
/// The status overview, and from it one host or the notifications page.
case status
case host(id: String)
case notifications
static let scheme = "wristcode"
/// `wristcode://thread/<hostId>/<threadId>`, `wristcode://new`, `wristcode://recent`, `wristcode://status`,
/// `wristcode://host/<hostId>` or `wristcode://notifications`.
var url: URL {
var components = URLComponents()
components.scheme = Self.scheme
switch self {
case let .thread(hostId, threadId):
components.host = "thread"
components.percentEncodedPath = "/" + [hostId, threadId]
.map { $0.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? $0 }
.joined(separator: "/")
case .newThread:
components.host = "new"
case .recent:
components.host = "recent"
case .status:
components.host = "status"
case let .host(id):
components.host = "host"
components.percentEncodedPath = "/" + (id.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? id)
case .notifications:
components.host = "notifications"
}
return components.url!
}
/// The route a `wristcode://` URL names, or nil when it names none.
init?(url: URL) {
guard url.scheme == Self.scheme,
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
else { return nil }
let parts = components.percentEncodedPath.split(separator: "/").map { $0.removingPercentEncoding ?? String($0) }
switch components.host {
case "thread" where parts.count == 2 && parts.allSatisfy { !$0.isEmpty }:
self = .thread(hostId: parts[0], threadId: parts[1])
case "new":
self = .newThread
case "recent":
self = .recent
case "status":
self = .status
case "host" where parts.count == 1 && !parts[0].isEmpty:
self = .host(id: parts[0])
case "notifications":
self = .notifications
default:
return nil
}
}
}