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

Commit 900a7a5

Browse files
authored
Fix bug in CertificatesView
1 parent fcd4c24 commit 900a7a5

1 file changed

Lines changed: 100 additions & 85 deletions

File tree

Sources/prosign/views/CertificateView.swift

Lines changed: 100 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -57,89 +57,7 @@ struct CertificateView: View {
5757
ScrollView {
5858
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 20) {
5959
ForEach(customCertificates) { cert in
60-
ZStack(alignment: .top) {
61-
VStack(alignment: .leading, spacing: 12) {
62-
Text(cert.displayName)
63-
.font(.title2)
64-
.fontWeight(.semibold)
65-
.foregroundColor(.primary)
66-
if let expiry = certExpiries[cert.folderName] {
67-
let now = Date()
68-
let components = Calendar.current.dateComponents([.day], from: now, to: expiry)
69-
let days = components.day ?? 0
70-
let displayDate = expiry.formattedWithOrdinal()
71-
let expiryText: String
72-
if days > 0 {
73-
expiryText = "Expires in \(days) days on \(displayDate)"
74-
} else {
75-
let pastDays = abs(days)
76-
expiryText = "Expired \(pastDays) days ago on \(displayDate)"
77-
}
78-
Text(expiryText)
79-
.font(.caption)
80-
.fontWeight(.medium)
81-
.foregroundColor(.primary)
82-
} else {
83-
Text("No expiry date")
84-
.font(.caption)
85-
.fontWeight(.medium)
86-
.foregroundColor(.secondary)
87-
}
88-
}
89-
.padding(20)
90-
.frame(maxWidth: .infinity)
91-
.background(backgroundColor(for: cert.folderName))
92-
.cornerRadius(16)
93-
.overlay(
94-
RoundedRectangle(cornerRadius: 16)
95-
.stroke(selectedCert == cert.folderName ? Color.blue : Color.clear, lineWidth: 3)
96-
)
97-
.onTapGesture {
98-
// Only allow deselection if there are other certificates available
99-
if selectedCert == cert.folderName && customCertificates.count > 1 {
100-
if let nextCert = customCertificates.first(where: { $0.folderName != cert.folderName }) {
101-
selectedCert = nextCert.folderName
102-
UserDefaults.standard.set(selectedCert, forKey: "selectedCertificateFolder")
103-
}
104-
} else {
105-
selectedCert = cert.folderName
106-
UserDefaults.standard.set(selectedCert, forKey: "selectedCertificateFolder")
107-
}
108-
}
109-
110-
HStack {
111-
Button(action: {
112-
// EDIT: trigger identifiable sheet
113-
editingCertificate = cert
114-
}) {
115-
Image(systemName: "pencil")
116-
.foregroundColor(.blue)
117-
.font(.caption)
118-
.padding(8)
119-
.background(Color(.systemGray6).opacity(0.8))
120-
.clipShape(Circle())
121-
}
122-
123-
Spacer()
124-
125-
Button(action: {
126-
if customCertificates.count > 1 {
127-
certToDelete = cert
128-
showingDeleteAlert = true
129-
}
130-
}) {
131-
Image(systemName: "trash")
132-
.foregroundColor(customCertificates.count > 1 ? .red : .gray)
133-
.font(.caption)
134-
.padding(8)
135-
.background(Color(.systemGray6).opacity(0.8))
136-
.clipShape(Circle())
137-
}
138-
.disabled(customCertificates.count <= 1)
139-
}
140-
.padding(.top, 12)
141-
.padding(.horizontal, 12)
142-
}
60+
certificateItem(for: cert)
14361
}
14462
}
14563
.padding()
@@ -188,8 +106,70 @@ struct CertificateView: View {
188106
}
189107
}
190108

