gitbay/Views/Repos/TreeView.swift

v1.13.1
gitbay-ios/gitbay/Views/Repos/TreeView.swift history · blame · raw

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}