gitbay/Repos/RefsViewModel.swift
45 lines · 1500 bytes
1import Foundation
2import Observation
3
4/// `repo refs` — the branches and tags the server knows, so a ref is
5/// picked rather than typed.
6@Observable
7@MainActor
8final class RefsViewModel {
9
10 private(set) var state: LoadState<RepoRefs> = .loading
11 var searchText = ""
12
13 private let client: GitbayClient
14 let repoPath: String
15 /// The repo's default branch, marked in the list.
16 private(set) var defaultBranch: String?
17
18 init(client: GitbayClient, repoPath: String) {
19 self.client = client
20 self.repoPath = repoPath
21 }
22
23 private func matching(_ refs: [RepoRef]) -> [RepoRef] {
24 let query = searchText.trimmingCharacters(in: .whitespaces).lowercased()
25 guard !query.isEmpty else { return refs }
26 return refs.filter { $0.name.lowercased().contains(query) }
27 }
28
29 var branches: [RepoRef] { matching(state.value?.branches ?? []) }
30 var tags: [RepoRef] { matching(state.value?.tags ?? []) }
31
32 func load() async {
33 do {
34 async let refs = client.read(["repo", "refs", repoPath], as: RepoRefs.self)
35 async let detail = try? client.read(["repo", "show", repoPath], as: RepoDetail.self)
36 let loaded = try await refs
37 defaultBranch = await detail?.defaultBranch
38 state = (loaded.branches.isEmpty && loaded.tags.isEmpty)
39 ? .empty("No branches or tags yet.")
40 : .loaded(loaded)
41 } catch {
42 state = .from(error)
43 }
44 }
45}