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

Commit 2d84c9e

Browse files
authored
Enhance SignerView with progress and error states
Refactor SignerView to include progress tracking and error handling.
1 parent 62c1101 commit 2d84c9e

File tree

1 file changed

+103
-20
lines changed

1 file changed

+103
-20
lines changed

Sources/prosign/views/SignerView.swift

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import ProStoreTools
55
struct SignerView: View {
66
@StateObject private var ipa = FileItem()
77
@State private var isProcessing = false
8-
@State private var progressMessage = ""
8+
@State private var overallProgress: Double = 0.0
9+
@State private var currentStage: String = ""
10+
@State private var barColor: Color = .blue
11+
@State private var isError: Bool = false
12+
@State private var errorDetails: String = ""
913
@State private var showActivity = false
1014
@State private var activityURL: URL? = nil
1115
@State private var showPickerFor: PickerKind? = nil
@@ -73,18 +77,26 @@ struct SignerView: View {
7377
}
7478
.padding(.vertical, 8)
7579

76-
Section(header: Text("Status")
77-
.font(.headline)
78-
.foregroundColor(.primary)
79-
.padding(.top, 8)) {
80-
HStack {
81-
if isProcessing {
82-
ProgressView()
83-
.padding(.trailing, 8)
80+
if isProcessing || !currentStage.isEmpty {
81+
Section(header: Text("Progress")
82+
.font(.headline)
83+
.foregroundColor(.primary)
84+
.padding(.top, 8)) {
85+
HStack {
86+
Text(currentStage)
87+
.foregroundColor(currentStage == "Error" ? .red : currentStage == "Done!" ? .green : .primary)
88+
ProgressView(value: overallProgress)
89+
.progressViewStyle(.linear)
90+
.tint(barColor)
91+
.frame(maxWidth: .infinity)
92+
Text("\(Int(overallProgress * 100))%")
93+
.foregroundColor(currentStage == "Error" ? .red : currentStage == "Done!" ? .green : .primary)
94+
}
95+
if isError {
96+
Text(errorDetails)
97+
.foregroundColor(.red)
98+
.font(.subheadline)
8499
}
85-
Text(progressMessage)
86-
.foregroundColor(progressMessage.contains("Error") ? .red : progressMessage.contains("Done") ? .green : .primary)
87-
.animation(.easeIn, value: progressMessage)
88100
}
89101
}
90102
}
@@ -135,11 +147,23 @@ struct SignerView: View {
135147

136148
func runSign() {
137149
guard let ipaURL = ipa.url else {
138-
progressMessage = "Pick IPA file first 😅"
150+
currentStage = "Error"
151+
errorDetails = "Pick IPA file first 😅"
152+
isError = true
153+
withAnimation {
154+
overallProgress = 1.0
155+
barColor = .red
156+
}
139157
return
140158
}
141159
guard let selectedFolder = UserDefaults.standard.string(forKey: "selectedCertificateFolder") else {
142-
progressMessage = "No certificate selected 😅"
160+
currentStage = "Error"
161+
errorDetails = "No certificate selected 😅"
162+
isError = true
163+
withAnimation {
164+
overallProgress = 1.0
165+
barColor = .red
166+
}
143167
return
144168
}
145169
let certDir = CertificateFileManager.shared.certificatesDirectory.appendingPathComponent(selectedFolder)
@@ -148,7 +172,13 @@ struct SignerView: View {
148172
let passwordURL = certDir.appendingPathComponent("password.txt")
149173

150174
guard FileManager.default.fileExists(atPath: p12URL.path), FileManager.default.fileExists(atPath: provURL.path) else {
151-
progressMessage = "Error loading certificate files 😅"
175+
currentStage = "Error"
176+
errorDetails = "Error loading certificate files 😅"
177+
isError = true
178+
withAnimation {
179+
overallProgress = 1.0
180+
barColor = .red
181+
}
152182
return
153183
}
154184

@@ -161,7 +191,11 @@ struct SignerView: View {
161191
}
162192

163193
isProcessing = true
164-
progressMessage = "Starting signing process..."
194+
currentStage = "Preparing"
195+
overallProgress = 0.0
196+
barColor = .blue
197+
isError = false
198+
errorDetails = ""
165199

166200
ProStoreTools.sign(
167201
ipaURL: ipaURL,
@@ -170,7 +204,7 @@ struct SignerView: View {
170204
p12Password: p12Password,
171205
progressUpdate: { message in
172206
DispatchQueue.main.async {
173-
progressMessage = message
207+
updateProgress(from: message)
174208
}
175209
},
176210
completion: { result in
@@ -179,13 +213,62 @@ struct SignerView: View {
179213
switch result {
180214
case .success(let signedIPAURL):
181215
activityURL = signedIPAURL
182-
showActivity = true
183-
progressMessage = "Done! ✅ IPA ready to share 🎉"
216+
withAnimation {
217+
overallProgress = 1.0
218+
barColor = .green
219+
currentStage = "Done!"
220+
}
221+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
222+
showActivity = true
223+
}
184224
case .failure(let error):
185-
progressMessage = "Error ❌: \(error.localizedDescription)"
225+
withAnimation {
226+
overallProgress = 1.0
227+
barColor = .red
228+
currentStage = "Error"
229+
}
230+
isError = true
231+
errorDetails = error.localizedDescription
186232
}
187233
}
188234
}
189235
)
190236
}
237+
238+
private func updateProgress(from message: String) {
239+
withAnimation {
240+
if message.contains("Preparing") {
241+
currentStage = "Preparing"
242+
overallProgress = 0.0
243+
} else if message.contains("Unzipping") {
244+
currentStage = "Unzipping"
245+
if let pct = extractPercentage(from: message) {
246+
overallProgress = 0.25 + (pct / 100.0) * 0.25
247+
} else {
248+
overallProgress = 0.25
249+
}
250+
} else if message.contains("Signing") {
251+
currentStage = "Signing"
252+
overallProgress = 0.5
253+
} else if message.contains("Zipping") {
254+
currentStage = "Zipping"
255+
if let pct = extractPercentage(from: message) {
256+
overallProgress = 0.75 + (pct / 100.0) * 0.25
257+
} else {
258+
overallProgress = 0.75
259+
}
260+
}
261+
}
262+
}
263+
264+
private func extractPercentage(from message: String) -> Double? {
265+
if let range = message.range(of: "(") {
266+
let substring = message[range.lowerBound...]
267+
if let endRange = substring.range(of: "%)") {
268+
let pctString = substring[..<endRange.lowerBound].dropFirst()
269+
return Double(pctString)
270+
}
271+
}
272+
return nil
273+
}
191274
}

0 commit comments

Comments
 (0)