// 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 static let scheme = "wristcode" /// `wristcode://thread//` or `wristcode://new`. 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" } 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 default: return nil } } }