gitbay/Repos/WikiViewModel.swift
78 lines · 1990 bytes
1import Foundation
2import Observation
3
4/// `wiki list` — the pages, and which one is the landing page.
5nonisolated struct WikiListing: Decodable, Sendable, Hashable {
6 let path: String
7 let home: String?
8 let pages: [String]
9}
10
11/// `wiki show` — one page's source. Rendered by format, as a README is.
12nonisolated struct WikiPage: Decodable, Sendable, Hashable {
13 let path: String
14 let page: String
15 let file: String
16 let size: Int
17 let binary: Bool?
18 let content: String?
19
20 var isBinary: Bool { binary ?? false }
21}
22
23/// A repository's wiki. The pages live in a companion repo and are
24/// edited by pushing to it, so this is a reading surface only — the
25/// same write interface every surface has.
26@Observable
27@MainActor
28final class WikiViewModel {
29
30 private(set) var state: LoadState<WikiListing> = .loading
31
32 private let client: GitbayClient
33 let repoPath: String
34
35 init(client: GitbayClient, repoPath: String) {
36 self.client = client
37 self.repoPath = repoPath
38 }
39
40 func load() async {
41 do {
42 let listing = try await client.read(
43 ["wiki", "list", repoPath], as: WikiListing.self)
44 state = listing.pages.isEmpty
45 ? .empty("This wiki has no pages yet.")
46 : .loaded(listing)
47 } catch {
48 state = .from(error)
49 }
50 }
51}
52
53/// One wiki page.
54@Observable
55@MainActor
56final class WikiPageViewModel {
57
58 private(set) var state: LoadState<WikiPage> = .loading
59
60 private let client: GitbayClient
61 let repoPath: String
62 let page: String
63
64 init(client: GitbayClient, repoPath: String, page: String) {
65 self.client = client
66 self.repoPath = repoPath
67 self.page = page
68 }
69
70 func load() async {
71 do {
72 state = .loaded(try await client.read(
73 ["wiki", "show", repoPath, page], as: WikiPage.self))
74 } catch {
75 state = .from(error)
76 }
77 }
78}