krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
v3.8.1: Hutch/Models/Patchset.swift · raw
1import Foundation
2
3/// Review state of a patchset on lists.sr.ht.
4enum PatchsetStatus: String, Codable, Sendable, CaseIterable {
5 case unknown = "UNKNOWN"
6 case proposed = "PROPOSED"
7 case needsRevision = "NEEDS_REVISION"
8 case superseded = "SUPERSEDED"
9 case approved = "APPROVED"
10 case rejected = "REJECTED"
11 case applied = "APPLIED"
12
13 var displayName: String {
14 switch self {
15 case .unknown: "Unknown"
16 case .proposed: "Proposed"
17 case .needsRevision: "Needs Revision"
18 case .superseded: "Superseded"
19 case .approved: "Approved"
20 case .rejected: "Rejected"
21 case .applied: "Applied"
22 }
23 }
24
25 var systemImage: String {
26 switch self {
27 case .unknown: "questionmark.circle"
28 case .proposed: "paperplane"
29 case .needsRevision: "exclamationmark.arrow.circlepath"
30 case .superseded: "arrow.triangle.branch"
31 case .approved: "checkmark.seal"
32 case .rejected: "xmark.circle"
33 case .applied: "checkmark.circle.fill"
34 }
35 }
36
37 /// Whether the patchset is still awaiting a decision.
38 var isOpen: Bool {
39 switch self {
40 case .unknown, .proposed, .needsRevision: true
41 case .superseded, .approved, .rejected, .applied: false
42 }
43 }
44
45 /// Statuses a reviewer can set directly.
46 ///
47 /// `unknown` is a sentinel for patchsets sr.ht could not classify, and
48 /// `superseded` is set by the server when a later version arrives, so neither
49 /// is offered as a choice.
50 static var assignable: [PatchsetStatus] {
51 [.proposed, .needsRevision, .approved, .rejected, .applied]
52 }
53}
54
55/// A patchset as it appears in a mailing list listing, derived from the thread's
56/// root email rather than a dedicated patchsets query — `MailingList` exposes no
57/// such field.
58struct PatchsetSummary: Identifiable, Hashable, Sendable {
59 let id: Int
60 let subject: String
61 let version: Int
62 let prefix: String?
63 let status: PatchsetStatus
64
65 /// The `[PATCH v2]`-style prefix sr.ht parsed from the subject, if any.
66 var versionLabel: String? {
67 guard version > 1 else { return nil }
68 return "v\(version)"
69 }
70}
71
72/// One email within a patchset: either the cover letter or a single patch.
73struct PatchsetEmail: Identifiable, Hashable, Sendable {
74 let id: Int
75 let subject: String
76 let date: Date?
77 let sender: Entity
78 /// Split into commit message and diff blocks for rendering.
79 let contentBlocks: [InboxMessageContentBlock]
80 /// Position within the series, from the `[PATCH 2/5]` prefix.
81 let index: Int?
82 let count: Int?
83
84 var seriesLabel: String? {
85 guard let index, let count, count > 1 else { return nil }
86 return "\(index)/\(count)"
87 }
88}
89
90/// A build or check reported against a patchset.
91struct PatchsetToolResult: Identifiable, Hashable, Sendable {
92 let id: Int
93 let icon: PatchsetToolIcon
94 let details: String
95}
96
97enum PatchsetToolIcon: String, Codable, Sendable {
98 case pending = "PENDING"
99 case waiting = "WAITING"
100 case success = "SUCCESS"
101 case failed = "FAILED"
102 case cancelled = "CANCELLED"
103
104 var systemImage: String {
105 switch self {
106 case .pending, .waiting: "clock"
107 case .success: "checkmark.circle.fill"
108 case .failed: "xmark.circle.fill"
109 case .cancelled: "minus.circle"
110 }
111 }
112}
113
114/// A patchset with its cover letter, patches, and review context.
115struct PatchsetDetail: Sendable {
116 let id: Int
117 let created: Date
118 let updated: Date
119 let subject: String
120 let version: Int
121 let prefix: String?
122 let status: PatchsetStatus
123 let submitter: Entity
124 let coverLetter: PatchsetEmail?
125 let patches: [PatchsetEmail]
126 /// Set when a newer version of this series exists.
127 let supersededBy: Int?
128 /// Set when this series revises an earlier one.
129 let supersedes: Int?
130 let tools: [PatchsetToolResult]
131 let mbox: URL?
132}