1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import Foundation
enum DeepLink: Equatable {
case profile(did: String)
case gallery(did: String, rkey: String)
case story(did: String, rkey: String)
static func from(url: URL) -> DeepLink? {
// Normalize: for grain:// scheme, host is the first segment (e.g. grain://profile/did/...)
// For https, path starts with /profile/did/...
let segments: [String] = if url.scheme == "grain", let host = url.host {
[host] + url.pathComponents.filter { $0 != "/" }
} else {
url.pathComponents.filter { $0 != "/" }
}
guard segments.first == "profile", segments.count >= 2 else { return nil }
let did = segments[1]
if segments.count >= 4, segments[2] == "gallery" {
return .gallery(did: did, rkey: segments[3])
}
if segments.count >= 4, segments[2] == "story" {
return .story(did: did, rkey: segments[3])
}
return .profile(did: did)
}
var galleryUri: String? {
if case let .gallery(did, rkey) = self {
return "at://\(did)/social.grain.gallery/\(rkey)"
}
return nil
}
}
extension DeepLink {
/// The push this link corresponds to, if it is one.
///
/// Stories return `nil`: they present as a full-screen cover rather than
/// joining the navigation stack, so the screen handling the link presents
/// them itself.
var route: Route? {
switch self {
case let .profile(did):
.profile(did: did)
case let .gallery(did, rkey):
.gallery(uri: "at://\(did)/social.grain.gallery/\(rkey)")
case .story:
nil
}
}
}