ErrorView.swift (5227B)
1 /* 2 * This file is part of GNU Taler, ©2022-26 Taler Systems S.A. 3 * See LICENSE.md 4 */ 5 /** 6 * @author Iván Ávalos 7 */ 8 import SwiftUI 9 import taler_swift 10 11 enum ErrorData { 12 case message(title: String, message: String) 13 case error(Error) 14 } 15 16 struct ErrorView: View { 17 let stack: CallStack 18 var title: String 19 var message: String? = nil 20 var copyable: Bool 21 22 var onDismiss: () -> Void 23 24 init(_ stack: CallStack, title: String, message: String? = nil, copyable: Bool, onDismiss: @escaping () -> Void) { 25 self.stack = stack 26 self.title = title 27 self.message = message 28 self.copyable = copyable 29 self.onDismiss = onDismiss 30 } 31 32 init(_ stack: CallStack, error: Error, devMode: Bool, onDismiss: @escaping () -> Void) { 33 let internetError = String(localized: "Network problem") 34 let internetMessage = String(localized: "Please check your internet connection and try again.") 35 let walletCoreError = String(localized: "Internal core error") 36 let initializationError = String(localized: "Initialization error") 37 let serializationError = String(localized: "Serialization error") 38 let deserializationError = String(localized: "Deserialization error") 39 let unknownError = String(localized: "Unknown error") 40 41 switch error { 42 case let walletError as WalletBackendError: 43 switch walletError { 44 case .walletCoreError(let walletBackendResponseError): 45 if let responseError = walletBackendResponseError { 46 if responseError.code == 7001 { 47 self.init(stack, title: internetError, message: internetMessage, copyable: false, onDismiss: onDismiss) 48 break 49 } 50 } 51 if let json = walletBackendResponseError?.toJSON(), devMode { 52 self.init(stack, title: walletCoreError, message: json, copyable: true, onDismiss: onDismiss) 53 } else if let hint = walletBackendResponseError?.errorResponse?.hint ?? walletBackendResponseError?.hint { 54 self.init(stack, title: walletCoreError, message: hint, copyable: false, onDismiss: onDismiss) 55 } else if let message = walletBackendResponseError?.message { 56 self.init(stack, title: walletCoreError, message: message, copyable: false, onDismiss: onDismiss) 57 } else { 58 self.init(stack, title: walletCoreError, copyable: false, onDismiss: onDismiss) 59 } 60 case .initializationError: 61 self.init(stack, title: initializationError, copyable: false, onDismiss: onDismiss) 62 case .serializationError: 63 self.init(stack, title: serializationError, copyable: false, onDismiss: onDismiss) 64 case .deserializationError: 65 self.init(stack, title: deserializationError, copyable: false, onDismiss: onDismiss) 66 } 67 default: 68 self.init(stack, title: unknownError, message: error.localizedDescription, copyable: false, onDismiss: onDismiss) 69 } 70 } 71 72 init(_ stack: CallStack, data: ErrorData, devMode: Bool, onDismiss: @escaping () -> Void) { 73 switch data { 74 case .message(let title, let message): 75 self.init(stack, title: title, message: message, copyable: false, onDismiss: onDismiss) 76 case .error(let error): 77 self.init(stack, error: error, devMode: devMode, onDismiss: onDismiss) 78 } 79 } 80 81 var body: some View { 82 ScrollView { 83 VStack { 84 Image(systemName: EXCLAMATION) 85 .resizable() 86 .frame(width: 50, height: 50) 87 .aspectRatio(contentMode: .fit) 88 .foregroundStyle(WalletColors().attention) 89 .padding() 90 91 Text(title) 92 .talerFont(.title) 93 .padding(.bottom) 94 95 if let message { 96 if copyable { 97 if #available(iOS 16.4, *) { 98 Text(message).monospaced() 99 } else { 100 Text(message).font(.system(.body, design: .monospaced)) 101 } 102 103 CopyButton(textToCopy: message, vertical: false) 104 .accessibilityLabel(Text("Copy the error JSON", comment: "a11y")) 105 .padding() 106 } else { 107 Text(message) 108 .multilineTextAlignment(.center) 109 } 110 } 111 } 112 } 113 .padding() 114 .safeAreaInset(edge: .bottom) { 115 Button("Close", role: .cancel) { 116 onDismiss() 117 } 118 .buttonStyle(TalerButtonStyle(type: .bordered)) 119 .padding(.bottom) 120 .padding(.horizontal) 121 } 122 } 123 }