krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
v3.0.4: Hutch/Views/Repositories/RepositoryRowView.swift · raw
1import SwiftUI
2
3struct RepositoryRowView: View {
4 @Environment(AppState.self) private var appState
5 @Environment(\.openURL) private var openURL
6
7 let repository: RepositorySummary
8 let buildStatus: RepositoryBuildStatus
9
10 var body: some View {
11 VStack(alignment: .leading, spacing: 4) {
12 HStack(alignment: .firstTextBaseline) {
13 Text(repository.name)
14 .font(.headline)
15
16 Spacer()
17
18 RepositoryForgeBadge(service: repository.service)
19
20 if buildStatus != .none {
21 RepositoryBuildStatusIndicator(status: buildStatus)
22 }
23 VisibilityBadge(visibility: repository.visibility)
24 }
25
26 Text(repository.owner.canonicalName)
27 .font(.subheadline)
28 .foregroundStyle(.secondary)
29
30 if let description = repository.description,
31 !description.isEmpty {
32 Text(description)
33 .font(.subheadline)
34 .foregroundStyle(.secondary)
35 .lineLimit(2)
36 }
37
38 HStack(spacing: 12) {
39 if let defaultBranchName = repository.defaultBranchName {
40 Label(defaultBranchName, systemImage: "arrow.triangle.branch")
41 .font(.caption)
42 .foregroundStyle(.secondary)
43 }
44
45 Spacer()
46
47 Text(repository.updated.relativeDescription)
48 .font(.caption)
49 .foregroundStyle(.tertiary)
50 }
51 }
52 .padding(.vertical, 2)
53 .contextMenu {
54 if let url = SRHTWebURL.repository(repository) {
55 Button {
56 openURL(url)
57 } label: {
58 Label("Open in Browser", systemImage: "safari")
59 }
60 }
61
62 Button {
63 if let url = SRHTWebURL.repository(repository)?.absoluteString {
64 appState.copyToPasteboard(url, label: "repository URL")
65 }
66 } label: {
67 Label("Copy URL", systemImage: "doc.on.doc")
68 }
69
70 Button {
71 if let url = SRHTWebURL.httpsCloneURL(repository) {
72 appState.copyToPasteboard(url, label: "HTTPS clone URL")
73 }
74 } label: {
75 Label("Copy HTTPS URL", systemImage: "doc.on.doc")
76 }
77
78 Button {
79 appState.copyToPasteboard(SRHTWebURL.sshCloneURL(repository), label: "SSH clone URL")
80 } label: {
81 Label("Copy SSH URL", systemImage: "terminal")
82 }
83
84 Button {
85 appState.copyToPasteboard(repository.rid, label: "repository RID")
86 } label: {
87 Label("Copy RID", systemImage: "number")
88 }
89 }
90 }
91}
92
93private struct RepositoryBuildStatusIndicator: View {
94 let status: RepositoryBuildStatus
95
96 var body: some View {
97 Circle()
98 .fill(color)
99 .frame(width: 8, height: 8)
100 .overlay {
101 Circle()
102 .strokeBorder(.primary.opacity(0.08))
103 }
104 .accessibilityLabel(accessibilityLabel)
105 }
106
107 private var color: Color {
108 switch status {
109 case .success:
110 .green
111 case .failed:
112 .red
113 case .running:
114 .orange
115 case .none:
116 .clear
117 }
118 }
119
120 private var accessibilityLabel: String {
121 switch status {
122 case .success:
123 "Latest build succeeded"
124 case .failed:
125 "Latest build failed"
126 case .running:
127 "Latest build is running"
128 case .none:
129 "No recent builds"
130 }
131 }
132}
133
134// MARK: - VisibilityBadge
135
136struct VisibilityBadge: View {
137 let visibility: Visibility
138
139 var body: some View {
140 Text(label)
141 .font(.caption2.weight(.medium))
142 .padding(.horizontal, 6)
143 .padding(.vertical, 2)
144 .background(color.opacity(0.15), in: Capsule())
145 .foregroundStyle(color)
146 }
147
148 private var label: String {
149 switch visibility {
150 case .public: "PUBLIC"
151 case .unlisted: "UNLISTED"
152 case .private: "PRIVATE"
153 }
154 }
155
156 private var color: Color {
157 switch visibility {
158 case .public: .green
159 case .unlisted: .orange
160 case .private: .red
161 }
162 }
163}