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

Commit f85e79f

Browse files
authored
Enhance CertificateView with new certificate handling
Added functionality to handle newly added certificates and improved state management for certificate selection.
1 parent 151276e commit f85e79f

1 file changed

Lines changed: 37 additions & 32 deletions

File tree

Sources/prosign/views/CertificateView.swift

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
// CertificateView.swift
22
import SwiftUI
33
import UniformTypeIdentifiers
4-
54
// Centralized types to avoid conflicts
65
struct CertificateFileItem {
76
var name: String = ""
87
var url: URL?
98
}
10-
119
struct CustomCertificate: Identifiable {
1210
let id = UUID()
1311
let displayName: String
1412
let folderName: String
1513
}
16-
1714
// MARK: - CertificateView (List + Add/Edit launchers)
1815
struct CertificateView: View {
1916
@State private var customCertificates: [CustomCertificate] = []
@@ -22,7 +19,8 @@ struct CertificateView: View {
2219
@State private var selectedCert: String? = nil
2320
@State private var showingDeleteAlert = false
2421
@State private var certToDelete: CustomCertificate?
25-
22+
@State private var newlyAddedFolder: String? = nil
23+
2624
var body: some View {
2725
// <-- Removed nested NavigationStack to avoid hiding the title from the parent stack
2826
ScrollView {
@@ -55,7 +53,7 @@ struct CertificateView: View {
5553
UserDefaults.standard.set(selectedCert, forKey: "selectedCertificateFolder")
5654
}
5755
}
58-
56+
5957
HStack {
6058
Button(action: {
6159
// EDIT: trigger identifiable sheet
@@ -68,9 +66,9 @@ struct CertificateView: View {
6866
.background(Color(.systemGray6).opacity(0.8))
6967
.clipShape(Circle())
7068
}
71-
69+
7270
Spacer()
73-
71+
7472
Button(action: {
7573
if customCertificates.count > 1 {
7674
certToDelete = cert
@@ -106,8 +104,13 @@ struct CertificateView: View {
106104
// ADD sheet (new certificate only)
107105
.sheet(isPresented: $showAddCertificateSheet, onDismiss: {
108106
reloadCertificatesAndEnsureSelection()
107+
if let newFolder = newlyAddedFolder {
108+
selectedCert = newFolder
109+
UserDefaults.standard.set(selectedCert, forKey: "selectedCertificateFolder")
110+
newlyAddedFolder = nil
111+
}
109112
}) {
110-
AddCertificateView()
113+
AddCertificateView(onSave: { newlyAddedFolder = $0 })
111114
.presentationDetents([.large])
112115
}
113116
// EDIT sheet (identifiable)
@@ -131,13 +134,13 @@ struct CertificateView: View {
131134
reloadCertificatesAndEnsureSelection()
132135
}
133136
}
134-
137+
135138
private func reloadCertificatesAndEnsureSelection() {
136139
customCertificates = CertificateFileManager.shared.loadCertificates()
137140
selectedCert = UserDefaults.standard.string(forKey: "selectedCertificateFolder")
138141
ensureSelection()
139142
}
140-
143+
141144
private func ensureSelection() {
142145
if selectedCert == nil || !customCertificates.contains(where: { $0.folderName == selectedCert }) {
143146
if let firstCert = customCertificates.first {
@@ -146,11 +149,11 @@ struct CertificateView: View {
146149
}
147150
}
148151
}
149-
152+
150153
private func deleteCertificate(_ cert: CustomCertificate) {
151154
try? CertificateFileManager.shared.deleteCertificate(folderName: cert.folderName)
152155
customCertificates = CertificateFileManager.shared.loadCertificates()
153-
156+
154157
if selectedCert == cert.folderName {
155158
if let newSelection = customCertificates.first {
156159
selectedCert = newSelection.folderName
@@ -163,12 +166,12 @@ struct CertificateView: View {
163166
ensureSelection()
164167
}
165168
}
166-
167169
// MARK: - Add / Edit View
168170
struct AddCertificateView: View {
169171
@Environment(\.dismiss) private var dismiss
170172
let editingCertificate: CustomCertificate?
171-
173+
let onSave: ((String) -> Void)?
174+
172175
@State private var p12File: CertificateFileItem?
173176
@State private var provFile: CertificateFileItem?
174177
@State private var password = ""
@@ -177,11 +180,12 @@ struct AddCertificateView: View {
177180
@State private var errorMessage = ""
178181
@State private var displayName: String = ""
179182
@State private var hasLoadedForEdit = false
180-
181-
init(editingCertificate: CustomCertificate? = nil) {
183+
184+
init(editingCertificate: CustomCertificate? = nil, onSave: ((String) -> Void)? = nil) {
182185
self.editingCertificate = editingCertificate
186+
self.onSave = onSave
183187
}
184-
188+
185189
var body: some View {
186190
// Use a NavigationStack inside the sheet so the sheet has its own nav bar
187191
NavigationStack {
@@ -201,7 +205,7 @@ struct AddCertificateView: View {
201205
}
202206
}
203207
.disabled(isChecking)
204-
208+
205209
Button(action: { activeSheet = .prov }) {
206210
HStack {
207211
Image(systemName: "gearshape.fill")
@@ -217,20 +221,20 @@ struct AddCertificateView: View {
217221
}
218222
.disabled(isChecking)
219223
}
220-
224+
221225
Section(header: Text("Display Name")) {
222226
TextField("Optional Display Name", text: $displayName)
223227
.disabled(isChecking)
224228
}
225-
229+
226230
Section(header: Text("Password")) {
227231
SecureField("Enter Password", text: $password)
228232
.disabled(isChecking)
229233
Text("Enter the password for the certificate. Leave it blank if there is no password needed.")
230234
.font(.caption)
231235
.foregroundColor(.secondary)
232236
}
233-
237+
234238
if !errorMessage.isEmpty {
235239
Text(errorMessage)
236240
.foregroundColor(.red)
@@ -246,7 +250,7 @@ struct AddCertificateView: View {
246250
}
247251
.disabled(isChecking)
248252
}
249-
253+
250254
ToolbarItem(placement: .navigationBarTrailing) {
251255
if isChecking {
252256
ProgressView()
@@ -279,17 +283,17 @@ struct AddCertificateView: View {
279283
}
280284
} // NavigationStack
281285
}
282-
286+
283287
private func loadForEdit(cert: CustomCertificate) {
284288
let certFolder = CertificateFileManager.shared.certificatesDirectory.appendingPathComponent(cert.folderName)
285289
let p12URL = certFolder.appendingPathComponent("certificate.p12")
286290
let provURL = certFolder.appendingPathComponent("profile.mobileprovision")
287291
let passwordURL = certFolder.appendingPathComponent("password.txt")
288292
let nameURL = certFolder.appendingPathComponent("name.txt")
289-
293+
290294
p12File = CertificateFileItem(name: "certificate.p12", url: p12URL)
291295
provFile = CertificateFileItem(name: "profile.mobileprovision", url: provURL)
292-
296+
293297
if let pwData = try? Data(contentsOf: passwordURL), let pw = String(data: pwData, encoding: .utf8) {
294298
password = pw
295299
}
@@ -299,10 +303,10 @@ struct AddCertificateView: View {
299303
}
300304
private func saveCertificate() {
301305
guard let p12URL = p12File?.url, let provURL = provFile?.url else { return }
302-
306+
303307
isChecking = true
304308
errorMessage = ""
305-
309+
306310
let workItem: DispatchWorkItem = DispatchWorkItem {
307311
do {
308312
var p12Data: Data
@@ -322,21 +326,22 @@ struct AddCertificateView: View {
322326
p12Data = try Data(contentsOf: p12URL)
323327
provData = try Data(contentsOf: provURL)
324328
}
325-
329+
326330
let checkResult = CertificatesManager.check(p12Data: p12Data, password: self.password, mobileProvisionData: provData)
327331
var dispatchError: String?
328-
332+
329333
switch checkResult {
330334
case .success(.success):
331335
// Generate displayName from cert if not set
332336
if localDisplayName.isEmpty {
333337
localDisplayName = CertificatesManager.getCertificateName(mobileProvisionData: provData) ?? "Custom Certificate"
334338
}
335-
339+
336340
if let folder = self.editingCertificate?.folderName {
337341
try CertificateFileManager.shared.updateCertificate(folderName: folder, p12Data: p12Data, provData: provData, password: self.password, displayName: localDisplayName)
338342
} else {
339-
_ = try CertificateFileManager.shared.saveCertificate(p12Data: p12Data, provData: provData, password: self.password, displayName: localDisplayName)
343+
let newFolder = try CertificateFileManager.shared.saveCertificate(p12Data: p12Data, provData: provData, password: self.password, displayName: localDisplayName)
344+
self.onSave?(newFolder)
340345
}
341346
case .success(.incorrectPassword):
342347
dispatchError = "Incorrect Password"
@@ -345,7 +350,7 @@ struct AddCertificateView: View {
345350
case .failure(let error):
346351
dispatchError = "Error: \(error.localizedDescription)"
347352
}
348-
353+
349354
DispatchQueue.main.async {
350355
self.isChecking = false
351356
if let err = dispatchError {

0 commit comments

Comments
 (0)