Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit 69b2360

Browse files
authored
Enhance UI feedback and loading states in OfficialCertificatesView
1 parent f75bffd commit 69b2360

1 file changed

Lines changed: 44 additions & 5 deletions

File tree

Sources/prosign/views/CertificateView.swift

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct OfficialCertificatesView: View {
7474
@State private var selectedRelease: Release? = nil
7575
@State private var statusMessage = ""
7676
@State private var isChecking = false
77+
@State private var isLoadingReleases = true
7778
@State private var p12Data: Data? = nil
7879
@State private var provData: Data? = nil
7980
@State private var password: String? = nil
@@ -84,6 +85,16 @@ struct OfficialCertificatesView: View {
8485
statusMessage.contains("Success")
8586
}
8687

88+
private var statusColor: Color {
89+
if statusMessage.contains("Downloading") {
90+
return .yellow
91+
} else if isSuccess {
92+
return .green
93+
} else {
94+
return .red
95+
}
96+
}
97+
8798
private let dateFormatter: DateFormatter = {
8899
let f = DateFormatter()
89100
f.dateStyle = .medium
@@ -95,9 +106,13 @@ struct OfficialCertificatesView: View {
95106
Form {
96107
Section("Select Official Certificate") {
97108
Picker("Certificate", selection: $selectedRelease) {
98-
Text("Select a certificate").tag(nil as Release?)
99-
ForEach(releases) { release in
100-
Text(cleanName(release.name)).tag(release as Release?)
109+
if isLoadingReleases {
110+
Text("-- Loading --").tag(nil as Release?)
111+
} else {
112+
Text("-- Select a certificate --").tag(nil as Release?)
113+
ForEach(releases) { release in
114+
Text(cleanName(release.name)).tag(release as Release?)
115+
}
101116
}
102117
}
103118
}
@@ -119,7 +134,10 @@ struct OfficialCertificatesView: View {
119134
.disabled(selectedRelease == nil || isChecking)
120135
if !statusMessage.isEmpty {
121136
Text(statusMessage)
122-
.foregroundColor(isSuccess ? .green : .red)
137+
.foregroundColor(statusColor)
138+
}
139+
if let expiry = expiry {
140+
expiryDisplay(for: expiry)
123141
}
124142
}
125143
Section {
@@ -144,6 +162,25 @@ struct OfficialCertificatesView: View {
144162
}
145163
}
146164

165+
private func expiryDisplay(for expiry: Date) -> some View {
166+
let now = Date()
167+
let components = Calendar.current.dateComponents([.day], from: now, to: expiry)
168+
let days = components.day ?? 0
169+
let displayDate = expiry.formattedWithOrdinal()
170+
let expiryText: String
171+
let expiryColor: Color
172+
if days > 0 {
173+
expiryText = "Expires on the \(displayDate)"
174+
expiryColor = .green
175+
} else {
176+
expiryText = "Expired on the \(displayDate)"
177+
expiryColor = .red
178+
}
179+
return Text(expiryText)
180+
.foregroundColor(expiryColor)
181+
.font(.caption)
182+
}
183+
147184
private func isoDate(string: String) -> Date {
148185
let formatter = ISO8601DateFormatter()
149186
return formatter.date(from: string) ?? Date()
@@ -185,10 +222,12 @@ struct OfficialCertificatesView: View {
185222
let decoded = try decoder.decode([Release].self, from: decodeData)
186223
await MainActor.run {
187224
self.releases = decoded.sorted { isoDate(string: $0.publishedAt) > isoDate(string: $1.publishedAt) }
225+
self.isLoadingReleases = false
188226
}
189227
} catch {
190228
await MainActor.run {
191229
self.statusMessage = "Failed to fetch releases: \(error.localizedDescription)"
230+
self.isLoadingReleases = false
192231
}
193232
}
194233
}
@@ -275,7 +314,7 @@ struct OfficialCertificatesView: View {
275314
self.password = pw
276315
self.displayName = dispName
277316
self.expiry = exp
278-
self.statusMessage = "Success: Ready to add \(dispName), expires \(exp?.formattedWithOrdinal() ?? "Unknown")"
317+
self.statusMessage = "Success: Ready to add \(dispName)"
279318
self.isChecking = false
280319
}
281320
} catch {

0 commit comments

Comments
 (0)