gitbay/Discovery/ProfileEdit.swift

v1.0.6
gitbay-ios/gitbay/Discovery/ProfileEdit.swift history · blame · raw

77 lines · 2864 bytes

 1import Foundation
 2
 3/// `profile set` — unlike every other filter or edit in the app, `--link`
 4/// replaces the whole set rather than appending, so every link the form
 5/// wants to keep is sent on every save. The form is always seeded from
 6/// the current profile, so every other field is also sent every time,
 7/// including empty ones: `--description ""` clears, omitting the flag
 8/// would leave the old value alone.
 9nonisolated struct ProfileEdit: Equatable, Sendable {
10
11    nonisolated struct Link: Equatable, Sendable, Identifiable {
12        var id = UUID()
13        var label: String
14        var url: String
15    }
16
17    var description: String
18    var website: String
19    var about: String
20    var aboutFormat: String
21    var links: [Link]
22
23    init(
24        description: String = "", website: String = "",
25        about: String = "", aboutFormat: String = "md",
26        links: [Link] = []
27    ) {
28        self.description = description
29        self.website = website
30        self.about = about
31        self.aboutFormat = aboutFormat
32        self.links = links
33    }
34
35    init(from profile: ProfileViewModel.Profile) {
36        description = profile.description ?? ""
37        website = profile.website ?? ""
38        about = profile.about ?? ""
39        aboutFormat = profile.aboutFormat ?? "md"
40        links = (profile.links ?? []).map { Link(label: $0.label ?? "", url: $0.url) }
41    }
42
43    /// At most 5 links and every link needs a URL — the server enforces
44    /// both, but the form should not let a save reach it that way. A
45    /// label may not contain `|` either: the server splits a link on its
46    /// first pipe, so a label carrying one would silently corrupt the URL
47    /// rather than be rejected.
48    var validationError: String? {
49        if links.count > 5 { return "At most 5 links." }
50        if links.contains(where: { $0.url.trimmingCharacters(in: .whitespaces).isEmpty }) {
51            return "A link needs a URL."
52        }
53        if links.contains(where: { $0.label.contains("|") }) {
54            return "A link label can't contain \"|\" — that's what separates it from the URL."
55        }
56        return nil
57    }
58
59    /// Everything except the about text, which travels over stdin.
60    func flags() -> [String] {
61        var flags = ["--description", description, "--website", website]
62        if links.isEmpty {
63            flags += ["--link", ""]
64        } else {
65            for link in links {
66                let label = link.label.trimmingCharacters(in: .whitespaces)
67                flags += ["--link", label.isEmpty ? link.url : "\(label)|\(link.url)"]
68            }
69        }
70        flags += ["--about-format", aboutFormat, "--file", "-"]
71        return flags
72    }
73
74    /// The about text, sent over stdin — never in argv, since it is
75    /// long-form and may hold newlines.
76    var aboutStdin: String { about }
77}