krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v3.8.2: 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}