diff options
| author | Christian Cleberg <[email protected]> | 2026-04-12 22:06:16 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-12 22:06:16 -0500 |
| commit | 86bcd9452d3107f68aca085e03e69b02667c0dbb (patch) | |
| tree | 8b0adece5cb0f8ffb178eaab2cd12d025c9ebf0a /Hutch/Networking | |
| parent | 31cbca674957eea7ae2529012e20a9d95158e561 (diff) | |
| download | hutch-86bcd9452d3107f68aca085e03e69b02667c0dbb.tar.gz hutch-86bcd9452d3107f68aca085e03e69b02667c0dbb.tar.bz2 hutch-86bcd9452d3107f68aca085e03e69b02667c0dbb.zip | |
feat: polish read-only project views and home integration
Refs: https://todo.sr.ht/~ccleberg/hutch/36
Refs: https://todo.sr.ht/~ccleberg/hutch/37
Refs: https://todo.sr.ht/~ccleberg/hutch/38
Diffstat (limited to 'Hutch/Networking')
| -rw-r--r-- | Hutch/Networking/ProjectService.swift | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/Hutch/Networking/ProjectService.swift b/Hutch/Networking/ProjectService.swift index 5a0b466..93ce71f 100644 --- a/Hutch/Networking/ProjectService.swift +++ b/Hutch/Networking/ProjectService.swift @@ -11,6 +11,17 @@ private struct ProjectPageUser: Decodable, Sendable { private struct ProjectPage: Decodable, Sendable { let results: [ProjectSummaryPayload] let cursor: String? + + private enum CodingKeys: String, CodingKey { + case results + case cursor + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + results = try container.decodeIfPresent([ProjectSummaryPayload].self, forKey: .results) ?? [] + cursor = try container.decodeIfPresent(String.self, forKey: .cursor) + } } private struct ProjectSummaryPayload: Decodable, Sendable { @@ -21,6 +32,27 @@ private struct ProjectSummaryPayload: Decodable, Sendable { let visibility: Visibility let tags: [String] let updated: Date + + private enum CodingKeys: String, CodingKey { + case rid + case name + case description + case website + case visibility + case tags + case updated + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + rid = try container.decode(String.self, forKey: .rid) + name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" + description = try container.decodeIfPresent(String.self, forKey: .description) + website = try container.decodeIfPresent(String.self, forKey: .website) + visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public + tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? [] + updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast + } } private struct ProjectDetailResponse: Decodable, Sendable { @@ -38,11 +70,40 @@ private struct ProjectDetailPayload: Decodable, Sendable { let mailingLists: ProjectMailingListPage let sources: ProjectSourcePage let trackers: ProjectTrackerPage + + private enum CodingKeys: String, CodingKey { + case rid + case name + case description + case website + case visibility + case tags + case updated + case mailingLists + case sources + case trackers + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + rid = try container.decode(String.self, forKey: .rid) + name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" + description = try container.decodeIfPresent(String.self, forKey: .description) + website = try container.decodeIfPresent(String.self, forKey: .website) + visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public + tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? [] + updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast + mailingLists = try container.decodeIfPresent(ProjectMailingListPage.self, forKey: .mailingLists) ?? .empty + sources = try container.decodeIfPresent(ProjectSourcePage.self, forKey: .sources) ?? .empty + trackers = try container.decodeIfPresent(ProjectTrackerPage.self, forKey: .trackers) ?? .empty + } } private struct ProjectMailingListPage: Decodable, Sendable { let results: [ProjectMailingListPayload] let cursor: String? + + static let empty = ProjectMailingListPage(results: [], cursor: nil) } private struct ProjectMailingListPayload: Decodable, Sendable { @@ -51,11 +112,30 @@ private struct ProjectMailingListPayload: Decodable, Sendable { let description: String? let visibility: Visibility let owner: Entity + + private enum CodingKeys: String, CodingKey { + case rid + case name + case description + case visibility + case owner + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + rid = try container.decode(String.self, forKey: .rid) + name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" + description = try container.decodeIfPresent(String.self, forKey: .description) + visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public + owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown") + } } private struct ProjectSourcePage: Decodable, Sendable { let results: [ProjectSourcePayload] let cursor: String? + + static let empty = ProjectSourcePage(results: [], cursor: nil) } private struct ProjectSourcePayload: Decodable, Sendable { @@ -65,11 +145,32 @@ private struct ProjectSourcePayload: Decodable, Sendable { let visibility: Visibility let owner: Entity let repoType: Project.SourceRepo.RepoType + + private enum CodingKeys: String, CodingKey { + case rid + case name + case description + case visibility + case owner + case repoType + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + rid = try container.decode(String.self, forKey: .rid) + name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" + description = try container.decodeIfPresent(String.self, forKey: .description) + visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public + owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown") + repoType = try container.decodeIfPresent(Project.SourceRepo.RepoType.self, forKey: .repoType) ?? .git + } } private struct ProjectTrackerPage: Decodable, Sendable { let results: [ProjectTrackerPayload] let cursor: String? + + static let empty = ProjectTrackerPage(results: [], cursor: nil) } private struct ProjectTrackerPayload: Decodable, Sendable { @@ -78,6 +179,23 @@ private struct ProjectTrackerPayload: Decodable, Sendable { let description: String? let visibility: Visibility let owner: Entity + + private enum CodingKeys: String, CodingKey { + case rid + case name + case description + case visibility + case owner + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + rid = try container.decode(String.self, forKey: .rid) + name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" + description = try container.decodeIfPresent(String.self, forKey: .description) + visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public + owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown") + } } struct ProjectService: Sendable { |
