diff --git a/Mist/Model/MistError.swift b/Mist/Model/MistError.swift index 3a641b4..3331867 100644 --- a/Mist/Model/MistError.swift +++ b/Mist/Model/MistError.swift @@ -19,6 +19,7 @@ enum MistError: Error, Equatable { case invalidTerminationStatus(status: Int32, output: String?, error: String?) case invalidURL(_ url: String) case maximumRetriesReached + case missingDevicesKey case missingFileAttributes case outputStreamBufferError case outputStreamWriteError @@ -60,6 +61,8 @@ enum MistError: Error, Equatable { return "Invalid URL: '\(url)'" case .maximumRetriesReached: return "Maximum number of retries reached" + case .missingDevicesKey: + return "Missing 'devices' key" case .missingFileAttributes: return "Missing file attributes" case .outputStreamBufferError: diff --git a/Mist/Model/RefreshState.swift b/Mist/Model/RefreshState.swift index c7fa72a..7bd62cb 100644 --- a/Mist/Model/RefreshState.swift +++ b/Mist/Model/RefreshState.swift @@ -11,6 +11,7 @@ enum RefreshState: String, CaseIterable, Identifiable { case pending = "Pending" case inProgress = "In Progress" case complete = "Complete" + case warning = "Warning" case error = "Error" var id: String { @@ -25,6 +26,8 @@ enum RefreshState: String, CaseIterable, Identifiable { return "gear.circle.fill" case .complete: return "checkmark.circle.fill" + case .warning: + return "exclamationmark.triangle.fill" case .error: return "x.circle.fill" } @@ -38,6 +41,8 @@ enum RefreshState: String, CaseIterable, Identifiable { return .blue case .complete: return .green + case .warning: + return .yellow case .error: return .red } diff --git a/Mist/Views/Refresh/RefreshRowView.swift b/Mist/Views/Refresh/RefreshRowView.swift index 3043ca8..066fed0 100644 --- a/Mist/Views/Refresh/RefreshRowView.swift +++ b/Mist/Views/Refresh/RefreshRowView.swift @@ -25,7 +25,7 @@ struct RefreshRowView: View { Text(title) Spacer() ScaledSystemImage(systemName: state.systemName, length: trailingImageLength, renderingMode: .palette) - .foregroundStyle(.white, state.color) + .foregroundStyle((state == .warning ? .black : .white), state.color) .rotationEffect(.degrees(degrees)) .animation(animation, value: degrees) } diff --git a/Mist/Views/Refresh/RefreshView.swift b/Mist/Views/Refresh/RefreshView.swift index 1688972..8b8c18f 100644 --- a/Mist/Views/Refresh/RefreshView.swift +++ b/Mist/Views/Refresh/RefreshView.swift @@ -16,7 +16,9 @@ struct RefreshView: View { @State private var firmwaresState: RefreshState = .pending @State private var installersState: RefreshState = .pending private let width: CGFloat = 200 - private let height: CGFloat = 200 + private var height: CGFloat { + firmwaresState == .warning ? 230 : 200 + } private var buttonText: String { [.pending, .inProgress].contains(firmwaresState) || [.pending, .inProgress].contains(installersState) ? "Cancel" : "Close" } @@ -30,6 +32,10 @@ struct RefreshView: View { Spacer() VStack { RefreshRowView(image: "memorychip", title: "Firmwares...", state: $firmwaresState) + if firmwaresState == .warning { + Text("The Firmwares API is being updated, please try again shortly.") + .font(.caption) + } RefreshRowView(image: "desktopcomputer.and.arrow.down", title: "Installers...", state: $installersState) } .padding(.horizontal) @@ -61,7 +67,15 @@ struct RefreshView: View { } catch { successful = false try? await Task.sleep(nanoseconds: nanoseconds) - firmwaresState = .error + + if let error = error as? MistError, + error == .missingDevicesKey { + withAnimation { + firmwaresState = .warning + } + } else { + firmwaresState = .error + } } installersState = .inProgress @@ -93,11 +107,14 @@ struct RefreshView: View { let string: String = try String(contentsOf: firmwaresURL, encoding: .utf8) guard let data: Data = string.data(using: .utf8), - let dictionary: [String: Any] = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any], - let devices: [String: Any] = dictionary["devices"] as? [String: Any] else { + let dictionary: [String: Any] = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else { throw MistError.invalidData } + guard let devices: [String: Any] = dictionary["devices"] as? [String: Any] else { + throw MistError.missingDevicesKey + } + let supportedBuilds: [String] = try Firmware.supportedBuilds() for (identifier, device) in devices {