191-
private func backgroundColor(for folderName: String) -> Color {
192-
guard let expiry = certExpiries[folderName], expiry != nil else {
109+
private func certificateItem(for cert: CustomCertificate) -> some View {
110+
ZStack(alignment: .top) {
111+
certificateContent(for: cert)
112+
.onTapGesture {
113+
// Only allow deselection if there are other certificates available
114+
if selectedCert == cert.folderName && customCertificates.count > 1 {
115+
if let nextCert = customCertificates.first(where: { $0.folderName != cert.folderName }) {
116+
selectedCert = nextCert.folderName
117+
UserDefaults.standard.set(selectedCert, forKey: "selectedCertificateFolder")
118+
}
119+
} else {
120+
selectedCert = cert.folderName
121+
UserDefaults.standard.set(selectedCert, forKey: "selectedCertificateFolder")
122+
}
123+
}
124+
certificateButtons(for: cert)
125+
}
126+
}
127+
128+
private func certificateContent(for cert: CustomCertificate) -> some View {
129+
VStack(alignment: .leading, spacing: 12) {
130+
Text(cert.displayName)
131+
.font(.title2)
132+
.fontWeight(.semibold)
133+
.foregroundColor(.primary)
134+
if let expiry = certExpiries[cert.folderName] {
135+
expiryDisplay(for: expiry)
136+
} else {
137+
Text("No expiry date")
138+
.font(.caption)
139+
.fontWeight(.medium)
140+
.foregroundColor(.secondary)
141+
}
142+
}
143+
.padding(20)
144+
.frame(maxWidth: .infinity)
145+
.background(certificateBackground(for: cert))
146+
.cornerRadius(16)
147+
.overlay(
148+
RoundedRectangle(cornerRadius: 16)
149+
.stroke(selectedCert == cert.folderName ? Color.blue : Color.clear, lineWidth: 3)
150+
)
151+
}
152+
153+
private func expiryDisplay(for expiry: Date) -> some View {
154+
let now = Date()
155+
let components = Calendar.current.dateComponents([.day], from: now, to: expiry)
156+
let days = components.day ?? 0
157+
let displayDate = expiry.formattedWithOrdinal()
158+
let expiryText: String
159+
if days > 0 {
160+
expiryText = "Expires in \(days) days on \(displayDate)"
161+
} else {
162+
let pastDays = abs(days)
163+
expiryText = "Expired \(pastDays) days ago on \(displayDate)"
164+
}
165+
return Text(expiryText)
166+
.font(.caption)
167+
.fontWeight(.medium)
168+
.foregroundColor(.primary)
169+
}
170+
171+
private func certificateBackground(for cert: CustomCertificate) -> Color {
172+
guard let expiry = certExpiries[cert.folderName], expiry != nil else {
193173
return Color.clear
194174
}
195175
let now = Date()
@@ -204,6 +184,41 @@ struct CertificateView: View {
204184
return .green.opacity(0.15)
205185
}
206186
}
187+
188+
private func certificateButtons(for cert: CustomCertificate) -> some View {
189+
HStack {
190+
Button(action: {
191+
// EDIT: trigger identifiable sheet
192+
editingCertificate = cert
193+
}) {
194+
Image(systemName: "pencil")
195+
.foregroundColor(.blue)
196+
.font(.caption)
197+
.padding(8)
198+
.background(Color(.systemGray6).opacity(0.8))
199+
.clipShape(Circle())
200+
}
201+
202+
Spacer()
203+
204+
Button(action: {
205+
if customCertificates.count > 1 {
206+
certToDelete = cert
207+
showingDeleteAlert = true
208+
}
209+
}) {
210+
Image(systemName: "trash")
211+
.foregroundColor(customCertificates.count > 1 ? .red : .gray)
212+
.font(.caption)
213+
.padding(8)
214+
.background(Color(.systemGray6).opacity(0.8))
215+
.clipShape(Circle())
216+
}
217+
.disabled(customCertificates.count <= 1)
218+
}
219+
.padding(.top, 12)
220+
.padding(.horizontal, 12)
221+
}
207222

208223
private func reloadCertificatesAndEnsureSelection() {
209224
customCertificates = CertificateFileManager.shared.loadCertificates()

0 commit comments

Comments
 (0)