gitbay/Views/Repos/FileView.swift

5411753023a5e2958f17b523903abce380941107
gitbay-ios/gitbay/Views/Repos/FileView.swift history · blame · raw

80 lines · 2624 bytes

 1import SwiftUI
 2
 3struct FileView: View {
 4
 5    @Environment(\.colorScheme) private var colorScheme
 6    @State private var model: FileViewModel
 7
 8    init(client: GitbayClient, repo: String, path: String, ref: String?) {
 9        _model = State(initialValue: FileViewModel(
10            client: client, repoPath: repo, filePath: path, ref: ref
11        ))
12    }
13
14    var body: some View {
15        Group {
16            if let file = model.state.value {
17                content(file)
18            } else {
19                Color.clear
20            }
21        }
22        .overlay { LoadStateOverlay(state: model.state) }
23        .navigationTitle(model.fileName)
24        .navigationBarTitleDisplayMode(.inline)
25        .task { await model.load() }
26    }
27
28    @ViewBuilder
29    private func content(_ file: FileContent) -> some View {
30        if file.binary {
31            ContentUnavailableView {
32                Label("Binary file", systemImage: "doc.zipper")
33            } description: {
34                Text("\(file.file) · \(Int64(file.size).formatted(.byteCount(style: .file)))")
35            }
36        } else if let text = file.content {
37            VStack(spacing: 0) {
38                if file.isTruncated {
39                    Label(
40                        "Truncated — showing the first \(Int64(file.size).formatted(.byteCount(style: .file))).",
41                        systemImage: "scissors"
42                    )
43                    .font(.caption)
44                    .frame(maxWidth: .infinity, alignment: .leading)
45                    .padding(8)
46                    .background(.yellow.opacity(0.15))
47                }
48                CodeScrollView(text: text, fileName: model.fileName, colorScheme: colorScheme)
49            }
50        }
51    }
52}
53
54/// Both-axis scrolling for code, highlighted when the language is known.
55private struct CodeScrollView: View {
56
57    let text: String
58    let fileName: String
59    let colorScheme: ColorScheme
60
61    var body: some View {
62        ScrollView([.horizontal, .vertical]) {
63            code
64                .padding(12)
65                .frame(maxWidth: .infinity, alignment: .leading)
66        }
67        .font(.caption.monospaced())
68    }
69
70    private var code: some View {
71        let font = UIFont.monospacedSystemFont(
72            ofSize: UIFont.preferredFont(forTextStyle: .caption1).pointSize, weight: .regular
73        )
74        let highlighter = SyntaxHighlighter(colorScheme: colorScheme)
75        if let highlighted = highlighter.highlight(text, fileName: fileName, font: font) {
76            return Text(AttributedString(highlighted))
77        }
78        return Text(text)
79    }
80}