summaryrefslogtreecommitdiff
path: root/Hutch/Views/Repositories/LinkedFileSheetView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Hutch/Views/Repositories/LinkedFileSheetView.swift')
-rw-r--r--Hutch/Views/Repositories/LinkedFileSheetView.swift85
1 files changed, 85 insertions, 0 deletions
diff --git a/Hutch/Views/Repositories/LinkedFileSheetView.swift b/Hutch/Views/Repositories/LinkedFileSheetView.swift
new file mode 100644
index 0000000..4f176be
--- /dev/null
+++ b/Hutch/Views/Repositories/LinkedFileSheetView.swift
@@ -0,0 +1,85 @@
+import SwiftUI
+
+/// A sheet that fetches and displays a single repository file by path,
+/// using the `repository.path()` GraphQL field — one API call, no tree traversal.
+struct LinkedFileSheetView: View {
+ let rid: String
+ let service: SRHTService
+ let client: SRHTClient
+ let request: LinkedFileRequest
+
+ @AppStorage(AppStorageKeys.wrapRepositoryFileLines) private var wrapLines = false
+ @Environment(\.dismiss) private var dismiss
+
+ @State private var entry: TreeEntry?
+ @State private var isLoading = true
+ @State private var error: String?
+
+ var body: some View {
+ NavigationStack {
+ Group {
+ if isLoading {
+ SRHTLoadingStateView(message: "Loading \(request.fileName)…")
+ } else if let error {
+ SRHTErrorStateView(
+ title: "Couldn't Load File",
+ message: error,
+ retryAction: { await load() }
+ )
+ } else if let entry, let object = entry.object {
+ fileContentView(entry: entry, object: object)
+ } else {
+ ContentUnavailableView(
+ "File Not Found",
+ systemImage: "doc.questionmark",
+ description: Text("\(request.path) could not be found in this repository.")
+ )
+ }
+ }
+ .navigationTitle(request.fileName)
+ .navigationBarTitleDisplayMode(.inline)
+ .toolbar {
+ ToolbarItem(placement: .topBarTrailing) {
+ Button("Done") { dismiss() }
+ }
+ }
+ }
+ .task { await load() }
+ }
+
+ private func load() async {
+ isLoading = true
+ error = nil
+ let vm = FileTreeViewModel(repositoryRid: rid, service: service, client: client)
+ do {
+ entry = try await vm.fetchLinkedFile(path: request.path, revspec: request.revspec)
+ } catch {
+ self.error = error.userFacingMessage
+ }
+ isLoading = false
+ }
+
+ @ViewBuilder
+ private func fileContentView(entry: TreeEntry, object: GitObject) -> some View {
+ switch object {
+ case .textBlob(let blob):
+ CodeFileTextView(
+ text: blob.text ?? "",
+ fileName: entry.name,
+ wrapLines: wrapLines
+ )
+ case .binaryBlob:
+ ContentUnavailableView(
+ "Binary File",
+ systemImage: "doc.zipper",
+ description: Text("Binary files cannot be displayed inline.")
+ )
+ default:
+ ContentUnavailableView(
+ "Unknown File",
+ systemImage: "questionmark.folder",
+ description: Text("This object type cannot be displayed.")
+ )
+ }
+ }
+}