gitbay/Views/Repos/TreeView.swift
83 lines · 2738 bytes
1import SwiftUI
2
3struct TreeView: View {
4
5 @State private var model: TreeViewModel
6
7 init(client: GitbayClient, repo: String, directory: String, ref: String?) {
8 _model = State(initialValue: TreeViewModel(
9 client: client, repoPath: repo, directory: directory, ref: ref
10 ))
11 }
12
13 var body: some View {
14 List {
15 ForEach(model.entries) { entry in
16 if entry.isDirectory {
17 NavigationLink(value: RepoRoute.tree(
18 repo: model.repoPath,
19 directory: model.childDirectory(entry),
20 ref: model.ref
21 )) {
22 EntryRow(entry: entry)
23 }
24 } else {
25 NavigationLink(value: RepoRoute.file(
26 repo: model.repoPath,
27 path: model.childDirectory(entry),
28 ref: model.ref
29 )) {
30 EntryRow(entry: entry)
31 }
32 }
33 }
34 }
35 .overlay { LoadStateOverlay(state: model.state) }
36 .navigationTitle(model.directory.isEmpty
37 ? String(model.repoPath.split(separator: "/").last ?? "")
38 : String(model.directory.split(separator: "/").last ?? ""))
39 .navigationBarTitleDisplayMode(.inline)
40 .toolbar {
41 ToolbarItem(placement: .topBarTrailing) {
42 NavigationLink(value: RepoRoute.log(
43 repo: model.repoPath, ref: model.ref, path: nil
44 )) {
45 Image(systemName: "clock")
46 }
47 .accessibilityLabel("History")
48 .accessibilityIdentifier("tree-history-button")
49 }
50 }
51 .task { await model.load() }
52 .refreshable { await model.load() }
53 }
54}
55
56private struct EntryRow: View {
57 let entry: TreeEntry
58
59 var body: some View {
60 HStack {
61 Label {
62 Text(entry.name)
63 .lineLimit(1)
64 } icon: {
65 Image(systemName: icon)
66 .foregroundStyle(entry.isDirectory ? Color.accentColor : .secondary)
67 }
68 Spacer()
69 if let size = entry.size, !entry.isDirectory {
70 Text(size.formatted(.byteCount(style: .file)))
71 .font(.gbSans(.caption))
72 .foregroundStyle(.tertiary)
73 .monospacedDigit()
74 }
75 }
76 }
77
78 private var icon: String {
79 if entry.isDirectory { return "folder.fill" }
80 if entry.isSymlink { return "arrow.turn.down.right" }
81 return "doc"
82 }
83}