krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
v2.15.1: Hutch/App/DeepLink.swift · raw
1import Foundation
2
3/// Represents a parsed `hutch://` deep link.
4enum DeepLink: Equatable {
5 case home
6 /// hutch://git/<owner>/<repo>
7 case repository(owner: String, repo: String)
8 /// hutch://todo/<owner>/<tracker>/<ticketId>
9 case ticket(owner: String, tracker: String, ticketId: Int)
10 /// hutch://builds/<jobId>
11 case build(jobId: Int)
12 /// hutch://builds (tab-level)
13 case buildsTab
14 /// hutch://repositories (tab-level)
15 case repositoriesTab
16 /// hutch://trackers (tab-level)
17 case trackersTab
18 /// hutch://status
19 case systemStatus
20 /// hutch://lookup
21 case lookup
22
23 /// Attempt to parse a URL into a DeepLink.
24 /// Expected format: hutch://<path>
25 init?(url: URL) {
26 guard url.scheme == "hutch" else { return nil }
27
28 // url.host gives the first path component for opaque URLs;
29 // use standardized path components from the full string.
30 let components = url.pathComponents(fromScheme: "hutch")
31
32 switch components.first {
33 case "home", nil:
34 self = .home
35
36 case "git" where components.count >= 3:
37 let owner = components[1]
38 let repo = components[2]
39 self = .repository(owner: owner, repo: repo)
40
41 case "todo" where components.count >= 4:
42 let owner = components[1]
43 let tracker = components[2]
44 guard let ticketId = Int(components[3]) else { return nil }
45 self = .ticket(owner: owner, tracker: tracker, ticketId: ticketId)
46
47 case "builds" where components.count >= 2:
48 guard let jobId = Int(components[1]) else { return nil }
49 self = .build(jobId: jobId)
50
51 case "builds":
52 self = .buildsTab
53
54 case "repositories":
55 self = .repositoriesTab
56
57 case "trackers":
58 self = .trackersTab
59
60 case "status":
61 self = .systemStatus
62
63 case "lookup":
64 self = .lookup
65
66 default:
67 return nil
68 }
69 }
70}
71
72private extension URL {
73 /// Parse path components from a custom-scheme URL.
74 /// For `hutch://git/~user/repo`, returns `["git", "~user", "repo"]`.
75 func pathComponents(fromScheme scheme: String) -> [String] {
76 // Remove scheme prefix and split by "/"
77 var str = absoluteString
78 if str.hasPrefix("\(scheme)://") {
79 str = String(str.dropFirst("\(scheme)://".count))
80 }
81 return str.split(separator: "/").map(String.init)
82 }
83}