krz/hutch

an ios client for sourcehut

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

v2.10.3: Hutch/Views/Lookup/UserProfileViewModel.swift · raw

  1import Foundation
  2
  3@Observable
  4@MainActor
  5final class UserProfileViewModel {
  6    private(set) var repositories: [RepositorySummary] = []
  7    private(set) var trackers: [TrackerSummary] = []
  8    private(set) var isLoadingRepositories = false
  9    private(set) var isLoadingTrackers = false
 10    var repositoriesError: String?
 11    var trackersError: String?
 12
 13    private let client: SRHTClient
 14    let ownerUsername: String
 15
 16    init(ownerUsername: String, client: SRHTClient) {
 17        self.ownerUsername = ownerUsername
 18        self.client = client
 19    }
 20
 21    func loadRepositories() async {
 22        isLoadingRepositories = true
 23        repositoriesError = nil
 24        defer { isLoadingRepositories = false }
 25
 26        do {
 27            let result = try await client.execute(
 28                service: .git,
 29                query: Self.repositoriesQuery,
 30                variables: ["owner": ownerUsername],
 31                responseType: UserRepositoriesResponse.self
 32            )
 33            repositories = result.user.repositories.results.map { $0.repositorySummary(service: .git) }
 34        } catch {
 35            repositoriesError = error.userFacingMessage
 36        }
 37    }
 38
 39    func loadTrackers() async {
 40        isLoadingTrackers = true
 41        trackersError = nil
 42        defer { isLoadingTrackers = false }
 43
 44        do {
 45            let result = try await client.execute(
 46                service: .todo,
 47                query: Self.trackersQuery,
 48                variables: ["owner": ownerUsername],
 49                responseType: UserTrackersResponse.self
 50            )
 51            trackers = result.user.trackers.results
 52        } catch {
 53            trackersError = error.userFacingMessage
 54        }
 55    }
 56
 57    private static let repositoriesQuery = """
 58    query userRepositories($owner: String!) {
 59        user(username: $owner) {
 60            repositories {
 61                results {
 62                    id
 63                    rid
 64                    name
 65                    description
 66                    visibility
 67                    updated
 68                    owner { canonicalName }
 69                    HEAD { name target }
 70                }
 71                cursor
 72            }
 73        }
 74    }
 75    """
 76
 77    private static let trackersQuery = """
 78    query userTrackers($owner: String!) {
 79        user(username: $owner) {
 80            trackers {
 81                results {
 82                    id
 83                    rid
 84                    name
 85                    description
 86                    visibility
 87                    updated
 88                    owner { canonicalName }
 89                }
 90                cursor
 91            }
 92        }
 93    }
 94    """
 95
 96    private struct UserRepositoriesResponse: Decodable, Sendable {
 97        let user: UserRepositoriesContainer
 98    }
 99
100    private struct UserRepositoriesContainer: Decodable, Sendable {
101        let repositories: RepositoriesPage
102    }
103
104    private struct RepositoriesPage: Decodable, Sendable {
105        let results: [RepositoryPayload]
106        let cursor: String?
107    }
108
109    private struct RepositoryPayload: Decodable, Sendable {
110        let id: Int
111        let rid: String
112        let name: String
113        let description: String?
114        let visibility: Visibility
115        let updated: Date
116        let owner: Entity
117        let head: Reference?
118
119        enum CodingKeys: String, CodingKey {
120            case id, rid, name, description, visibility, updated, owner
121            case head = "HEAD"
122        }
123
124        func repositorySummary(service: SRHTService) -> RepositorySummary {
125            RepositorySummary(
126                id: id,
127                rid: rid,
128                service: service,
129                name: name,
130                description: description,
131                visibility: visibility,
132                updated: updated,
133                owner: owner,
134                head: head
135            )
136        }
137    }
138
139    private struct UserTrackersResponse: Decodable, Sendable {
140        let user: UserTrackersContainer
141    }
142
143    private struct UserTrackersContainer: Decodable, Sendable {
144        let trackers: TrackersPage
145    }
146
147    private struct TrackersPage: Decodable, Sendable {
148        let results: [TrackerSummary]
149        let cursor: String?
150    }
151}