krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
v2.10.2: Hutch/Views/Repositories/ReferencesListView.swift · raw
1import SwiftUI
2
3struct ReferencesListView: View {
4 let viewModel: RepositoryDetailViewModel
5
6 var body: some View {
7 List {
8 if !viewModel.branches.isEmpty {
9 Section("Branches") {
10 ForEach(viewModel.branches, id: \.name) { ref in
11 ReferenceRow(reference: ref, prefix: "refs/heads/")
12 }
13 }
14 }
15
16 if !viewModel.tags.isEmpty {
17 Section("Tags") {
18 ForEach(viewModel.tags, id: \.name) { ref in
19 ReferenceRow(reference: ref, prefix: "refs/tags/")
20 }
21 }
22 }
23 }
24 .listStyle(.insetGrouped)
25 .overlay {
26 if viewModel.isLoadingRefs, viewModel.branches.isEmpty, viewModel.tags.isEmpty {
27 SRHTLoadingStateView(message: "Loading references…")
28 } else if let error = viewModel.error, viewModel.branches.isEmpty, viewModel.tags.isEmpty {
29 SRHTErrorStateView(
30 title: "Couldn't Load References",
31 message: error,
32 retryAction: { await viewModel.loadReferences() }
33 )
34 } else if viewModel.branches.isEmpty, viewModel.tags.isEmpty {
35 ContentUnavailableView(
36 "No References",
37 systemImage: "arrow.triangle.branch",
38 description: Text("This repository has no branches or tags.")
39 )
40 }
41 }
42 .task {
43 if viewModel.branches.isEmpty, viewModel.tags.isEmpty {
44 await viewModel.loadReferences()
45 }
46 }
47 .refreshable {
48 await viewModel.loadReferences()
49 }
50 }
51}
52
53private struct ReferenceRow: View {
54 let reference: ReferenceDetail
55 let prefix: String
56
57 var body: some View {
58 HStack {
59 Label {
60 VStack(alignment: .leading, spacing: 2) {
61 Text(shortName)
62 .font(.body.monospaced())
63 if let date = reference.date {
64 Text(date.relativeDescription)
65 .font(.caption)
66 .foregroundStyle(.secondary)
67 }
68 }
69 } icon: {
70 Image(systemName: icon)
71 .foregroundStyle(iconColor)
72 }
73
74 Spacer()
75
76 Text(String((reference.target ?? "").prefix(8)))
77 .font(.caption.monospaced())
78 .foregroundStyle(.secondary)
79 }
80 }
81
82 private var shortName: String {
83 if reference.name.hasPrefix(prefix) {
84 String(reference.name.dropFirst(prefix.count))
85 } else {
86 reference.name
87 }
88 }
89
90 private var icon: String {
91 prefix.contains("tags") ? "tag" : "arrow.triangle.branch"
92 }
93
94 private var iconColor: Color {
95 prefix.contains("tags") ? .orange : .blue
96 }
97}