gitbay/Views/Repos/TreeView.swift

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

72 lines · 2314 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        .task { await model.load() }
41        .refreshable { await model.load() }
42    }
43}
44
45private struct EntryRow: View {
46    let entry: TreeEntry
47
48    var body: some View {
49        HStack {
50            Label {
51                Text(entry.name)
52                    .lineLimit(1)
53            } icon: {
54                Image(systemName: icon)
55                    .foregroundStyle(entry.isDirectory ? Color.accentColor : .secondary)
56            }
57            Spacer()
58            if let size = entry.size, !entry.isDirectory {
59                Text(size.formatted(.byteCount(style: .file)))
60                    .font(.caption)
61                    .foregroundStyle(.tertiary)
62                    .monospacedDigit()
63            }
64        }
65    }
66
67    private var icon: String {
68        if entry.isDirectory { return "folder.fill" }
69        if entry.isSymlink { return "arrow.turn.down.right" }
70        return "doc"
71    }
72}