krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v3.1.6: 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                    .themedRow()
 14                }
 15            }
 16
 17            if !viewModel.tags.isEmpty {
 18                Section("Tags") {
 19                    ForEach(viewModel.tags, id: \.name) { ref in
 20                        ReferenceRow(reference: ref, prefix: "refs/tags/")
 21                    }
 22                    .themedRow()
 23                }
 24            }
 25        }
 26        .themedList()
 27        .listStyle(.insetGrouped)
 28        .overlay {
 29            if viewModel.isLoadingRefs, viewModel.branches.isEmpty, viewModel.tags.isEmpty {
 30                SRHTLoadingStateView(message: "Loading references…")
 31            } else if let error = viewModel.error, viewModel.branches.isEmpty, viewModel.tags.isEmpty {
 32                SRHTErrorStateView(
 33                    title: "Couldn't Load References",
 34                    message: error,
 35                    retryAction: { await viewModel.loadReferences() }
 36                )
 37            } else if viewModel.branches.isEmpty, viewModel.tags.isEmpty {
 38                ContentUnavailableView(
 39                    "No References",
 40                    systemImage: "arrow.triangle.branch",
 41                    description: Text("This repository has no branches or tags.")
 42                )
 43            }
 44        }
 45        .task {
 46            if viewModel.branches.isEmpty, viewModel.tags.isEmpty {
 47                await viewModel.loadReferences()
 48            }
 49        }
 50        .refreshable {
 51            await viewModel.loadReferences()
 52        }
 53    }
 54}
 55
 56private struct ReferenceRow: View {
 57    let reference: ReferenceDetail
 58    let prefix: String
 59
 60    var body: some View {
 61        HStack {
 62            Label {
 63                VStack(alignment: .leading, spacing: 2) {
 64                    Text(shortName)
 65                        .font(.body.monospaced())
 66                    if let date = reference.date {
 67                        Text(date.relativeDescription)
 68                            .font(.caption)
 69                            .foregroundStyle(.secondary)
 70                    }
 71                }
 72            } icon: {
 73                Image(systemName: icon)
 74                    .foregroundStyle(iconColor)
 75            }
 76
 77            Spacer()
 78
 79            Text(String((reference.target ?? "").prefix(8)))
 80                .font(.caption.monospaced())
 81                .foregroundStyle(.secondary)
 82        }
 83    }
 84
 85    private var shortName: String {
 86        if reference.name.hasPrefix(prefix) {
 87            String(reference.name.dropFirst(prefix.count))
 88        } else {
 89            reference.name
 90        }
 91    }
 92
 93    private var icon: String {
 94        prefix.contains("tags") ? "tag" : "arrow.triangle.branch"
 95    }
 96
 97    private var iconColor: Color {
 98        prefix.contains("tags") ? .orange : .blue
 99    }
100}