aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2024-03-08 13:27:44 -0600
committerIván Ávalos <avalos@disroot.org>2024-04-11 10:26:04 -0600
commitdb06fc9130deb1dfebeef69e33deb0299e73418d (patch)
tree361a5d416f96ea886c6db62de724f8f7f970bfb2
parentc38068b2d616bcdde39d0845f5be136fd1f1591d (diff)
downloadtaler-ios-db06fc9130deb1dfebeef69e33deb0299e73418d.tar.gz
taler-ios-db06fc9130deb1dfebeef69e33deb0299e73418d.tar.bz2
taler-ios-db06fc9130deb1dfebeef69e33deb0299e73418d.zip
Laying the foundations of improved error handling
-rw-r--r--TalerWallet.xcodeproj/project.pbxproj12
-rw-r--r--TalerWallet1/Controllers/Controller.swift20
-rw-r--r--TalerWallet1/Helper/Encodable+toJSON.swift22
-rw-r--r--TalerWallet1/Views/Main/MainView.swift15
-rw-r--r--TalerWallet1/Views/Sheets/ErrorSheet.swift88
5 files changed, 157 insertions, 0 deletions
diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj
index 9e801c2..c2be79e 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -278,6 +278,10 @@
E37AA62B2AF197E5003850CF /* Model+Refund.swift in Sources */ = {isa = PBXBuildFile; fileRef = E37AA6292AF197E5003850CF /* Model+Refund.swift */; };
E37AA62E2AF19BE0003850CF /* RefundURIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E37AA62D2AF19BE0003850CF /* RefundURIView.swift */; };
E37AA62F2AF19BE0003850CF /* RefundURIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E37AA62D2AF19BE0003850CF /* RefundURIView.swift */; };
+ E3E48FB22B9B7B5400898A0F /* ErrorSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E48FB12B9B7B5400898A0F /* ErrorSheet.swift */; };
+ E3E48FB32B9B7B5400898A0F /* ErrorSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E48FB12B9B7B5400898A0F /* ErrorSheet.swift */; };
+ E3E48FB52B9B7D5000898A0F /* Encodable+toJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E48FB42B9B7D5000898A0F /* Encodable+toJSON.swift */; };
+ E3E48FB62B9B7D5000898A0F /* Encodable+toJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E48FB42B9B7D5000898A0F /* Encodable+toJSON.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -458,6 +462,8 @@
D14AFD3E24D232B500C51073 /* TalerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TalerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E37AA6292AF197E5003850CF /* Model+Refund.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Model+Refund.swift"; sourceTree = "<group>"; };
E37AA62D2AF19BE0003850CF /* RefundURIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefundURIView.swift; sourceTree = "<group>"; };
+ E3E48FB12B9B7B5400898A0F /* ErrorSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorSheet.swift; sourceTree = "<group>"; };
+ E3E48FB42B9B7D5000898A0F /* Encodable+toJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encodable+toJSON.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -640,6 +646,7 @@
4E8E25322A1CD39700A27BFA /* EqualIconWidthDomain.swift */,
4EBA563E2A7FD9390084948B /* SuperScriptDigits.swift */,
4EC4008B2AE5664100DF72C7 /* CharacterSet+contains.swift */,
+ E3E48FB42B9B7D5000898A0F /* Encodable+toJSON.swift */,
);
path = Helper;
sourceTree = "<group>";
@@ -830,6 +837,7 @@
4EB0952A2989CBFE0043A8A1 /* Payment */,
E37AA62C2AF19BA6003850CF /* Refund */,
4E3B4BBF2A41E64000CC88B8 /* P2P_Sheets */,
+ E3E48FB12B9B7B5400898A0F /* ErrorSheet.swift */,
);
path = Sheets;
sourceTree = "<group>";
@@ -1130,6 +1138,7 @@
4E3EAE312A990778009F1BE8 /* SendAmount.swift in Sources */,
4E3EAE332A990778009F1BE8 /* EqualIconWidthDomain.swift in Sources */,
4EEC11932B83FB7A00146CFF /* SubjectInputV.swift in Sources */,
+ E3E48FB52B9B7D5000898A0F /* Encodable+toJSON.swift in Sources */,
4E3EAE342A990778009F1BE8 /* SuperScriptDigits.swift in Sources */,
4E3EAE352A990778009F1BE8 /* P2pPayURIView.swift in Sources */,
4E3EAE362A990778009F1BE8 /* Model+Payment.swift in Sources */,
@@ -1151,6 +1160,7 @@
4E3EAE452A990778009F1BE8 /* P2PReadyV.swift in Sources */,
4E3EAE462A990778009F1BE8 /* TextFieldAlert.swift in Sources */,
4E3EAE472A990778009F1BE8 /* QuiteSomeCoins.swift in Sources */,
+ E3E48FB22B9B7B5400898A0F /* ErrorSheet.swift in Sources */,
4E2D8DD52B45822A00234039 /* AmountV.swift in Sources */,
4E3EAE492A990778009F1BE8 /* ManualWithdrawDone.swift in Sources */,
4E3EAE4B2A990778009F1BE8 /* ShareSheet.swift in Sources */,
@@ -1247,6 +1257,7 @@
4E40E0BE29F25ABB00B85369 /* SendAmount.swift in Sources */,
4E8E25332A1CD39700A27BFA /* EqualIconWidthDomain.swift in Sources */,
4EEC11942B83FB7A00146CFF /* SubjectInputV.swift in Sources */,
+ E3E48FB62B9B7D5000898A0F /* Encodable+toJSON.swift in Sources */,
4EBA563F2A7FD9390084948B /* SuperScriptDigits.swift in Sources */,
4E578E942A4822D500F21F1C /* P2pPayURIView.swift in Sources */,
4EB095542989CBFE0043A8A1 /* Model+Payment.swift in Sources */,
@@ -1268,6 +1279,7 @@
4EB3136129FEE79B007D68BC /* P2PReadyV.swift in Sources */,
4EB0956B2989CBFE0043A8A1 /* TextFieldAlert.swift in Sources */,
4EBA82AD2A3F580500E5F39A /* QuiteSomeCoins.swift in Sources */,
+ E3E48FB32B9B7B5400898A0F /* ErrorSheet.swift in Sources */,
4E2D8DD62B45822A00234039 /* AmountV.swift in Sources */,
4EB431672A1E55C700C5690E /* ManualWithdrawDone.swift in Sources */,
4E753A082A0B6A5F002D9328 /* ShareSheet.swift in Sources */,
diff --git a/TalerWallet1/Controllers/Controller.swift b/TalerWallet1/Controllers/Controller.swift
index 03c6997..d0941f8 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -48,6 +48,13 @@ class Controller: ObservableObject {
var messageForSheet: String? = nil
+ @Published var showError: Bool = false
+ @Published var error: WalletBackendResponseError? = nil {
+ didSet {
+ self.showError = error != nil
+ }
+ }
+
init() {
// for family in UIFont.familyNames {
// print(family)
@@ -218,3 +225,16 @@ extension Controller {
return .unknown
}
}
+
+// MARK: -
+extension Controller {
+ @MainActor
+ func showError(error: WalletBackendResponseError) {
+ self.error = error
+ }
+
+ @MainActor
+ func cleanError() {
+ self.error = nil
+ }
+}
diff --git a/TalerWallet1/Helper/Encodable+toJSON.swift b/TalerWallet1/Helper/Encodable+toJSON.swift
new file mode 100644
index 0000000..265148d
--- /dev/null
+++ b/TalerWallet1/Helper/Encodable+toJSON.swift
@@ -0,0 +1,22 @@
+//
+// Codable+toJson.swift
+// TalerWallet
+//
+// Created by Ivan Avalos on 08/03/24.
+// Copyright © 2024 Taler. All rights reserved.
+//
+
+import Foundation
+
+extension Encodable {
+ func toJSON(_ encoder: JSONEncoder = JSONEncoder()) -> String? {
+ let e = encoder
+ e.outputFormatting = .prettyPrinted
+ if let data = try? e.encode(self) {
+ let result = String(decoding: data, as: UTF8.self)
+ return String(result)
+ }
+
+ return nil
+ }
+}
diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift
index 6563daa..6c9100c 100644
--- a/TalerWallet1/Views/Main/MainView.swift
+++ b/TalerWallet1/Views/Main/MainView.swift
@@ -101,6 +101,12 @@ extension MainView {
@State private var showKycAlert: Bool = false
@State private var kycURI: URL?
+#if DEBUG
+ @AppStorage("developerMode") var developerMode: Bool = true
+#else
+ @AppStorage("developerMode") var developerMode: Bool = false
+#endif
+
private var openKycButton: some View {
Button("KYC") {
showKycAlert = false
@@ -249,6 +255,15 @@ extension MainView {
}
}
}
+ .sheet(isPresented: $controller.showError) {
+ controller.cleanError()
+ } content: {
+ if let error = controller.error {
+ ErrorSheet(error: error, developerMode: developerMode) {
+ controller.cleanError()
+ }
+ }
+ }
} // body
} // Content
}
diff --git a/TalerWallet1/Views/Sheets/ErrorSheet.swift b/TalerWallet1/Views/Sheets/ErrorSheet.swift
new file mode 100644
index 0000000..5b64cf3
--- /dev/null
+++ b/TalerWallet1/Views/Sheets/ErrorSheet.swift
@@ -0,0 +1,88 @@
+//
+// ErrorSheet.swift
+// TalerWallet
+//
+// Created by Ivan Avalos on 08/03/24.
+// Copyright © 2024 Taler. All rights reserved.
+//
+
+import SwiftUI
+
+struct ErrorSheet: View {
+ var message: String
+ var copyable: Bool
+
+ var onDismiss: () -> Void
+
+ let navTitle = String(localized: "Error")
+
+ init(message: String, copyable: Bool, onDismiss: @escaping () -> Void) {
+ self.message = message
+ self.copyable = copyable
+ self.onDismiss = onDismiss
+ }
+
+ init(error: WalletBackendResponseError, developerMode: Bool, onDismiss: @escaping () -> Void) {
+ if let json = error.toJSON(), developerMode {
+ self.init(message: json, copyable: true, onDismiss: onDismiss)
+ } else {
+ self.init(message: error.message, copyable: false, onDismiss: onDismiss)
+ }
+ }
+
+ var body: some View {
+ NavigationView {
+ VStack {
+ Image(systemName: "exclamationmark.circle.fill")
+ .resizable()
+ .frame(width: 100, height: 100)
+ .aspectRatio(contentMode: .fit)
+ .foregroundStyle(.red)
+ .padding(.bottom)
+
+ if copyable {
+ if #available(iOS 16.4, *) {
+ Text(message)
+ .foregroundStyle(.red)
+ .monospaced()
+ } else {
+ Text(message)
+ .foregroundStyle(.red)
+ .font(.system(.body, design: .monospaced))
+ }
+
+ CopyButton(textToCopy: message, vertical: false)
+ .accessibilityLabel("Copy the error JSON")
+ .padding(.top)
+ } else {
+ Text(message)
+ .multilineTextAlignment(.center)
+ }
+ }
+ .navigationTitle(navTitle)
+ .navigationBarTitleDisplayMode(.inline)
+ .toolbar {
+ ToolbarItem {
+ Button {
+ onDismiss()
+ } label: {
+ Label("Close", systemImage: "xmark.circle")
+ }
+ }
+ }
+ .padding()
+ }
+ }
+}
+
+struct ErrorSheet_Previews: PreviewProvider {
+ static let error = WalletBackendResponseError(
+ talerErrorCode: 7025,
+ talerErrorHint: "A KYC step is required before withdrawal can proceed",
+ message: "A KYC step is required before withdrawal can proceed")
+
+ static var previews: some View {
+ ErrorSheet(error: error, developerMode: true, onDismiss: {})
+ ErrorSheet(error: error, developerMode: false, onDismiss: {})
+ }
+}