Improve compose posting error messages

This commit is contained in:
Shadowfacts 2020-09-09 18:33:59 -04:00
parent e19a6528ad
commit 7c4bbfd730
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
5 changed files with 57 additions and 23 deletions

View File

@ -50,22 +50,22 @@ public class Client {
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
completion(.failure(.networkError(error)))
return
}
guard let data = data,
let response = response as? HTTPURLResponse else {
completion(.failure(Error.invalidResponse))
completion(.failure(.invalidResponse))
return
}
guard response.statusCode == 200 else {
let mastodonError = try? self.decoder.decode(MastodonError.self, from: data)
let error = mastodonError.flatMap { Error.mastodonError($0.description) } ?? Error.unknownError
let error: Error = mastodonError.flatMap { .mastodonError($0.description) } ?? .unexpectedStatus(response.statusCode)
completion(.failure(error))
return
}
guard let result = try? self.decoder.decode(Result.self, from: data) else {
completion(.failure(Error.invalidModel))
completion(.failure(.invalidModel))
return
}
let pagination = response.allHeaderFields["Link"].flatMap { $0 as? String }.flatMap(Pagination.init)
@ -315,7 +315,8 @@ public class Client {
extension Client {
public enum Error: LocalizedError {
case unknownError
case networkError(Swift.Error)
case unexpectedStatus(Int)
case invalidRequest
case invalidResponse
case invalidModel
@ -323,8 +324,13 @@ extension Client {
public var localizedDescription: String {
switch self {
case .unknownError:
return "Unknown Error"
case .networkError(let error):
return "Network Error: \(error.localizedDescription)"
// todo: support more status codes
case .unexpectedStatus(413):
return "HTTP 413: Payload Too Large"
case .unexpectedStatus(let code):
return "HTTP Code \(code)"
case .invalidRequest:
return "Invalid Request"
case .invalidResponse:

View File

@ -10,5 +10,5 @@ import Foundation
public enum Response<Result: Decodable> {
case success(Result, Pagination?)
case failure(Error)
case failure(Client.Error)
}

View File

@ -22,16 +22,16 @@ public class InstanceSelector {
let request = URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
completion(.failure(error))
completion(.failure(.networkError(error)))
return
}
guard let data = data,
let response = response as? HTTPURLResponse else {
completion(.failure(Client.Error.invalidResponse))
completion(.failure(.invalidResponse))
return
}
guard response.statusCode == 200 else {
completion(.failure(Client.Error.unknownError))
completion(.failure(.unexpectedStatus(response.statusCode)))
return
}
guard let result = try? decoder.decode([Instance].self, from: data) else {

View File

@ -12,14 +12,14 @@ import Combine
struct ComposeView: View {
@ObservedObject var draft: Draft
@EnvironmentObject var mastodonController: MastodonController
@EnvironmentObject var uiState: ComposeUIState
@State var isPosting = false
@State var postProgress: Double = 0
@State var postTotalProgress: Double = 0
@State var isShowingPostErrorAlert = false
@State var postError: Error?
@State private var isPosting = false
@State private var postProgress: Double = 0
@State private var postTotalProgress: Double = 0
@State private var isShowingPostErrorAlert = false
@State private var postError: PostError?
private let stackPadding: CGFloat = 8
@ -191,6 +191,9 @@ struct ComposeView: View {
case let .failure(error):
self.isShowingPostErrorAlert = true
self.postError = error
self.postProgress = 0
self.postTotalProgress = 0
self.isPosting = false
case let .success(uploadedAttachments):
let request = Client.createStatus(text: draft.text,
@ -222,7 +225,7 @@ struct ComposeView: View {
}
}
private func uploadAttachments(_ completion: @escaping (Result<[Attachment], Error>) -> Void) {
private func uploadAttachments(_ completion: @escaping (Result<[Attachment], AttachmentUploadError>) -> Void) {
let group = DispatchGroup()
var anyFailed = false
@ -239,13 +242,13 @@ struct ComposeView: View {
let formAttachment = FormAttachment(mimeType: mimeType, data: data, fileName: "file")
let request = Client.upload(attachment: formAttachment, description: compAttachment.attachmentDescription)
self.mastodonController.run(request) { (response) in
postProgress += 1
switch response {
case let .failure(error):
uploadedAttachments[index] = .failure(error)
anyFailed = true
case let .success(attachment, _):
postProgress += 1
uploadedAttachments[index] = .success(attachment)
}
@ -274,14 +277,37 @@ struct ComposeView: View {
}
}
fileprivate struct AttachmentUploadError: LocalizedError {
fileprivate protocol PostError: LocalizedError {}
extension PostError {
var localizedDescription: String {
if let self = self as? Client.Error {
return self.localizedDescription
} else if let self = self as? AttachmentUploadError {
return self.localizedDescription
} else {
return "Unknown Error"
}
}
}
extension Client.Error: PostError {}
fileprivate struct AttachmentUploadError: PostError {
let errors: [Error?]
var localizedDescription: String {
return errors.enumerated().compactMap { (index, error) -> String? in
guard let error = error else { return nil }
return "Attachment \(index + 1): \(error.localizedDescription)"
}.joined(separator: ", ")
let description: String
// need to downcast to use more specific localizedDescription impl from Pachyderm
if let error = error as? Client.Error {
description = error.localizedDescription
} else {
description = error.localizedDescription
}
return "Attachment \(index + 1): \(description)"
}.joined(separator: ",\n")
}
}

View File

@ -21,6 +21,8 @@ struct WrappedProgressView: UIViewRepresentable {
func updateUIView(_ uiView: UIProgressView, context: Context) {
if total > 0 {
uiView.setProgress(Float(value / total), animated: true)
} else {
uiView.setProgress(0, animated: true)
}
}
}