krz/hutch

an ios client for sourcehut

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

v3.5.0: Hutch/Views/Repositories/LinkedFileSheetView.swift · raw

 1import SwiftUI
 2
 3/// A sheet that fetches and displays a single repository file by path,
 4/// using the `repository.path()` GraphQL field  one API call, no tree traversal.
 5struct LinkedFileSheetView: View {
 6    let rid: String
 7    let service: SRHTService
 8    let client: SRHTClient
 9    let request: LinkedFileRequest
10
11    @AppStorage(AppStorageKeys.wrapRepositoryFileLines) private var wrapLines = false
12    @Environment(\.dismiss) private var dismiss
13
14    @State private var entry: TreeEntry?
15    @State private var isLoading = true
16    @State private var error: String?
17
18    var body: some View {
19        NavigationStack {
20            Group {
21                if isLoading {
22                    SRHTLoadingStateView(message: "Loading \(request.fileName)")
23                } else if let error {
24                    SRHTErrorStateView(
25                        title: "Couldn't Load File",
26                        message: error,
27                        retryAction: { await load() }
28                    )
29                } else if let entry, let object = entry.object {
30                    fileContentView(entry: entry, object: object)
31                } else {
32                    ContentUnavailableView(
33                        "File Not Found",
34                        systemImage: "doc.questionmark",
35                        description: Text("\(request.path) could not be found in this repository.")
36                    )
37                }
38            }
39            .navigationTitle(request.fileName)
40            .navigationBarTitleDisplayMode(.inline)
41            .toolbar {
42                ToolbarItem(placement: .topBarTrailing) {
43                    Button("Done") { dismiss() }
44                }
45            }
46        }
47        .task { await load() }
48    }
49
50    private func load() async {
51        isLoading = true
52        error = nil
53        let vm = FileTreeViewModel(repositoryRid: rid, service: service, client: client)
54        do {
55            entry = try await vm.fetchLinkedFile(path: request.path, revspec: request.revspec)
56        } catch {
57            self.error = error.userFacingMessage
58        }
59        isLoading = false
60    }
61
62    @ViewBuilder
63    private func fileContentView(entry: TreeEntry, object: GitObject) -> some View {
64        switch object {
65        case .textBlob(let blob):
66            CodeFileTextView(
67                text: blob.text ?? "",
68                fileName: entry.name,
69                wrapLines: wrapLines
70            )
71        case .binaryBlob:
72            ContentUnavailableView(
73                "Binary File",
74                systemImage: "doc.zipper",
75                description: Text("Binary files cannot be displayed inline.")
76            )
77        default:
78            ContentUnavailableView(
79                "Unknown File",
80                systemImage: "questionmark.folder",
81                description: Text("This object type cannot be displayed.")
82            )
83        }
84    }
85}