taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit d5e285e741f1ac2427c80e1f4fcf63a9439ede9f
parent b1da0929c1468ca0a44655a775d1f9fb3051faea
Author: Marc Stibane <marc@taler.net>
Date:   Sat, 15 Mar 2025 15:23:57 +0100

ErrorView (no sheet, but ZStack)

Diffstat:
MTalerWallet.xcodeproj/project.pbxproj | 12++++++------
ATalerWallet1/Views/Main/ErrorView.swift | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MTalerWallet1/Views/Main/MainView.swift | 6+++---
DTalerWallet1/Views/Sheets/ErrorSheet.swift | 125-------------------------------------------------------------------------------
MTalerWallet1/Views/Sheets/QRSheet.swift | 12++++++------
MTalerWallet1/Views/Sheets/Sheet.swift | 2+-
MTalerWallet1/Views/Transactions/TransactionSummaryV.swift | 6+++---
7 files changed, 144 insertions(+), 144 deletions(-)

diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj @@ -334,8 +334,8 @@ 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 */; }; + E3E48FB22B9B7B5400898A0F /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E48FB12B9B7B5400898A0F /* ErrorView.swift */; }; + E3E48FB32B9B7B5400898A0F /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E48FB12B9B7B5400898A0F /* ErrorView.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 */ @@ -547,7 +547,7 @@ 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>"; }; + E3E48FB12B9B7B5400898A0F /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; }; E3E48FB42B9B7D5000898A0F /* Encodable+toJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encodable+toJSON.swift"; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -894,6 +894,7 @@ isa = PBXGroup; children = ( 4EB095442989CBFE0043A8A1 /* MainView.swift */, + E3E48FB12B9B7B5400898A0F /* ErrorView.swift */, 4EED38542D140C1400F6C038 /* TabBarModel.swift */, 4EB095392989CBFE0043A8A1 /* WalletEmptyView.swift */, ); @@ -970,7 +971,6 @@ 4EB0952A2989CBFE0043A8A1 /* Payment */, E37AA62C2AF19BA6003850CF /* Refund */, 4E3B4BBF2A41E64000CC88B8 /* P2P_Sheets */, - E3E48FB12B9B7B5400898A0F /* ErrorSheet.swift */, ); path = Sheets; sourceTree = "<group>"; @@ -1329,7 +1329,7 @@ 4E3EAE452A990778009F1BE8 /* P2PReadyV.swift in Sources */, 4E3EAE462A990778009F1BE8 /* TextFieldAlert.swift in Sources */, 4E3EAE472A990778009F1BE8 /* QuiteSomeCoins.swift in Sources */, - E3E48FB22B9B7B5400898A0F /* ErrorSheet.swift in Sources */, + E3E48FB22B9B7B5400898A0F /* ErrorView.swift in Sources */, 4E2D8DD52B45822A00234039 /* AmountV.swift in Sources */, 4E3EAE492A990778009F1BE8 /* ManualWithdrawDone.swift in Sources */, 4E3EAE4B2A990778009F1BE8 /* ShareSheet.swift in Sources */, @@ -1474,7 +1474,7 @@ 4EB3136129FEE79B007D68BC /* P2PReadyV.swift in Sources */, 4EB0956B2989CBFE0043A8A1 /* TextFieldAlert.swift in Sources */, 4EBA82AD2A3F580500E5F39A /* QuiteSomeCoins.swift in Sources */, - E3E48FB32B9B7B5400898A0F /* ErrorSheet.swift in Sources */, + E3E48FB32B9B7B5400898A0F /* ErrorView.swift in Sources */, 4E2D8DD62B45822A00234039 /* AmountV.swift in Sources */, 4EB431672A1E55C700C5690E /* ManualWithdrawDone.swift in Sources */, 4E753A082A0B6A5F002D9328 /* ShareSheet.swift in Sources */, diff --git a/TalerWallet1/Views/Main/ErrorView.swift b/TalerWallet1/Views/Main/ErrorView.swift @@ -0,0 +1,125 @@ +/* + * This file is part of GNU Taler, ©2022-25 Taler Systems S.A. + * See LICENSE.md + */ +/** + * @author Iván Ávalos + */ +import SwiftUI +import taler_swift + +enum ErrorData { + case message(title: String, message: String) + case error(Error) +} + +struct ErrorView: View { + var title: String + var message: String? = nil + var copyable: Bool + + var onDismiss: () -> Void + + init(title: String, message: String? = nil, copyable: Bool, onDismiss: @escaping () -> Void) { + self.title = title + self.message = message + self.copyable = copyable + self.onDismiss = onDismiss + } + + init(error: Error, devMode: Bool, onDismiss: @escaping () -> Void) { + let walletCoreError = String(localized: "Internal core error") + let initializationError = String(localized: "Initialization error") + let serializationError = String(localized: "Serialization error") + let deserializationError = String(localized: "Deserialization error") + let unknownError = String(localized: "Unknown error") + + switch error { + case let walletError as WalletBackendError: + switch walletError { + case .walletCoreError(let error): + if let json = error?.toJSON(), devMode { + self.init(title: walletCoreError, message: json, copyable: true, onDismiss: onDismiss) + } else if let hint = error?.errorResponse?.hint ?? error?.hint { + self.init(title: walletCoreError, message: hint, copyable: false, onDismiss: onDismiss) + } else if let message = error?.message { + self.init(title: walletCoreError, message: message, copyable: false, onDismiss: onDismiss) + } else { + self.init(title: walletCoreError, copyable: false, onDismiss: onDismiss) + } + case .initializationError: + self.init(title: initializationError, copyable: false, onDismiss: onDismiss) + case .serializationError: + self.init(title: serializationError, copyable: false, onDismiss: onDismiss) + case .deserializationError: + self.init(title: deserializationError, copyable: false, onDismiss: onDismiss) + } + default: + self.init(title: unknownError, message: error.localizedDescription, copyable: false, onDismiss: onDismiss) + } + } + + init(data: ErrorData, devMode: Bool, onDismiss: @escaping () -> Void) { + switch data { + case .message(let title, let message): + self.init(title: title, message: message, copyable: false, onDismiss: onDismiss) + case .error(let error): + self.init(error: error, devMode: devMode, onDismiss: onDismiss) + } + } + + var body: some View { + ScrollView { + VStack { + Image(systemName: "exclamationmark.circle") + .resizable() + .frame(width: 50, height: 50) + .aspectRatio(contentMode: .fit) + .foregroundStyle(WalletColors().attention) + .padding() + + Text(title) + .talerFont(.title) + .padding(.bottom) + + if let message { + if copyable { + if #available(iOS 16.4, *) { + Text(message).monospaced() + } else { + Text(message).font(.system(.body, design: .monospaced)) + } + + CopyButton(textToCopy: message, vertical: false) + .accessibilityLabel("Copy the error JSON") + .padding() + } else { + Text(message) + .multilineTextAlignment(.center) + } + } + } + } + .padding() + .safeAreaInset(edge: .bottom) { + Button("Close", role: .cancel) { + onDismiss() + } + .buttonStyle(TalerButtonStyle(type: .bordered)) + .padding(.bottom) + .padding(.horizontal) + } + } +} + +struct ErrorSheet_Previews: PreviewProvider { + static let error = WalletBackendError.walletCoreError(WalletBackendResponseError( + code: 7025, when: Timestamp.now(), + hint: "A KYC step is required before withdrawal can proceed", + message: "A KYC step is required before withdrawal can proceed")) + + static var previews: some View { + ErrorView(error: error, devMode: true, onDismiss: {}) + ErrorView(error: error, devMode: false, onDismiss: {}) + } +} diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -82,7 +82,7 @@ struct MainView: View { if (!showScanner && urlToOpen == nil) { if let error2 = model.error2 { - ErrorSheet(data: error2, devMode: developerMode) { + ErrorView(data: error2, devMode: developerMode) { model.setError(nil) }.interactiveDismissDisabled() .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all)) @@ -96,8 +96,8 @@ struct MainView: View { let mainGroup = Group { switch controller.backendState { case .ready: mainContent - case .error: ErrorSheet(title: String(localized: ""), - copyable: true) {} + case .error: ErrorView(title: String(localized: ""), + copyable: true) {} default: // show launch animation until either ready or error LaunchAnimationView() } diff --git a/TalerWallet1/Views/Sheets/ErrorSheet.swift b/TalerWallet1/Views/Sheets/ErrorSheet.swift @@ -1,125 +0,0 @@ -/* - * This file is part of GNU Taler, ©2022-25 Taler Systems S.A. - * See LICENSE.md - */ -/** - * @author Iván Ávalos - */ -import SwiftUI -import taler_swift - -enum ErrorData { - case message(title: String, message: String) - case error(Error) -} - -struct ErrorSheet: View { - var title: String - var message: String? = nil - var copyable: Bool - - var onDismiss: () -> Void - - init(title: String, message: String? = nil, copyable: Bool, onDismiss: @escaping () -> Void) { - self.title = title - self.message = message - self.copyable = copyable - self.onDismiss = onDismiss - } - - init(error: Error, devMode: Bool, onDismiss: @escaping () -> Void) { - let walletCoreError = String(localized: "Internal core error") - let initializationError = String(localized: "Initialization error") - let serializationError = String(localized: "Serialization error") - let deserializationError = String(localized: "Deserialization error") - let unknownError = String(localized: "Unknown error") - - switch error { - case let walletError as WalletBackendError: - switch walletError { - case .walletCoreError(let error): - if let json = error?.toJSON(), devMode { - self.init(title: walletCoreError, message: json, copyable: true, onDismiss: onDismiss) - } else if let hint = error?.errorResponse?.hint ?? error?.hint { - self.init(title: walletCoreError, message: hint, copyable: false, onDismiss: onDismiss) - } else if let message = error?.message { - self.init(title: walletCoreError, message: message, copyable: false, onDismiss: onDismiss) - } else { - self.init(title: walletCoreError, copyable: false, onDismiss: onDismiss) - } - case .initializationError: - self.init(title: initializationError, copyable: false, onDismiss: onDismiss) - case .serializationError: - self.init(title: serializationError, copyable: false, onDismiss: onDismiss) - case .deserializationError: - self.init(title: deserializationError, copyable: false, onDismiss: onDismiss) - } - default: - self.init(title: unknownError, message: error.localizedDescription, copyable: false, onDismiss: onDismiss) - } - } - - init(data: ErrorData, devMode: Bool, onDismiss: @escaping () -> Void) { - switch data { - case .message(let title, let message): - self.init(title: title, message: message, copyable: false, onDismiss: onDismiss) - case .error(let error): - self.init(error: error, devMode: devMode, onDismiss: onDismiss) - } - } - - var body: some View { - ScrollView { - VStack { - Image(systemName: "exclamationmark.circle") - .resizable() - .frame(width: 50, height: 50) - .aspectRatio(contentMode: .fit) - .foregroundStyle(WalletColors().attention) - .padding() - - Text(title) - .talerFont(.title) - .padding(.bottom) - - if let message { - if copyable { - if #available(iOS 16.4, *) { - Text(message).monospaced() - } else { - Text(message).font(.system(.body, design: .monospaced)) - } - - CopyButton(textToCopy: message, vertical: false) - .accessibilityLabel("Copy the error JSON") - .padding() - } else { - Text(message) - .multilineTextAlignment(.center) - } - } - } - } - .padding() - .safeAreaInset(edge: .bottom) { - Button("Close", role: .cancel) { - onDismiss() - } - .buttonStyle(TalerButtonStyle(type: .bordered)) - .padding(.bottom) - .padding(.horizontal) - } - } -} - -struct ErrorSheet_Previews: PreviewProvider { - static let error = WalletBackendError.walletCoreError(WalletBackendResponseError( - code: 7025, when: Timestamp.now(), - hint: "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, devMode: true, onDismiss: {}) - ErrorSheet(error: error, devMode: false, onDismiss: {}) - } -} diff --git a/TalerWallet1/Views/Sheets/QRSheet.swift b/TalerWallet1/Views/Sheets/QRSheet.swift @@ -47,16 +47,16 @@ struct QRSheet: View { urlToOpen: $urlToOpen) } else { // let _ = print(scannedURL) // TODO: error logging - ErrorSheet(title: String(localized: "Scanned QR is no talerURI"), - message: scannedURL.absoluteString, - copyable: true) { + ErrorView(title: String(localized: "Scanned QR is no talerURI"), + message: scannedURL.absoluteString, + copyable: true) { dismissTop(stack.push()) } } } else { - ErrorSheet(title: String(localized: "Scanned QR is no URL"), - message: scannedCode, - copyable: true) { + ErrorView(title: String(localized: "Scanned QR is no URL"), + message: scannedCode, + copyable: true) { dismissTop(stack.push()) } } diff --git a/TalerWallet1/Views/Sheets/Sheet.swift b/TalerWallet1/Views/Sheets/Sheet.swift @@ -56,7 +56,7 @@ struct Sheet: View { .accessibilityValue(idString) } if let error2 = model.error2 { - ErrorSheet(data: error2, devMode: developerMode) { + ErrorView(data: error2, devMode: developerMode) { model.setError(nil) logger.log("ErrorSheet dismissTop") dismissTop(stack.push()) diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift @@ -298,9 +298,9 @@ struct TransactionSummaryV: View { badge: CONFIRM_BANK) } } } } @unknown default: - ErrorSheet(title: "Unknown withdrawal type", // should not happen, so no L10N - message: withdrawalDetails.type.rawValue, - copyable: true) { + ErrorView(title: "Unknown withdrawal type", // should not happen, so no L10N + message: withdrawalDetails.type.rawValue, + copyable: true) { dismissTop(stack.push()) } } // switch