[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] branch master updated (c38068b -> 6b94fe0)
From: |
gnunet |
Subject: |
[taler-taler-ios] branch master updated (c38068b -> 6b94fe0) |
Date: |
Thu, 11 Apr 2024 23:13:32 +0200 |
This is an automated email from the git hooks/post-receive script.
marc-stibane pushed a change to branch master
in repository taler-ios.
from c38068b details for refresh tx
new 6413ef7 rename setConfig
new da472b3 Bump version to 0.9.6 (1)
new be420ef updateExchangeEntry (temporarily) back to exchangeBaseUrl
(instead of scopeInfo)
new f2b2e74 emitObservabilityEvents
new aa7472d symLog after quickjs.sendMessage returned
new a44efce clientCancellationId
new 60c7ee2 Laying the foundations of improved error handling
new 6cb8d57 Improve errors and move them to WalletModel
new f7c55f5 Implement error handling all around (+refactoring)
new fa74633 Improvements to error dialog
new 7cecef9 Prepare notification error handling
new 8ba4476 Centralize all error handling in the model
new 08a200e Fixes for error handling rebase
new eb30e3e catch WalletBackendError.walletCoreError
new 643226c cleanup
new 7587ccd error handling, logging
new 6b94fe0 Bump version to 0.9.7 (1)
The 17 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
TalerWallet.xcodeproj/project.pbxproj | 28 +++--
TalerWallet1/Backend/WalletBackendError.swift | 21 ++--
TalerWallet1/Backend/WalletCore.swift | 31 +++--
TalerWallet1/Controllers/Controller.swift | 36 ++----
TalerWallet1/Controllers/DebugViewC.swift | 9 +-
TalerWallet1/Controllers/PublicConstants.swift | 3 +
TalerWallet1/Helper/Encodable+toJSON.swift | 21 ++++
TalerWallet1/Model/Model+Balances.swift | 15 +--
TalerWallet1/Model/Model+Deposit.swift | 12 +-
TalerWallet1/Model/Model+Exchange.swift | 61 +++++-----
TalerWallet1/Model/Model+P2P.swift | 36 +++---
TalerWallet1/Model/Model+Payment.swift | 12 +-
TalerWallet1/Model/Model+Pending.swift | 14 +--
TalerWallet1/Model/Model+Refund.swift | 8 +-
TalerWallet1/Model/Model+Settings.swift | 12 +-
TalerWallet1/Model/Model+Transactions.swift | 42 +++----
TalerWallet1/Model/Model+Withdraw.swift | 36 +++---
TalerWallet1/Model/Transaction.swift | 1 +
TalerWallet1/Model/WalletModel.swift | 47 +++++---
TalerWallet1/Views/Balances/BalancesListView.swift | 19 +--
.../Views/Balances/BalancesSectionView.swift | 21 ++--
TalerWallet1/Views/Banking/DepositAmountV.swift | 12 +-
TalerWallet1/Views/Banking/DepositIbanV.swift | 11 +-
TalerWallet1/Views/Banking/DepositWithdrawV.swift | 13 ++-
TalerWallet1/Views/Banking/ExchangeListView.swift | 11 +-
TalerWallet1/Views/Banking/ExchangeRowView.swift | 5 +-
TalerWallet1/Views/Banking/ManualWithdraw.swift | 24 +++-
.../Views/Banking/ManualWithdrawDone.swift | 13 +--
TalerWallet1/Views/HelperViews/AmountInputV.swift | 5 +-
TalerWallet1/Views/HelperViews/BarGraph.swift | 8 +-
TalerWallet1/Views/HelperViews/SubjectInputV.swift | 5 +-
.../Views/HelperViews/TransactionButton.swift | 9 +-
TalerWallet1/Views/Main/MainView.swift | 37 +++++-
TalerWallet1/Views/Main/WalletEmptyView.swift | 6 +-
TalerWallet1/Views/Peer2peer/P2PReadyV.swift | 48 ++++----
TalerWallet1/Views/Peer2peer/P2PSubjectV.swift | 5 +-
TalerWallet1/Views/Peer2peer/RequestPayment.swift | 16 +--
TalerWallet1/Views/Peer2peer/SendAmount.swift | 12 +-
TalerWallet1/Views/Settings/SettingsView.swift | 62 +++-------
TalerWallet1/Views/Sheets/ErrorSheet.swift | 130 +++++++++++++++++++++
.../Views/Sheets/P2P_Sheets/P2pAcceptDone.swift | 16 ++-
.../Views/Sheets/P2P_Sheets/P2pPayURIView.swift | 6 +-
.../Sheets/P2P_Sheets/P2pReceiveURIView.swift | 11 +-
.../Views/Sheets/Payment/PayTemplateV.swift | 14 +--
.../Views/Sheets/Payment/PaymentDone.swift | 14 +--
.../Views/Sheets/Payment/PaymentView.swift | 19 ++-
.../Views/Sheets/Refund/RefundURIView.swift | 11 +-
TalerWallet1/Views/Sheets/Sheet.swift | 22 +++-
.../WithdrawAcceptDone.swift | 16 +--
.../WithdrawBankIntegrated/WithdrawTOSView.swift | 40 +++----
.../WithdrawBankIntegrated/WithdrawURIView.swift | 21 ++--
TalerWallet1/Views/Sheets/WithdrawExchangeV.swift | 15 +--
.../Views/Transactions/TransactionSummaryV.swift | 18 ++-
.../Views/Transactions/TransactionsListView.swift | 4 +-
TestFlight/WhatToTest.en-US.txt | 15 +++
55 files changed, 643 insertions(+), 516 deletions(-)
create mode 100644 TalerWallet1/Helper/Encodable+toJSON.swift
create mode 100644 TalerWallet1/Views/Sheets/ErrorSheet.swift
diff --git a/TalerWallet.xcodeproj/project.pbxproj
b/TalerWallet.xcodeproj/project.pbxproj
index 9e801c2..417df6e 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 */,
@@ -1372,7 +1384,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1390,7 +1402,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.5;
+ MARKETING_VERSION = 0.9.7;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-1";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1414,7 +1426,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1432,7 +1444,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.5;
+ MARKETING_VERSION = 0.9.7;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-1";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1573,7 +1585,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1591,7 +1603,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.5;
+ MARKETING_VERSION = 0.9.7;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-2";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1615,7 +1627,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1633,7 +1645,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.5;
+ MARKETING_VERSION = 0.9.7;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-2";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/TalerWallet1/Backend/WalletBackendError.swift
b/TalerWallet1/Backend/WalletBackendError.swift
index 9b4cea4..1465988 100644
--- a/TalerWallet1/Backend/WalletBackendError.swift
+++ b/TalerWallet1/Backend/WalletBackendError.swift
@@ -4,6 +4,7 @@
*/
/**
* @author Marc Stibane
+ * @author Iván Ávalos
*/
import Foundation
@@ -13,38 +14,38 @@ enum WalletBackendError: Error {
case initializationError
case serializationError
case deserializationError
- case walletCoreError
+ case walletCoreError(WalletBackendResponseError?)
}
/// Information supplied by the backend describing an error.
struct WalletBackendResponseError: Codable {
/// Numeric error code defined defined in the GANA gnu-taler-error-codes
registry.
- var talerErrorCode: Int
+ var code: Int
/// English description of the error code.
- var talerErrorHint: String
+ var hint: String
/// English diagnostic message that can give details for the instance of
the error.
- var message: String
-
+ var message: String? = nil
+
/// Error details, type depends on `talerErrorCode`.
- var details: Data?
+ var details: Data? = nil
}
extension WalletCore {
static func serializeRequestError() -> WalletBackendResponseError {
- return WalletBackendResponseError(talerErrorCode: -1, talerErrorHint:
"Could not serialize request.", message: "")
+ return WalletBackendResponseError(code: -1, hint: "Could not serialize
request.", message: "")
}
static func parseResponseError() -> WalletBackendResponseError {
- return WalletBackendResponseError(talerErrorCode: -2, talerErrorHint:
"Could not parse response.", message: "")
+ return WalletBackendResponseError(code: -2, hint: "Could not parse
response.", message: "")
}
static func parseFailureError() -> WalletBackendResponseError {
- return WalletBackendResponseError(talerErrorCode: -3, talerErrorHint:
"Could not parse error detail.", message: "")
+ return WalletBackendResponseError(code: -3, hint: "Could not parse
error detail.", message: "")
}
static func walletError() -> WalletBackendResponseError {
- return WalletBackendResponseError(talerErrorCode: -4, talerErrorHint:
"Error detail.", message: "")
+ return WalletBackendResponseError(code: -4, hint: "Error detail.",
message: "")
}
}
diff --git a/TalerWallet1/Backend/WalletCore.swift
b/TalerWallet1/Backend/WalletCore.swift
index 8952261..47df531 100644
--- a/TalerWallet1/Backend/WalletCore.swift
+++ b/TalerWallet1/Backend/WalletCore.swift
@@ -2,6 +2,10 @@
* This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ * @author Iván Ávalos
+ */
import SwiftUI // FOUNDATION has no AppStorage
import AnyCodable
import FTalerWalletcore
@@ -62,7 +66,7 @@ class WalletCore: QuickjsMessageHandler {
let operation: String?
let id: UInt?
let result: AnyCodable?
- let error: AnyCodable? // should be WalletBackendResponseError?
+ let error: WalletBackendResponseError?
let payload: AnyCodable?
}
@@ -109,12 +113,10 @@ extension WalletCore {
let jsonData = try JSONEncoder().encode(walletError)
logger.error("wallet-core sent back an error for request
\(requestId, privacy: .public)")
symLog.log("id:\(requestId) \(walletError)")
- // TODO: decode jsonData to WalletBackendResponseError - or
HTTPError
- completion(requestId, timeSent, jsonData,
WalletCore.walletError())
+ completion(requestId, timeSent, jsonData, walletError)
} catch { // JSON encoding of response.result failed /
should never happen
symLog.log(decoded)
logger.error("cannot encode wallet-core Error")
- // TODO: show error alert
completion(requestId, timeSent, nil,
WalletCore.parseFailureError())
}
} else { // JSON decoding of error message failed
@@ -195,6 +197,11 @@ extension WalletCore {
logger.info("No State change: \(decoded.transactionId,
privacy: .private(mask: .hash))")
return
}
+
+ if decoded.errorInfo == nil {
+ postNotification(.Error, userInfo: [NOTIFICATIONERROR:
decoded.errorInfo])
+ }
+
let components = decoded.transactionId.components(separatedBy: ":")
if components.count >= 3 { // txn:$txtype:$uid
if let type = TransactionType(rawValue: components[1]) {
@@ -305,6 +312,7 @@ print("\n❗️ WalletCore.swift:251 Notification: ",
anyPayload, "\n") /
}
} catch let error {
symLog.log("Error \(error) parsing notification: \(anyPayload)")
// TODO: .error
+ postNotification(.Error, userInfo: [NOTIFICATIONERROR: error])
// TODO: if DevMode then should log into file for user
}
}
@@ -386,9 +394,9 @@ print("\n❗️ WalletCore.swift:251 Notification: ",
anyPayload, "\n") /
self.completions[requestId] = (sendTime, completionHandler)
self.requestsMade += 1
self.semaphore.signal() // free requestsMade
- self.symLog.log(jsonString)
self.logger.log("sendRequest \(requestId, privacy: .public):
\(request.operation, privacy: .public)")
self.quickjs.sendMessage(message: jsonString)
+ self.symLog.log(jsonString)
} catch { // call completion
self.semaphore.signal()
self.symLog.log(error)
@@ -407,9 +415,13 @@ extension WalletCore {
sendRequest(request: reqData) { requestId, timeSent, result, error
in
let timeUsed = Date.now - timeSent
let millisecs = timeUsed.milliseconds
- self.logger.info("Request \"id\":\(requestId, privacy:
.public) took \(millisecs, privacy: .public) ms")
+ if let error {
+ self.logger.error("Request \"id\":\(requestId, privacy:
.public) failed after \(millisecs, privacy: .public) ms")
+ } else {
+ self.logger.info("Request \"id\":\(requestId, privacy:
.public) took \(millisecs, privacy: .public) ms")
+ }
var err: Error? = nil
- if let json = result {
+ if let json = result, error == nil {
do {
let decoded = try
JSONDecoder().decode(T.Response.self, from: json)
continuation.resume(returning: (decoded, requestId))
@@ -434,12 +446,13 @@ extension WalletCore {
err = error // this will be thrown in
continuation.resume(throwing:), otherwise keep nil
}
} else {
- if let error = error {
+ // TODO: WALLET_CORE_REQUEST_CANCELLED
+ if let error {
self.lastError = FullError(type: "error", operation:
request.operation(), id: requestId, error: error)
} else {
self.lastError = nil
}
- err = WalletBackendError.walletCoreError
+ err = WalletBackendError.walletCoreError(error)
}
continuation.resume(throwing: err ??
TransactionDecodingError.invalidStringValue)
}
diff --git a/TalerWallet1/Controllers/Controller.swift
b/TalerWallet1/Controllers/Controller.swift
index 03c6997..a3b79ee 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -87,35 +87,15 @@ class Controller: ObservableObject {
}
@MainActor
- func getInfo(from exchangeBaseUrl: String, model: WalletModel) async ->
CurrencyInfo? {
- if let exchange = await model.getExchangeByUrl(url: exchangeBaseUrl) {
-// let scopeInfo = exchange.scopeInfo
-// if let info = hasInfo(for: scopeInfo.currency) {
-// return info
-// }
-// do {
-// let info = try await model.getCurrencyInfoM(scope:
scopeInfo, delay: 0)
-// await setInfo(info)
-// return info
-// } catch {
-// return nil
-// }
-
- let scopeInfo = exchange.scopeInfo
- if let info = hasInfo(for: scopeInfo.currency) {
- return info
- }
- do {
- let info = try await model.getCurrencyInfoM(scope: scopeInfo,
delay: 0)
- await setInfo(info)
- return info
- } catch {
- return nil
- }
- } else {
- // TODO: Error "Can't get Exchange Info"
+ func getInfo(from exchangeBaseUrl: String, model: WalletModel) async
throws -> CurrencyInfo? {
+ let exchange = try await model.getExchangeByUrl(url: exchangeBaseUrl)
+ let scopeInfo = exchange.scopeInfo
+ if let info = hasInfo(for: scopeInfo.currency) {
+ return info
}
- return nil
+ let info = try await model.getCurrencyInfoM(scope: scopeInfo, delay: 0)
+ await setInfo(info)
+ return info
}
@MainActor
diff --git a/TalerWallet1/Controllers/DebugViewC.swift
b/TalerWallet1/Controllers/DebugViewC.swift
index 8cd8108..c7de32f 100644
--- a/TalerWallet1/Controllers/DebugViewC.swift
+++ b/TalerWallet1/Controllers/DebugViewC.swift
@@ -39,15 +39,14 @@ public let VIEW_TRANSACTIONSUMMARY = VIEW_TRANSACTIONLIST +
1 // 22 Transa
public let VIEW_TRANSACTIONDETAIL = VIEW_TRANSACTIONSUMMARY + 1 // 23
TransactionDetail
-
// MARK: - Manual Withdrawal (from Banking / ExchangeList)
-// receive coins from bank ==> shows IBAN + Purpose/Subject for manual wire
transfer
+// receive coins from bank ==> shows payee, IBAN + Purpose/Subject for manual
wire transfer
public let VIEW_WITHDRAWAL = VIEW_EMPTY_HISTORY + 10 // 30
WithdrawAmount
public let VIEW_WITHDRAW_TOS = VIEW_WITHDRAWAL + 1 // 31
WithdrawTOSView
public let VIEW_WITHDRAW_ACCEPT = VIEW_WITHDRAW_TOS + 1 // 32
// MARK: Manual Deposit (from Banking / ExchangeList)
-// send coins back to bank account ==> orders exchange to make the wire
transfer
+// send coins back to customer ==> instruct exchange to make the wire transfer
to the customer's bank account
public let VIEW_DEPOSIT = VIEW_WITHDRAWAL + 10 // 40
Deposit Coins
//public let VIEW_DEPOSIT_TOS // - user
already accepted the ToS at withdrawal, invoice or receive
public let VIEW_DEPOSIT_ACCEPT = VIEW_DEPOSIT + 2 // 42
@@ -57,7 +56,7 @@ public let VIEW_DEPOSIT_ACCEPT = VIEW_DEPOSIT + 2
// 42
public let VIEW_P2P_SEND = VIEW_DEPOSIT + 10 // 50 Send
Coins
//public let VIEW_SEND_TOS // - user
already accepted the ToS at withdrawal, invoice or receive
public let VIEW_P2P_SUBJECT = VIEW_P2P_SEND + 2 // 52 Send
/ Request Subject
-public let VIEW_P2P_READY = VIEW_P2P_SEND + 3 // 53 Send
/ Request Ready
+public let VIEW_P2P_READY = VIEW_P2P_SUBJECT + 1 // 53 Send
/ Request Ready
// MARK: P2P Private Receive (from Balances)
// pull credit from another wallet ==> shows QR code to be scanned / link to
be sent by mail or messenger
@@ -104,6 +103,8 @@ public let SHEET_RCV_P2P_ACCEPT = SHEET_RCV_P2P_TOS + 1
// 162 Recei
// openURL (Link, NFC or scan QR) ==> receive coins from merchant
public let SHEET_REFUND = SHEET_RCV_P2P + 10 // 170
Receive Refunds
+
+// MARK: -
extension UIDevice {
var hasNotch: Bool {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
diff --git a/TalerWallet1/Controllers/PublicConstants.swift
b/TalerWallet1/Controllers/PublicConstants.swift
index 2eb2ad8..5b563d0 100644
--- a/TalerWallet1/Controllers/PublicConstants.swift
+++ b/TalerWallet1/Controllers/PublicConstants.swift
@@ -59,6 +59,8 @@ public let TALERURI = "talerUri"
public let TRANSACTIONTRANSITION = "transactionTransition"
public let TRANSACTIONID = "transactionID"
+public let NOTIFICATIONERROR = "error"
+
/// Notifications sent by wallet-core
extension Notification.Name {
static let BalanceChange = Notification.Name("balance-change")
@@ -79,6 +81,7 @@ extension Notification.Name {
// static let PayOperationSuccess =
Notification.Name("pay-operation-success")
static let ProposalAccepted = Notification.Name("proposal-accepted")
static let ProposalDownloaded = Notification.Name("proposal-downloaded")
+ static let Error = Notification.Name("error")
}
/// Notifications for internal synchronization
diff --git a/TalerWallet1/Helper/Encodable+toJSON.swift
b/TalerWallet1/Helper/Encodable+toJSON.swift
new file mode 100644
index 0000000..b2ffc74
--- /dev/null
+++ b/TalerWallet1/Helper/Encodable+toJSON.swift
@@ -0,0 +1,21 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+/**
+ * @author Iván Ávalos
+ */
+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/Model/Model+Balances.swift
b/TalerWallet1/Model/Model+Balances.swift
index 6d4be7f..09c5acd 100644
--- a/TalerWallet1/Model/Model+Balances.swift
+++ b/TalerWallet1/Model/Model+Balances.swift
@@ -54,19 +54,14 @@ fileprivate struct Balances: WalletBackendFormattedRequest {
// MARK: -
extension WalletModel {
/// fetch Balances from Wallet-Core. No networking involved
- @MainActor func balancesM(_ stack: CallStack)
- async -> [Balance] { // M for MainActor
+ @MainActor func balancesM(_ stack: CallStack, viewHandles: Bool = false)
+ async throws -> [Balance] { // M for MainActor
await semaphore.wait()
defer { semaphore.signal() }
if cachedBalances == nil {
- do {
- let request = Balances()
- let response = try await sendRequest(request, ASYNCDELAY)
- cachedBalances = response.balances
- } catch {
- logger.error("balancesM failed: \(error)")
- // TODO: show error
- }
+ let request = Balances()
+ let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
+ cachedBalances = response.balances
} else {
logger.trace("returning cached Balances")
}
diff --git a/TalerWallet1/Model/Model+Deposit.swift
b/TalerWallet1/Model/Model+Deposit.swift
index 8afd67d..2d520ca 100644
--- a/TalerWallet1/Model/Model+Deposit.swift
+++ b/TalerWallet1/Model/Model+Deposit.swift
@@ -74,27 +74,27 @@ fileprivate struct CreateDepositGroup:
WalletBackendFormattedRequest {
extension WalletModel {
/// validate IBAN
@MainActor
- func validateIbanM(_ iban: String) // M for MainActor
+ func validateIbanM(_ iban: String, viewHandles: Bool = false) // M
for MainActor
async throws -> Bool {
let request = ValidateIban(iban: iban)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response.valid
}
/// deposit coins. Networking involved
@MainActor
- func prepareDepositM(_ depositPaytoUri: String, amount: Amount) // M
for MainActor
+ func prepareDepositM(_ depositPaytoUri: String, amount: Amount,
viewHandles: Bool = false) // M for MainActor
async throws -> PrepareDepositResult {
let request = PrepareDeposit(depositPaytoUri: depositPaytoUri,
amount: amount)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
return response
}
@MainActor
- func createDepositGroupM(_ depositPaytoUri: String, amount: Amount) // M
for MainActor
+ func createDepositGroupM(_ depositPaytoUri: String, amount: Amount,
viewHandles: Bool = false) // M for MainActor
async throws -> DepositGroupResult {
let request = CreateDepositGroup(depositPaytoUri: depositPaytoUri,
amount: amount)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
return response
}
}
diff --git a/TalerWallet1/Model/Model+Exchange.swift
b/TalerWallet1/Model/Model+Exchange.swift
index 2eeeec5..0377ff7 100644
--- a/TalerWallet1/Model/Model+Exchange.swift
+++ b/TalerWallet1/Model/Model+Exchange.swift
@@ -117,12 +117,14 @@ fileprivate struct GetExchangeByUrl:
WalletBackendFormattedRequest {
fileprivate struct UpdateExchange: WalletBackendFormattedRequest {
struct Response: Decodable {} // no result - getting no error back means
success
func operation() -> String { "updateExchangeEntry" }
- func args() -> Args { Args(scopeInfo: scopeInfo) }
+// func args() -> Args { Args(scopeInfo: scopeInfo) }
+ func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl) }
- var scopeInfo: ScopeInfo
+// var scopeInfo: ScopeInfo
+ var exchangeBaseUrl: String
struct Args: Encodable {
- var scopeInfo: ScopeInfo
+ var exchangeBaseUrl: String
}
}
@@ -154,11 +156,11 @@ fileprivate struct GetCurrencySpecification:
WalletBackendFormattedRequest {
// MARK: -
extension WalletModel {
/// ask wallet-core for its list of known exchanges
- @MainActor func listExchangesForScopedCurrencyM(scope: ScopeInfo)
+ @MainActor func listExchangesForScopedCurrencyM(scope: ScopeInfo,
viewHandles: Bool = false)
async -> [ExchangeUrlItem] { // M for MainActor
do {
let request = ListExchangesForScopedCurrency(scope: scope)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
return response.exchanges
} catch {
return [] // empty, but not nil
@@ -166,52 +168,47 @@ extension WalletModel {
}
/// ask wallet-core for its list of known exchanges
- @MainActor func listExchangesM()
- async -> [Exchange] { // M for MainActor
- do {
- let request = ListExchanges()
- let response = try await sendRequest(request, ASYNCDELAY)
- return response.exchanges
- } catch {
- // TODO: Error
- return [] // empty, but not nil
- }
+ @MainActor func listExchangesM(devMode: Bool = false, viewHandles: Bool =
false)
+ async throws -> [Exchange] { // M for MainActor
+ let request = ListExchanges()
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ return response.exchanges
}
/// add a new exchange with URL to the wallet's list of known exchanges
- func getExchangeByUrl(url: String)
- async -> Exchange? {
- do {
- let request = GetExchangeByUrl(exchangeBaseUrl: url)
+ func getExchangeByUrl(url: String, viewHandles: Bool = false)
+ async throws -> Exchange {
+ let request = GetExchangeByUrl(exchangeBaseUrl: url)
// logger.info("query for exchange: \(url, privacy: .public)")
- let response = try await sendRequest(request)
- return response
- } catch {
- return nil
- }
+ let response = try await sendRequest(request, viewHandles: viewHandles)
+ return response
}
/// add a new exchange with URL to the wallet's list of known exchanges
- func addExchange(url: String)
+ func addExchange(url: String, viewHandles: Bool = false)
async throws {
let request = AddExchange(exchangeBaseUrl: url)
logger.info("adding exchange: \(url, privacy: .public)")
- _ = try await sendRequest(request)
+ _ = try await sendRequest(request, viewHandles: viewHandles)
}
/// ask wallet-core to update an existing exchange by querying it for
denominations, fees, and scoped currency info
- func updateExchange(scopeInfo: ScopeInfo)
+// func updateExchange(scopeInfo: ScopeInfo)
+// func updateExchange(scopeInfo: ScopeInfo, viewHandles: Bool = false)
+ func updateExchange(exchangeBaseUrl: String, viewHandles: Bool = false)
async throws {
- let request = UpdateExchange(scopeInfo: scopeInfo)
- logger.info("updating exchange for: \(scopeInfo.currency, privacy:
.public)")
- _ = try await sendRequest(request)
+// let request = UpdateExchange(scopeInfo: scopeInfo)
+ let request = UpdateExchange(exchangeBaseUrl: exchangeBaseUrl)
+// logger.info("updating exchange for: \(scopeInfo.currency, privacy:
.public)")
+ logger.info("updating exchange: \(exchangeBaseUrl, privacy: .public)")
+ _ = try await sendRequest(request, viewHandles: viewHandles)
}
@MainActor
- func getCurrencyInfoM(scope: ScopeInfo, delay: UInt = 0)
+ func getCurrencyInfoM(scope: ScopeInfo, delay: UInt = 0, viewHandles: Bool
= false)
async throws -> CurrencyInfo {
let request = GetCurrencySpecification(scope: scope)
- let response = try await sendRequest(request, ASYNCDELAY + delay)
+ let response = try await sendRequest(request, ASYNCDELAY + delay,
viewHandles: viewHandles)
return CurrencyInfo(scope: scope, specs:
response.currencySpecification,
formatter: CurrencyFormatter.formatter(scope: scope,
specs:
response.currencySpecification))
diff --git a/TalerWallet1/Model/Model+P2P.swift
b/TalerWallet1/Model/Model+P2P.swift
index 28ad60d..498eced 100644
--- a/TalerWallet1/Model/Model+P2P.swift
+++ b/TalerWallet1/Model/Model+P2P.swift
@@ -32,10 +32,10 @@ fileprivate struct GetMaxPeerPushAmount:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func getMaxPeerPushAmountM(_ currency: String) // M for MainActor
+ func getMaxPeerPushAmountM(_ currency: String, viewHandles: Bool = false)
// M for MainActor
async throws -> AmountResponse {
let request = GetMaxPeerPushAmount(currency: currency)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // getMaxPeerPushAmountM
@@ -58,10 +58,10 @@ fileprivate struct CheckPeerPushDebit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func checkPeerPushDebitM(_ amount: Amount) // M for MainActor
+ func checkPeerPushDebitM(_ amount: Amount, viewHandles: Bool = false)
// M for MainActor
async throws -> CheckPeerPushDebitResponse {
let request = CheckPeerPushDebit(amount: amount)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // checkPeerPushDebitM
@@ -90,11 +90,11 @@ fileprivate struct InitiatePeerPushDebit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func initiatePeerPushDebitM(_ baseURL: String?, terms: PeerContractTerms)
// M for MainActor
+ func initiatePeerPushDebitM(_ baseURL: String?, terms: PeerContractTerms,
viewHandles: Bool = false) // M for MainActor
async throws -> InitiatePeerPushDebitResponse {
let request = InitiatePeerPushDebit(exchangeBaseUrl: baseURL,
partialContractTerms: terms)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // initiatePeerPushDebitM
@@ -123,10 +123,10 @@ fileprivate struct CheckPeerPullCredit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func checkPeerPullCreditM(_ amount: Amount, exchangeBaseUrl: String?)
// M for MainActor
+ func checkPeerPullCreditM(_ amount: Amount, exchangeBaseUrl: String?,
viewHandles: Bool = false) // M for MainActor
async throws -> CheckPeerPullCreditResponse {
let request = CheckPeerPullCredit(exchangeBaseUrl: exchangeBaseUrl,
amount: amount)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // checkPeerPullCreditM
@@ -151,11 +151,11 @@ fileprivate struct InitiatePeerPullCredit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func initiatePeerPullCreditM(_ baseURL: String?, terms: PeerContractTerms)
// M for MainActor
+ func initiatePeerPullCreditM(_ baseURL: String?, terms: PeerContractTerms,
viewHandles: Bool = false) // M for MainActor
async throws -> InitiatePeerPullCreditResponse {
let request = InitiatePeerPullCredit(exchangeBaseUrl: baseURL,
partialContractTerms: terms)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // initiatePeerPullCreditM
@@ -181,10 +181,10 @@ fileprivate struct PreparePeerPushCredit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func preparePeerPushCreditM(_ talerUri: String) // M for MainActor
+ func preparePeerPushCreditM(_ talerUri: String, viewHandles: Bool = false)
// M for MainActor
async throws -> PreparePeerPushCreditResponse {
let request = PreparePeerPushCredit(talerUri: talerUri)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // preparePeerPushCreditM
@@ -202,10 +202,10 @@ fileprivate struct AcceptPeerPushCredit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func acceptPeerPushCreditM(_ transactionId: String) // M for
MainActor
+ func acceptPeerPushCreditM(_ transactionId: String, viewHandles: Bool =
false) // M for MainActor
async throws -> Decodable {
let request = AcceptPeerPushCredit(transactionId: transactionId)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // acceptPeerPushCreditM
@@ -230,10 +230,10 @@ fileprivate struct PreparePeerPullDebit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func preparePeerPullDebitM(_ talerUri: String) // M for MainActor
+ func preparePeerPullDebitM(_ talerUri: String, viewHandles: Bool = false)
// M for MainActor
async throws -> PreparePeerPullDebitResponse {
let request = PreparePeerPullDebit(talerUri: talerUri)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // preparePeerPullDebitM
@@ -251,10 +251,10 @@ fileprivate struct ConfirmPeerPullDebit:
WalletBackendFormattedRequest {
}
extension WalletModel {
@MainActor
- func confirmPeerPullDebitM(_ transactionId: String) // M for
MainActor
+ func confirmPeerPullDebitM(_ transactionId: String, viewHandles: Bool =
false) // M for MainActor
async throws -> Decodable {
let request = ConfirmPeerPullDebit(transactionId: transactionId)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
} // confirmPeerPullDebitM
diff --git a/TalerWallet1/Model/Model+Payment.swift
b/TalerWallet1/Model/Model+Payment.swift
index f4f1204..3abb316 100644
--- a/TalerWallet1/Model/Model+Payment.swift
+++ b/TalerWallet1/Model/Model+Payment.swift
@@ -197,25 +197,25 @@ fileprivate struct confirmPayForUri:
WalletBackendFormattedRequest {
extension WalletModel {
/// load payment details. Networking involved
@MainActor
- func preparePayForUriM(_ talerPayUri: String) // M for MainActor
+ func preparePayForUriM(_ talerPayUri: String, viewHandles: Bool = false)
// M for MainActor
async throws -> PreparePayResult {
let request = PreparePayForUri(talerPayUri: talerPayUri)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
return response
}
@MainActor
- func preparePayForTemplateM(_ talerPayTemplateUri: String, amount:
Amount?, summary: String?) // M for MainActor
+ func preparePayForTemplateM(_ talerPayTemplateUri: String, amount:
Amount?, summary: String?, viewHandles: Bool = false) // M for MainActor
async throws -> PreparePayResult {
let templateParams = TemplateParams(amount: amount, summary: summary)
let request = PreparePayForTemplate(talerPayTemplateUri:
talerPayTemplateUri, templateParams: templateParams)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor
- func confirmPayM(_ transactionId: String) // M for MainActor
+ func confirmPayM(_ transactionId: String, viewHandles: Bool = false)
// M for MainActor
async throws -> ConfirmPayResult {
let request = confirmPayForUri(transactionId: transactionId)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
return response
}
}
diff --git a/TalerWallet1/Model/Model+Pending.swift
b/TalerWallet1/Model/Model+Pending.swift
index e2dec9f..f316293 100644
--- a/TalerWallet1/Model/Model+Pending.swift
+++ b/TalerWallet1/Model/Model+Pending.swift
@@ -42,14 +42,10 @@ struct PendingOperation: Codable, Hashable {
}
// MARK: -
extension WalletModel {
- @MainActor func getPendingOperationsM()
- async -> [PendingOperation] { // M for MainActor
- do {
- let request = GetPendingOperations()
- let response = try await sendRequest(request, ASYNCDELAY)
- return response.pendingOperations
- } catch {
- return []
- }
+ @MainActor func getPendingOperationsM(viewHandles: Bool = false)
+ async throws -> [PendingOperation] { // M for MainActor
+ let request = GetPendingOperations()
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ return response.pendingOperations
}
}
diff --git a/TalerWallet1/Model/Model+Refund.swift
b/TalerWallet1/Model/Model+Refund.swift
index 4892c61..6ce5407 100644
--- a/TalerWallet1/Model/Model+Refund.swift
+++ b/TalerWallet1/Model/Model+Refund.swift
@@ -40,15 +40,15 @@ struct StartRefundQueryRequest:
WalletBackendFormattedRequest {
// MARK: -
extension WalletModel {
@MainActor
- func startRefundForUriM(url: String) async throws -> String {
+ func startRefundForUriM(url: String, viewHandles: Bool = false) async
throws -> String {
let request = StartRefundURIRequest(talerRefundUri: url)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response.transactionId
}
@MainActor
- func startRefundM(transactionId: String) async throws {
+ func startRefundM(transactionId: String, viewHandles: Bool = false) async
throws {
let request = StartRefundQueryRequest(transactionId: transactionId)
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
}
diff --git a/TalerWallet1/Model/Model+Settings.swift
b/TalerWallet1/Model/Model+Settings.swift
index a727679..0561023 100644
--- a/TalerWallet1/Model/Model+Settings.swift
+++ b/TalerWallet1/Model/Model+Settings.swift
@@ -33,13 +33,13 @@ fileprivate struct WithdrawTestBalanceRequest:
WalletBackendFormattedRequest {
}
}
extension WalletModel {
- @MainActor func loadTestKudosM(test: Bool, amount: Amount)
+ @MainActor func loadTestKudosM(test: Bool, amount: Amount, viewHandles:
Bool = false)
async throws { // M for MainActor
let request = WithdrawTestBalanceRequest(amount: amount,
// bankBaseUrl: test ? TESTBANK :
DEMOBANK,
corebankApiBaseUrl: test ? TESTBANK :
DEMOBANK,
exchangeBaseUrl: test ? TESTEXCHANGE :
DEMOEXCHANGE)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
} // loadTestKudosM()
// MARK: -
@@ -77,7 +77,7 @@ fileprivate struct RunIntegrationTest:
WalletBackendFormattedRequest {
}
}
extension WalletModel {
- @MainActor func runIntegrationTestM(newVersion: Bool, test: Bool)
+ @MainActor func runIntegrationTestM(newVersion: Bool, test: Bool,
viewHandles: Bool = false)
async throws { // M for MainActor
let amountW = Amount(currency: test ? TESTCURRENCY : DEMOCURRENCY,
cent: 300)
let amountS = Amount(currency: test ? TESTCURRENCY : DEMOCURRENCY,
cent: 100)
@@ -89,7 +89,7 @@ extension WalletModel {
merchantAuthToken: MERCHANTAUTHTOKEN,
amountToWithdraw: amountW,
amountToSpend: amountS)
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
} // runIntegrationTestM()
// MARK: -
@@ -111,9 +111,9 @@ fileprivate struct InfiniteTransactionLoop:
WalletBackendFormattedRequest {
}
}
extension WalletModel {
- func testingInfiniteTransaction(delayMs: Int32, shouldFetch: Bool)
+ func testingInfiniteTransaction(delayMs: Int32, shouldFetch: Bool,
viewHandles: Bool = false)
async throws {
let request = InfiniteTransactionLoop(delayMs: delayMs, shouldFetch:
shouldFetch)
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
} // runIntegrationTestM()
diff --git a/TalerWallet1/Model/Model+Transactions.swift
b/TalerWallet1/Model/Model+Transactions.swift
index 26288bf..c8d19df 100644
--- a/TalerWallet1/Model/Model+Transactions.swift
+++ b/TalerWallet1/Model/Model+Transactions.swift
@@ -103,52 +103,48 @@ struct ResumeTransaction: WalletBackendFormattedRequest {
// MARK: -
extension WalletModel {
/// ask wallet-core for its list of transactions filtered by searchString
- func transactionsT(_ stack: CallStack, scopeInfo: ScopeInfo, searchString:
String? = nil,
- sort: String = "descending", includeRefreshes: Bool =
false)
- async -> [Transaction] { // might
be called from a background thread itself
- do {
- let request = GetTransactions(scopeInfo: scopeInfo, currency:
scopeInfo.currency, search: searchString, sort: sort, includeRefreshes:
includeRefreshes)
- let response = try await sendRequest(request, ASYNCDELAY)
- return response.transactions
- } catch {
- return []
- }
+ func transactionsT(_ stack: CallStack, scopeInfo: ScopeInfo, searchString:
String? = nil,
+ sort: String = "descending", includeRefreshes: Bool =
false, viewHandles: Bool = false)
+ async throws -> [Transaction] {
+ let request = GetTransactions(scopeInfo: scopeInfo, currency:
scopeInfo.currency, search: searchString, sort: sort, includeRefreshes:
includeRefreshes)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ return response.transactions
}
/// fetch transactions from Wallet-Core. No networking involved
- @MainActor func transactionsMA(_ stack: CallStack, scopeInfo: ScopeInfo,
searchString: String? = nil, sort: String = "descending")
- async -> [Transaction] { // M for MainActor
- return await transactionsT(stack.push(), scopeInfo: scopeInfo,
searchString: searchString, sort: sort)
+ @MainActor func transactionsMA(_ stack: CallStack, scopeInfo: ScopeInfo,
searchString: String? = nil, sort: String = "descending", viewHandles: Bool =
false)
+ async throws -> [Transaction] { // M for MainActor
+ return try await transactionsT(stack.push(), scopeInfo: scopeInfo,
searchString: searchString, sort: sort, viewHandles: viewHandles)
}
/// abort the specified transaction from Wallet-Core. No networking
involved
- func abortTransaction(transactionId: String) async throws {
+ func abortTransaction(transactionId: String, viewHandles: Bool = false)
async throws {
let request = AbortTransaction(transactionId: transactionId)
logger.notice("abortTransaction: \(transactionId, privacy:
.private(mask: .hash))")
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
/// delete the specified transaction from Wallet-Core. No networking
involved
- func deleteTransaction(transactionId: String) async throws {
+ func deleteTransaction(transactionId: String, viewHandles: Bool = false)
async throws {
let request = DeleteTransaction(transactionId: transactionId)
logger.notice("deleteTransaction: \(transactionId, privacy:
.private(mask: .hash))")
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
- func failTransaction(transactionId: String) async throws {
+ func failTransaction(transactionId: String, viewHandles: Bool = false)
async throws {
let request = FailTransaction(transactionId: transactionId)
logger.notice("failTransaction: \(transactionId, privacy:
.private(mask: .hash))")
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
- func suspendTransaction(transactionId: String) async throws {
+ func suspendTransaction(transactionId: String, viewHandles: Bool = false)
async throws {
let request = SuspendTransaction(transactionId: transactionId)
logger.notice("suspendTransaction: \(transactionId, privacy:
.private(mask: .hash))")
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
- func resumeTransaction(transactionId: String) async throws {
+ func resumeTransaction(transactionId: String, viewHandles: Bool = false)
async throws {
let request = ResumeTransaction(transactionId: transactionId)
logger.notice("resumeTransaction: \(transactionId, privacy:
.private(mask: .hash))")
- let _ = try await sendRequest(request, ASYNCDELAY)
+ let _ = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
}
diff --git a/TalerWallet1/Model/Model+Withdraw.swift
b/TalerWallet1/Model/Model+Withdraw.swift
index 8ca4725..7aa2488 100644
--- a/TalerWallet1/Model/Model+Withdraw.swift
+++ b/TalerWallet1/Model/Model+Withdraw.swift
@@ -92,13 +92,15 @@ struct WithdrawalAmountDetails: Decodable {
fileprivate struct GetWithdrawalDetailsForAmount:
WalletBackendFormattedRequest {
typealias Response = WithdrawalAmountDetails
func operation() -> String { "getWithdrawalDetailsForAmount" }
- func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl, amount:
amount) }
+ func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl, amount:
amount, clientCancellationId: cancellationId) }
var exchangeBaseUrl: String
var amount: Amount
+ var cancellationId: String?
struct Args: Encodable {
var exchangeBaseUrl: String
var amount: Amount
+ var clientCancellationId: String?
}
}
// MARK: -
@@ -192,56 +194,58 @@ fileprivate struct AcceptManualWithdrawal:
WalletBackendFormattedRequest {
extension WalletModel {
/// load withdraw-exchange details. Networking involved
@MainActor // M for MainActor
- func loadWithdrawalExchangeForUriM(_ talerUri: String)
+ func loadWithdrawalExchangeForUriM(_ talerUri: String, viewHandles: Bool =
false)
async throws -> WithdrawExchangeResponse {
let request = PrepareWithdrawExchange(talerUri: talerUri)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
/// load withdrawal details. Networking involved
@MainActor // M for MainActor
- func getWithdrawalDetailsForUriM(_ talerWithdrawUri: String)
+ func getWithdrawalDetailsForUriM(_ talerWithdrawUri: String, viewHandles:
Bool = false)
async throws -> WithdrawUriInfoResponse {
let request = GetWithdrawalDetailsForURI(talerWithdrawUri:
talerWithdrawUri)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor // M for MainActor
- func getWithdrawalDetailsForAmountM(_ exchangeBaseUrl: String, amount:
Amount)
+ func getWithdrawalDetailsForAmountM(_ exchangeBaseUrl: String, amount:
Amount,
+ cancellationId: String? = nil,
viewHandles: Bool = false)
async throws -> WithdrawalAmountDetails {
let request = GetWithdrawalDetailsForAmount(exchangeBaseUrl:
exchangeBaseUrl,
- amount: amount)
- let response = try await sendRequest(request, ASYNCDELAY)
+ amount: amount,
+ cancellationId:
cancellationId)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor // M for MainActor
- func loadExchangeTermsOfServiceM(_ exchangeBaseUrl: String,
acceptedFormat: [String], acceptLanguage: String)
+ func loadExchangeTermsOfServiceM(_ exchangeBaseUrl: String,
acceptedFormat: [String], acceptLanguage: String, viewHandles: Bool = false)
async throws -> ExchangeTermsOfService {
let request = GetExchangeTermsOfService(exchangeBaseUrl:
exchangeBaseUrl,
acceptedFormat:
acceptedFormat,
acceptLanguage:
acceptLanguage)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor // M for MainActor
- func setExchangeTOSAcceptedM(_ exchangeBaseUrl: String, etag: String)
+ func setExchangeTOSAcceptedM(_ exchangeBaseUrl: String, etag: String,
viewHandles: Bool = false)
async throws -> Decodable {
let request = SetExchangeTOSAccepted(exchangeBaseUrl: exchangeBaseUrl,
etag: etag)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor // M for MainActor
- func sendAcceptIntWithdrawalM(_ exchangeBaseUrl: String, withdrawURL:
String)
+ func sendAcceptIntWithdrawalM(_ exchangeBaseUrl: String, withdrawURL:
String, viewHandles: Bool = false)
async throws -> AcceptWithdrawalResponse? {
let request = AcceptBankIntegratedWithdrawal(talerWithdrawUri:
withdrawURL, exchangeBaseUrl: exchangeBaseUrl)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor // M for MainActor
- func sendAcceptManualWithdrawalM(_ exchangeBaseUrl: String, amount:
Amount, restrictAge: Int?)
+ func sendAcceptManualWithdrawalM(_ exchangeBaseUrl: String, amount:
Amount, restrictAge: Int?, viewHandles: Bool = false)
async throws -> AcceptManualWithdrawalResult? {
let request = AcceptManualWithdrawal(exchangeBaseUrl: exchangeBaseUrl,
amount: amount, restrictAge: restrictAge)
- let response = try await sendRequest(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
}
diff --git a/TalerWallet1/Model/Transaction.swift
b/TalerWallet1/Model/Transaction.swift
index dc2d7a6..85ed2d3 100644
--- a/TalerWallet1/Model/Transaction.swift
+++ b/TalerWallet1/Model/Transaction.swift
@@ -142,6 +142,7 @@ struct TransactionTransition: Codable { //
Notification
var newTxState: TransactionState
var transactionId: String
var experimentalUserData: String? // KYC
+ var errorInfo: WalletBackendResponseError?
}
enum TxAction: String, Codable {
diff --git a/TalerWallet1/Model/WalletModel.swift
b/TalerWallet1/Model/WalletModel.swift
index 9c57e90..5463f76 100644
--- a/TalerWallet1/Model/WalletModel.swift
+++ b/TalerWallet1/Model/WalletModel.swift
@@ -27,7 +27,12 @@ class WalletModel: ObservableObject {
let semaphore = AsyncSemaphore(value: 1)
var cachedBalances: [Balance]? = nil
- func sendRequest<T: WalletBackendFormattedRequest> (_ request: T, _ delay:
UInt = 0)
+ @Published var showError: Bool = false
+ @Published var error: ErrorData? = nil {
+ didSet { showError = error != nil }
+ }
+
+ func sendRequest<T: WalletBackendFormattedRequest> (_ request: T, _ delay:
UInt = 0, viewHandles: Bool = false)
async throws -> T.Response { // T for any Thread
#if !DEBUG
logger.log("sending: \(request.operation(), privacy: .public)")
@@ -47,20 +52,24 @@ class WalletModel: ObservableObject {
} catch { // rethrows
let timeUsed = Date.now - sendTime
logger.error("\(request.operation(), privacy: .public) failed
after \(timeUsed.milliseconds, privacy: .public) ms\n\(error, privacy:
.public)")
+ if !viewHandles {
+ // TODO: symlog + controller sound
+ self.error = .error(error)
+ }
throw error
}
}
- func getTransactionByIdT(_ transactionId: String)
+ func getTransactionByIdT(_ transactionId: String, viewHandles: Bool =
false)
async throws -> Transaction { // T for any Thread
// might be called from a background thread itself
let request = GetTransactionById(transactionId: transactionId)
- return try await sendRequest(request, ASYNCDELAY)
+ return try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
}
/// get the specified transaction from Wallet-Core. No networking involved
- @MainActor func getTransactionByIdM(_ transactionId: String)
+ @MainActor func getTransactionByIdM(_ transactionId: String, viewHandles:
Bool = false)
async throws -> Transaction { // M for MainActor
- return try await getTransactionByIdT(transactionId) // call
GetTransactionById on main thread
+ return try await getTransactionByIdT(transactionId, viewHandles:
viewHandles) // call GetTransactionById on main thread
}
}
// MARK: -
@@ -102,7 +111,7 @@ fileprivate struct Testing: Encodable {
self.insecureTrustExchange = false
self.preventThrottling = false
self.skipDefaults = false
- self.emitObservabilityEvents = false
+ self.emitObservabilityEvents = true
}
}
@@ -120,7 +129,7 @@ fileprivate struct Config: Encodable {
fileprivate struct ConfigRequest: WalletBackendFormattedRequest {
var setTesting: Bool
- func operation() -> String { "setConfig" }
+ func operation() -> String { "setWalletRunConfig" }
func args() -> Args {
let testing = Testing(devModeActive: setTesting)
let builtin = Builtin(exchanges: [])
@@ -177,11 +186,11 @@ fileprivate struct InitRequest:
WalletBackendFormattedRequest {
extension WalletModel {
/// initalize Wallet-Core. Will do networking
- func initWalletCoreT(setTesting: Bool) async throws -> VersionInfo {
+ func initWalletCoreT(setTesting: Bool, viewHandles: Bool = false) async
throws -> VersionInfo {
// T for any Thread
let docPath = try docPath(sqlite3: true)
let request = InitRequest(persistentStoragePath: docPath, setTesting:
setTesting)
- let response = try await sendRequest(request, 0) // no Delay
+ let response = try await sendRequest(request, 0, viewHandles:
viewHandles) // no Delay
return response.versionInfo
}
@@ -233,10 +242,10 @@ fileprivate struct ResetRequest:
WalletBackendFormattedRequest {
extension WalletModel {
/// reset Wallet-Core
- func resetWalletCoreT() async throws {
+ func resetWalletCoreT(viewHandles: Bool = false) async throws {
// T for any Thread
let request = ResetRequest()
- _ = try await sendRequest(request, 0)
+ _ = try await sendRequest(request, 0, viewHandles: viewHandles)
}
}
// MARK: -
@@ -255,9 +264,21 @@ fileprivate struct DevExperimentRequest:
WalletBackendFormattedRequest {
extension WalletModel {
/// tell wallet-core to mock new transactions
- func devExperimentT(talerUri: String) async throws {
+ func devExperimentT(talerUri: String, viewHandles: Bool = false) async
throws {
// T for any Thread
let request = DevExperimentRequest(talerUri: talerUri)
- _ = try await sendRequest(request, 0)
+ _ = try await sendRequest(request, 0, viewHandles: viewHandles)
+ }
+}
+
+extension WalletModel {
+ @MainActor
+ func showError(_ error: ErrorData) {
+ self.error = error
+ }
+
+ @MainActor
+ func cleanError() {
+ self.error = nil
}
}
diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift
b/TalerWallet1/Views/Balances/BalancesListView.swift
index f12483d..804edf2 100644
--- a/TalerWallet1/Views/Balances/BalancesListView.swift
+++ b/TalerWallet1/Views/Balances/BalancesListView.swift
@@ -16,6 +16,7 @@ struct BalancesListView: View {
@Binding var shouldReloadBalances: Int
@EnvironmentObject private var model: WalletModel
+ @EnvironmentObject private var controller: Controller
@State private var lastReloadedBalances = 0
@State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING)
// Update currency when used
@@ -78,14 +79,18 @@ struct BalancesListView: View {
/// runs on MainActor if called in some Task {}
@discardableResult
- private func reloadBalances(_ stack: CallStack, _ invalidateCache: Bool)
async -> Int {
+ private func reloadBalances(_ stack: CallStack, _ invalidateCache: Bool)
async -> Int? {
if invalidateCache {
model.cachedBalances = nil
}
- let reloaded = await model.balancesM(stack.push())
- let count = reloaded.count
- balances = reloaded // redraw
- return count
+
+ if let reloaded = try? await model.balancesM(stack.push()) {
+ let count = reloaded.count
+ balances = reloaded // redraw
+ return count
+ }
+
+ return nil
}
var body: some View {
@@ -126,7 +131,7 @@ extension BalancesListView {
@Binding var amountToTransfer: Amount
@Binding var summary: String
@Binding var shouldReloadBalances: Int
- var reloadBalances: (_ stack: CallStack, _ invalidateCache: Bool)
async -> Int
+ var reloadBalances: (_ stack: CallStack, _ invalidateCache: Bool)
async -> Int?
var body: some View {
#if PRINT_CHANGES
@@ -155,7 +160,7 @@ extension BalancesListView {
.refreshable { // already async
symLog?.log("refreshing balances")
let count = await reloadBalances(stack.push("refreshing
balances"), true)
- if count > 0 {
+ if let count, count > 0 {
NotificationCenter.default.post(name: .BalanceReloaded,
object: nil)
}
}
diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift
b/TalerWallet1/Views/Balances/BalancesSectionView.swift
index 0d1a80a..1fab4db 100644
--- a/TalerWallet1/Views/Balances/BalancesSectionView.swift
+++ b/TalerWallet1/Views/Balances/BalancesSectionView.swift
@@ -40,21 +40,23 @@ struct BalancesSectionView {
@State private var completedTransactions: [Transaction] = []
@State private var pendingTransactions: [Transaction] = []
- func reloadOneAction(_ transactionId: String) async throws -> Transaction {
- return try await model.getTransactionByIdT(transactionId)
+ func reloadOneAction(_ transactionId: String, _ viewHandles: Bool) async
throws -> Transaction {
+ return try await model.getTransactionByIdT(transactionId, viewHandles:
viewHandles)
}
@State private var sectionID = UUID()
@State private var shownSectionID = UUID() // guaranteed to be different
the first time
func reloadCompleted(_ stack: CallStack) async -> () {
- transactions = await model.transactionsT(stack.push(), scopeInfo:
balance.scopeInfo, includeRefreshes: developerMode)
- completedTransactions = WalletModel.completedTransactions(transactions)
+ if let transactions = try? await model.transactionsT(stack.push(),
scopeInfo: balance.scopeInfo, includeRefreshes: developerMode) {
+ completedTransactions =
WalletModel.completedTransactions(transactions)
+ }
}
func reloadPending(_ stack: CallStack) async -> () {
- transactions = await model.transactionsT(stack.push(), scopeInfo:
balance.scopeInfo, includeRefreshes: developerMode)
- pendingTransactions = WalletModel.pendingTransactions(transactions)
+ if let transactions = try? await model.transactionsT(stack.push(),
scopeInfo: balance.scopeInfo, includeRefreshes: developerMode) {
+ pendingTransactions = WalletModel.pendingTransactions(transactions)
+ }
}
}
@@ -128,11 +130,12 @@ extension BalancesSectionView: View {
// if shownSectionID != sectionID {
symLog.log(".task for BalancesSectionView - reload
Transactions")
// TODO: only load the MAXRECENT most recent transactions
- let response = await model.transactionsT(stack.push(".task -
reload Transactions"), scopeInfo: scopeInfo, includeRefreshes: developerMode)
+ if let response = try? await model.transactionsT(stack.push(".task
- reload Transactions"), scopeInfo: scopeInfo, includeRefreshes: developerMode)
{
transactions = response
pendingTransactions = WalletModel.pendingTransactions(response)
completedTransactions =
WalletModel.completedTransactions(response)
shownSectionID = sectionID
+ }
// } else {
// symLog.log("task for BalancesSectionView \(sectionID) ❗️
skip reloading Transactions")
// }
@@ -169,7 +172,7 @@ fileprivate struct BalancesPendingRowView: View {
let balance: Balance // this is the currency to
be used
@Binding var pendingTransactions: [Transaction]
let reloadPending: (_ stack: CallStack) async -> ()
- let reloadOneAction: ((_ transactionId: String) async throws ->
Transaction)
+ let reloadOneAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Transaction)
var body: some View {
let pendingIncoming = balance.pendingIncoming
@@ -229,7 +232,7 @@ fileprivate struct BalancesNavigationLinksView: View {
@Binding var summary: String
@Binding var completedTransactions: [Transaction]
let reloadAllAction: (_ stack: CallStack) async -> ()
- let reloadOneAction: ((_ transactionId: String) async throws ->
Transaction)
+ let reloadOneAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Transaction)
// @EnvironmentObject private var model: WalletModel
@State private var buttonSelected: Int? = nil
diff --git a/TalerWallet1/Views/Banking/DepositAmountV.swift
b/TalerWallet1/Views/Banking/DepositAmountV.swift
index 70c3414..ae90f94 100644
--- a/TalerWallet1/Views/Banking/DepositAmountV.swift
+++ b/TalerWallet1/Views/Banking/DepositAmountV.swift
@@ -122,13 +122,11 @@ struct DepositAmountV: View {
depositStarted = true // don't run twice
Task { // runs on MainActor
symLog.log("Deposit")
- do {
- let result = try await
model.createDepositGroupM(paytoUri, amount: amountToTransfer)
+ if let result = try? await
model.createDepositGroupM(paytoUri, amount: amountToTransfer) {
symLog.log(result.transactionId)
ViewState2.shared.popToRootView(stack.push())
NotificationCenter.default.post(name:
.TransactionDone, object: nil, userInfo: nil)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
+ } else {
depositStarted = false
}
}
@@ -168,15 +166,13 @@ struct DepositAmountV: View {
feeStr = EMPTYSTRING
prepareDepositResult = nil
} else if let paytoUri {
- do {
- let ppCheck = try await
model.prepareDepositM(paytoUri, amount: amountToTransfer)
+ if let ppCheck = try? await
model.prepareDepositM(paytoUri, amount: amountToTransfer) {
prepareDepositResult = ppCheck
if let feeAmount = fee(ppCheck:
prepareDepositResult) {
feeStr = feeAmount.string(currencyInfo)
} else { feeStr = EMPTYSTRING }
announce(this: "\(amountVoiceOver), \(feeLabel)")
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
+ } else {
prepareDepositResult = nil
}
}
diff --git a/TalerWallet1/Views/Banking/DepositIbanV.swift
b/TalerWallet1/Views/Banking/DepositIbanV.swift
index 6b6fc9c..6d588bf 100644
--- a/TalerWallet1/Views/Banking/DepositIbanV.swift
+++ b/TalerWallet1/Views/Banking/DepositIbanV.swift
@@ -127,13 +127,10 @@ struct DepositIbanV: View {
// print("❗️ P2PSubjectV onDisappear")
}
.task(id: depositIBAN) {
- do {
- if try await model.validateIbanM(depositIBAN) {
- let payto =
"payto://iban/\(depositIBAN)?receiver-name=\(accountHolder)"
- paytoUri =
payto.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
- }
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
+ if (try? await model.validateIbanM(depositIBAN)) == true {
+ let payto =
"payto://iban/\(depositIBAN)?receiver-name=\(accountHolder)"
+ paytoUri = payto.addingPercentEncoding(withAllowedCharacters:
.urlQueryAllowed)!
+ } else {
paytoUri = nil
}
}
diff --git a/TalerWallet1/Views/Banking/DepositWithdrawV.swift
b/TalerWallet1/Views/Banking/DepositWithdrawV.swift
index 6bff91d..d538360 100644
--- a/TalerWallet1/Views/Banking/DepositWithdrawV.swift
+++ b/TalerWallet1/Views/Banking/DepositWithdrawV.swift
@@ -26,11 +26,14 @@ struct DepositWithdrawV: View {
amountToTransfer.setCurrency(currency)
buttonSelected = button // will trigger NavigationLink
// after user tapped a button, while navigation animation runs,
contact Exchange to update Fees
- Task { // runs on MainActor
- do {
- try await model.updateExchange(scopeInfo: scopeInfo)
- } catch { // TODO: error handling - couldn't updateExchange
- symLog.log("error: \(error)")
+ if let url = scopeInfo.url {
+ Task { // runs on MainActor
+ do {
+// try await model.updateExchange(scopeInfo: scopeInfo)
+ try await model.updateExchange(exchangeBaseUrl: url)
+ } catch { // TODO: error handling - couldn't updateExchange
+ symLog.log("error: \(error)")
+ }
}
}
}
diff --git a/TalerWallet1/Views/Banking/ExchangeListView.swift
b/TalerWallet1/Views/Banking/ExchangeListView.swift
index 504e077..6191730 100644
--- a/TalerWallet1/Views/Banking/ExchangeListView.swift
+++ b/TalerWallet1/Views/Banking/ExchangeListView.swift
@@ -16,6 +16,7 @@ struct ExchangeListView: View {
@Binding var balances: [Balance]
let navTitle: String
@EnvironmentObject private var model: WalletModel
+ @EnvironmentObject private var controller: Controller
@State var showAlert: Bool = false
@State var newExchange: String = TESTEXCHANGE
@@ -23,12 +24,9 @@ struct ExchangeListView: View {
func addExchange(_ exchange: String) -> Void {
Task { // runs on MainActor
symLog.log("adding: \(exchange)")
- do {
- try await model.addExchange(url: exchange)
+ if let _ = try? await model.addExchange(url: exchange) {
symLog.log("added: \(exchange)")
announce(this: "added: \(exchange)")
- } catch { // TODO: error handling - couldn't add exchangeURL
- symLog.log("error: \(error)")
}
}
}
@@ -74,6 +72,7 @@ struct ExchangeListCommonV {
@Binding var balances: [Balance]
@EnvironmentObject private var model: WalletModel
+ @EnvironmentObject private var controller: Controller
@AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
// @AppStorage("depositIBAN") var depositIBAN = EMPTYSTRING
// @AppStorage("accountHolder") var accountHolder = EMPTYSTRING
@@ -84,7 +83,9 @@ struct ExchangeListCommonV {
@State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING)
// TODO: Hold different values for different currencies?
func reloadExchanges() async -> Void {
- exchanges = await model.listExchangesM()
+ if let exc = try? await model.listExchangesM() {
+ exchanges = exc
+ }
}
}
// MARK: -
diff --git a/TalerWallet1/Views/Banking/ExchangeRowView.swift
b/TalerWallet1/Views/Banking/ExchangeRowView.swift
index 58208f9..1792c72 100644
--- a/TalerWallet1/Views/Banking/ExchangeRowView.swift
+++ b/TalerWallet1/Views/Banking/ExchangeRowView.swift
@@ -64,12 +64,9 @@ struct ExchangeRowView: View {
// FIXME: remove fake ScopeInfo once the REAL one is in
exchange.scopeInfo
let scopeInfo = exchange.scopeInfo
?? ScopeInfo(type: .global, currency: currency)
- do {
- let info = try await model.getCurrencyInfoM(scope:
scopeInfo, delay: delay)
+ if let info = try? await model.getCurrencyInfoM(scope:
scopeInfo, delay: delay) {
// logger.info("got info: \(scope.currency, privacy:
.public)")
await controller.setInfo(info)
- } catch { // TODO: error handling - couldn't get
CurrencyInfo
-// logger.error("Couldn't get info for: \(scope.currency,
privacy: .public)\n\(error)")
}
}
}
diff --git a/TalerWallet1/Views/Banking/ManualWithdraw.swift
b/TalerWallet1/Views/Banking/ManualWithdraw.swift
index 6427475..0499fc4 100644
--- a/TalerWallet1/Views/Banking/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Banking/ManualWithdraw.swift
@@ -110,22 +110,34 @@ struct ManualWithdraw: View {
}
}
.task(id: amountToTransfer.value) { // re-run this whenever
amountToTransfer changes
- symLog.log("getExchangeByUrl(\(scopeInfo?.url))")
if let exchangeBaseUrl = scopeInfo?.url {
+ symLog.log("getExchangeByUrl(\(exchangeBaseUrl))")
if exchange == nil || exchange?.tosStatus != .accepted {
- if let exc = await model.getExchangeByUrl(url:
exchangeBaseUrl) {
- exchange = exc
- } else {
+ do {
+ exchange = try await model.getExchangeByUrl(url:
exchangeBaseUrl)
+ } catch {
// TODO: Error "Can't get Exchange / Payment Service
Provider Info"
+ symLog.log(error.localizedDescription)
+ model.showError(.error(error))
+ controller.playSound(0)
}
}
if !amountToTransfer.isZero {
do {
let details = try await
model.getWithdrawalDetailsForAmountM(exchangeBaseUrl,
-
amount: amountToTransfer)
+
amount: amountToTransfer,
+
cancellationId: "cancel",
+
viewHandles: true)
withdrawalAmountDetails = details
// agePicker.setAges(ages:
withdrawalAmountDetails?.ageRestrictionOptions)
- } catch { // TODO: error
+ } catch WalletBackendError.walletCoreError(let
walletBackendResponseError) {
+ symLog.log(walletBackendResponseError?.hint)
+ // TODO: ignore WALLET_CORE_REQUEST_CANCELLED but
handle all others
+ // Passing non-nil to clientCancellationId will throw
WALLET_CORE_REQUEST_CANCELLED
+ // when calling getWithdrawalDetailsForAmount again
before the last call returned.
+ // Since amountToTransfer changed and we don't need
the old fee anymore, we just
+ // ignore it and do nothing.
+ } catch {
symLog.log(error.localizedDescription)
withdrawalAmountDetails = nil
}
diff --git a/TalerWallet1/Views/Banking/ManualWithdrawDone.swift
b/TalerWallet1/Views/Banking/ManualWithdrawDone.swift
index 3689416..6acb181 100644
--- a/TalerWallet1/Views/Banking/ManualWithdrawDone.swift
+++ b/TalerWallet1/Views/Banking/ManualWithdrawDone.swift
@@ -20,8 +20,8 @@ struct ManualWithdrawDone: View {
@State private var acceptManualWithdrawalResult:
AcceptManualWithdrawalResult?
@State private var transactionId: String?
- func reloadOneAction(_ transactionId: String) async throws -> Transaction {
- return try await model.getTransactionByIdT(transactionId)
+ func reloadOneAction(_ transactionId: String, viewHandles: Bool) async
throws -> Transaction {
+ return try await model.getTransactionByIdT(transactionId, viewHandles:
viewHandles)
}
func dismissTopAnimated(_ stack: CallStack) {
dismissTop()
@@ -55,12 +55,9 @@ struct ManualWithdrawDone: View {
DebugViewC.shared.setViewID(VIEW_WITHDRAW_ACCEPT, stack:
stack.push())
}.task {
if transactionId == nil {
- do {
- let result = try await
model.sendAcceptManualWithdrawalM(exchange.exchangeBaseUrl,
-
amount: amountToTransfer, restrictAge: 0)
- transactionId = result!.transactionId
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
+ if let result = try? await
model.sendAcceptManualWithdrawalM(exchange.exchangeBaseUrl,
+
amount: amountToTransfer, restrictAge: 0) {
+ transactionId = result.transactionId
}
}
}
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift
b/TalerWallet1/Views/HelperViews/AmountInputV.swift
index 2b542af..4ebb3e8 100644
--- a/TalerWallet1/Views/HelperViews/AmountInputV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountInputV.swift
@@ -33,8 +33,7 @@ struct AmountInputV: View {
func preparePayForTemplate() async {
if let url {
- do {
- let ppCheck = try await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary)
+ if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary) {
let amount = ppCheck.amountRaw
let currency = amount.currencyStr
let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
@@ -46,8 +45,6 @@ struct AmountInputV: View {
let amountVoiceOver = amount.string(currencyInfo)
announce(this: "\(amountVoiceOver), \(feeLabel)")
preparePayResult = ppCheck
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
}
}
diff --git a/TalerWallet1/Views/HelperViews/BarGraph.swift
b/TalerWallet1/Views/HelperViews/BarGraph.swift
index 3f64829..ecbd46d 100644
--- a/TalerWallet1/Views/HelperViews/BarGraph.swift
+++ b/TalerWallet1/Views/HelperViews/BarGraph.swift
@@ -15,6 +15,7 @@ struct BarGraphHeader: View {
@Binding var shouldReloadBalances: Int
@EnvironmentObject private var model: WalletModel
+ @EnvironmentObject private var controller: Controller
@Environment(\.colorScheme) private var colorScheme
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
@AppStorage("minimalistic") var minimalistic: Bool = false
@@ -37,9 +38,10 @@ struct BarGraphHeader: View {
if let scopeInfo {
symLog.log(".task for BarGraphHeader(\(scopeInfo.currency)) -
reload Transactions")
// TODO: only load the 10 most recent transactions
- let response = await model.transactionsT(stack.push(".task -
reload Transactions for \(scopeInfo.currency)"),
- scopeInfo: scopeInfo)
- completedTransactions =
WalletModel.completedTransactions(response)
+ if let response = try? await
model.transactionsT(stack.push(".task - reload Transactions for
\(scopeInfo.currency)"),
+ scopeInfo:
scopeInfo) {
+ completedTransactions =
WalletModel.completedTransactions(response)
+ }
}
}
}
diff --git a/TalerWallet1/Views/HelperViews/SubjectInputV.swift
b/TalerWallet1/Views/HelperViews/SubjectInputV.swift
index 56135f8..df64493 100644
--- a/TalerWallet1/Views/HelperViews/SubjectInputV.swift
+++ b/TalerWallet1/Views/HelperViews/SubjectInputV.swift
@@ -38,8 +38,7 @@ struct SubjectInputV<TargetView: View>: View {
func preparePayForTemplate() async {
if let url {
- do {
- let ppCheck = try await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary)
+ if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary) {
let amount = ppCheck.amountRaw
let currency = amount.currencyStr
let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
@@ -51,8 +50,6 @@ struct SubjectInputV<TargetView: View>: View {
let amountVoiceOver = amount.string(currencyInfo)
announce(this: "\(amountVoiceOver), \(feeLabel)")
preparePayResult = ppCheck
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
}
}
diff --git a/TalerWallet1/Views/HelperViews/TransactionButton.swift
b/TalerWallet1/Views/HelperViews/TransactionButton.swift
index cbb60d1..2accb3b 100644
--- a/TalerWallet1/Views/HelperViews/TransactionButton.swift
+++ b/TalerWallet1/Views/HelperViews/TransactionButton.swift
@@ -10,7 +10,7 @@ struct TransactionButton: View {
let transactionId: String
let command: TxAction
let warning: String?
- let action: (_ transactionId: String) async throws -> Void
+ let action: (_ transactionId: String, _ viewHandles: Bool) async throws ->
Void
@AppStorage("shouldShowWarning") var shouldShowWarning: Bool = true
@@ -21,12 +21,9 @@ struct TransactionButton: View {
private func doAction() {
disabled = true // don't try this more than once
Task { // runs on MainActor
- do {
- try await action(transactionId)
+ if let _ = try? await action(transactionId, false) {
// symLog.log("\(executed) \(transactionId)")
executed = true
- } catch { // TODO: error
-// symLog.log(error.localizedDescription)
}
}
}
@@ -75,7 +72,7 @@ struct TransactionButton: View {
#if DEBUG
struct TransactionButton_Previews: PreviewProvider {
- static func action(_ transactionId: String) async throws {
+ static func action(_ transactionId: String, _ viewHandles: Bool) async
throws {
print(transactionId)
}
diff --git a/TalerWallet1/Views/Main/MainView.swift
b/TalerWallet1/Views/Main/MainView.swift
index 6563daa..9d7effe 100644
--- a/TalerWallet1/Views/Main/MainView.swift
+++ b/TalerWallet1/Views/Main/MainView.swift
@@ -2,6 +2,10 @@
* This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ * @author Iván Ávalos
+ */
import SwiftUI
import os.log
import SymLog
@@ -20,7 +24,14 @@ struct MainView: View {
let stack: CallStack
@Binding var soundPlayed: Bool
+#if DEBUG
+ @AppStorage("developerMode") var developerMode: Bool = true
+#else
+ @AppStorage("developerMode") var developerMode: Bool = false
+#endif
+
@EnvironmentObject private var controller: Controller
+ @EnvironmentObject private var model: WalletModel
@AppStorage("talerFontIndex") var talerFontIndex: Int = 0 //
extension mustn't define this, so it must be here
@AppStorage("playSoundsI") var playSoundsI: Int = 1 //
extension mustn't define this, so it must be here
@AppStorage("playSoundsB") var playSoundsB: Bool = false
@@ -70,6 +81,15 @@ struct MainView: View {
let sheet = AnyView(URLSheet(stack: stack.push(), urlToOpen: url))
Sheet(sheetView: sheet)
}
+ .sheet(isPresented: $model.showError) {
+ model.cleanError()
+ } content: {
+ if let error = model.error {
+ ErrorSheet(data: error, devMode: developerMode) {
+ model.cleanError()
+ }.interactiveDismissDisabled()
+ }
+ }
} // body
}
// MARK: - TabBar
@@ -101,6 +121,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
@@ -234,16 +260,19 @@ extension MainView {
shouldReloadBalances += 1
selectedTab = .balances
}
+ .onNotification(.Error) { notification in
+ if let error = notification.userInfo?[NOTIFICATIONERROR] as?
Error {
+ model.showError(.error(error))
+ controller.playSound(0)
+ }
+ }
.onChange(of: balances) { newArray in
for balance in newArray {
let scope = balance.scopeInfo
if controller.hasInfo(for: scope.currency) == nil {
Task { // runs on MainActor
- do {
- let info = try await
model.getCurrencyInfoM(scope: scope, delay: delay)
+ if let info = try? await
model.getCurrencyInfoM(scope: scope, delay: delay) {
await controller.setInfo(info)
- } catch { // TODO: error handling - couldn't
get CurrencyInfo
- logger.error("Couldn't get info for:
\(scope.currency, privacy: .public)\n\(error)")
}
}
}
diff --git a/TalerWallet1/Views/Main/WalletEmptyView.swift
b/TalerWallet1/Views/Main/WalletEmptyView.swift
index a99a06f..46cb387 100644
--- a/TalerWallet1/Views/Main/WalletEmptyView.swift
+++ b/TalerWallet1/Views/Main/WalletEmptyView.swift
@@ -44,11 +44,7 @@ struct WalletEmptyView: View {
Task { // runs on MainActor
let amount = Amount(currency: DEMOCURRENCY, cent:
2500)
symLog.log("Withdraw KUDOS")
- do {
- try await model.loadTestKudosM(test: false,
amount: amount)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await model.loadTestKudosM(test: false, amount:
amount)
}
}
.buttonStyle(TalerButtonStyle(type: .prominent, narrow: false,
disabled: withDrawDisabled, aligned: .center))
diff --git a/TalerWallet1/Views/Peer2peer/P2PReadyV.swift
b/TalerWallet1/Views/Peer2peer/P2PReadyV.swift
index ade1597..d2bf281 100644
--- a/TalerWallet1/Views/Peer2peer/P2PReadyV.swift
+++ b/TalerWallet1/Views/Peer2peer/P2PReadyV.swift
@@ -27,8 +27,8 @@ struct P2PReadyV: View {
let navTitle = String(localized: "P2P Ready")
@State private var transactionId: String? = nil
- func reloadOneAction(_ transactionId: String) async throws -> Transaction {
- return try await model.getTransactionByIdT(transactionId)
+ func reloadOneAction(_ transactionId: String, viewHandles: Bool) async
throws -> Transaction {
+ return try await model.getTransactionByIdT(transactionId, viewHandles:
viewHandles)
}
var body: some View {
@@ -69,35 +69,33 @@ struct P2PReadyV: View {
}
.task(id: amountToTransfer.value) {
symLog.log(".task")
- do {
- guard transactionStarted == false else {
+ guard transactionStarted == false else {
// TODO: logger.warning("Try to start P2P a second time")
- symLog.log("Yikes❗️ Try to start P2P a second time")
- return
- }
- transactionStarted = true
- let timestamp = developerMode ?
Timestamp.inSomeMinutes(expireDays > 20 ? (24*60)
- :
expireDays > 5 ? 60 : 3)
- :
Timestamp.inSomeDays(expireDays)
- if amountToSend {
- let terms = PeerContractTerms(amount: amountToTransfer,
- summary: summary,
- purse_expiration: timestamp)
- // TODO: let user choose baseURL
- let response = try await model.initiatePeerPushDebitM(nil,
terms: terms)
+ symLog.log("Yikes❗️ Try to start P2P a second time")
+ return
+ }
+ transactionStarted = true
+ let timestamp = developerMode ? Timestamp.inSomeMinutes(expireDays
> 20 ? (24*60)
+ : expireDays
> 5 ? 60 : 3)
+ : Timestamp.inSomeDays(expireDays)
+ if amountToSend {
+ let terms = PeerContractTerms(amount: amountToTransfer,
+ summary: summary,
+ purse_expiration: timestamp)
+ // TODO: let user choose baseURL
+ if let response = try? await model.initiatePeerPushDebitM(nil,
terms: terms) {
// will switch from WithdrawProgressView to
TransactionSummaryV
transactionId = response.transactionId
- } else {
- let terms = PeerContractTerms(amount: amountToTransfer,
- summary: summary,
- purse_expiration: timestamp)
- // TODO: let user choose baseURL
- let response = try await
model.initiatePeerPullCreditM(nil, terms: terms)
+ }
+ } else {
+ let terms = PeerContractTerms(amount: amountToTransfer,
+ summary: summary,
+ purse_expiration: timestamp)
+ // TODO: let user choose baseURL
+ if let response = try? await
model.initiatePeerPullCreditM(nil, terms: terms) {
// will switch from WithdrawProgressView to
TransactionSummaryV
transactionId = response.transactionId
}
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
} // task
}
diff --git a/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
b/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
index 6982490..bbb2587 100644
--- a/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
+++ b/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
@@ -134,14 +134,11 @@ struct P2PSubjectV: View {
}
.task(id: amountToTransfer.value) {
if amountToSend && feeLabel == nil {
- do {
- let ppCheck = try await
model.checkPeerPushDebitM(amountToTransfer)
+ if let ppCheck = try? await
model.checkPeerPushDebitM(amountToTransfer) {
if let feeAmount = p2pFee(ppCheck: ppCheck) {
let feeStr = feeAmount.string(currencyInfo)
myFeeLabel = String(localized: "+ \(feeStr) fee")
} else { myFeeLabel = EMPTYSTRING }
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
}
}
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
index 90a5bc8..84e0a42 100644
--- a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -105,25 +105,13 @@ struct RequestPayment: View {
.task(id: amountToTransfer.value) {
if exchange == nil {
if let url = scopeInfo.url {
- if let exc = await model.getExchangeByUrl(url: url) {
- exchange = exc
- } else {
- // TODO: Error "Can't get Exchange / Payment Service
Provider Info"
- }
+ exchange = try? await model.getExchangeByUrl(url: url)
}
}
if amountToTransfer.isZero {
// fee = EMPTYSTRING
} else {
- do {
- let ppCheck = try await
model.checkPeerPullCreditM(amountToTransfer, exchangeBaseUrl: nil)
- peerPullCheck = ppCheck // redraw
- // TODO: set from exchange
-// agePicker.setAges(ages:
peerPushCheck?.ageRestrictionOptions)
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- peerPullCheck = nil
- }
+ peerPullCheck = try? await
model.checkPeerPullCreditM(amountToTransfer, exchangeBaseUrl: nil)
}
}
}
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift
b/TalerWallet1/Views/Peer2peer/SendAmount.swift
index ba468e8..0c25cc6 100644
--- a/TalerWallet1/Views/Peer2peer/SendAmount.swift
+++ b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -133,11 +133,7 @@ struct SendAmount: View {
.task(id: amountToTransfer.value) {
if exchange == nil {
if let url = scopeInfo.url {
- if let exc = await model.getExchangeByUrl(url: url) {
- exchange = exc
- } else {
- // TODO: Error "Can't get Exchange / Payment Service
Provider Info"
- }
+ exchange = try? await model.getExchangeByUrl(url: url)
}
}
do {
@@ -152,8 +148,7 @@ struct SendAmount: View {
} else if amountToTransfer.isZero {
feeStr = EMPTYSTRING
} else {
- do {
- let ppCheck = try await
model.checkPeerPushDebitM(amountToTransfer)
+ if let ppCheck = try? await
model.checkPeerPushDebitM(amountToTransfer) {
peerPushCheck = ppCheck
// TODO: set from exchange
// agePicker.setAges(ages: peerPushCheck?.ageRestrictionOptions)
@@ -161,8 +156,7 @@ struct SendAmount: View {
feeStr = feeAmount.string(currencyInfo)
} else { feeStr = EMPTYSTRING }
announce(this: "\(amountVoiceOver), \(feeLabel)")
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
+ } else {
peerPushCheck = nil
}
}
diff --git a/TalerWallet1/Views/Settings/SettingsView.swift
b/TalerWallet1/Views/Settings/SettingsView.swift
index 37ec955..aafe57e 100644
--- a/TalerWallet1/Views/Settings/SettingsView.swift
+++ b/TalerWallet1/Views/Settings/SettingsView.swift
@@ -65,11 +65,7 @@ struct SettingsView: View {
showResetAlert = false
Task { // runs on MainActor
symLog.log("❗️Reset wallet-core❗️")
- do {
- try await model.resetWalletCoreT()
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await model.resetWalletCoreT()
}
}
}
@@ -186,12 +182,8 @@ struct SettingsView: View {
withDrawDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("Withdraw KUDOS")
- do {
- let amount = Amount(currency:
DEMOCURRENCY, cent: 1100)
- try await model.loadTestKudosM(test:
false, amount: amount)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ let amount = Amount(currency:
DEMOCURRENCY, cent: 1100)
+ try? await model.loadTestKudosM(test:
false, amount: amount)
}
}
.buttonStyle(.bordered)
@@ -204,12 +196,8 @@ struct SettingsView: View {
withDrawDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("Withdraw TESTKUDOS")
- do {
- let amount = Amount(currency:
TESTCURRENCY, cent: 1100)
- try await model.loadTestKudosM(test:
true, amount: amount)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ let amount = Amount(currency:
TESTCURRENCY, cent: 1100)
+ try? await model.loadTestKudosM(test:
true, amount: amount)
}
}
.buttonStyle(.bordered)
@@ -227,13 +215,9 @@ struct SettingsView: View {
Button(title) {
Task { // runs on MainActor
symLog.log("running applyDevExperiment
Refresh")
- do {
- try await model.setConfigT(setTesting:
true)
- try await
model.devExperimentT(talerUri: "taler://dev-experiment/start-block-refresh")
- try await
model.devExperimentT(talerUri: "taler://dev-experiment/insert-pending-refresh")
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await model.setConfigT(setTesting:
true)
+ try? await model.devExperimentT(talerUri:
"taler://dev-experiment/start-block-refresh")
+ try? await model.devExperimentT(talerUri:
"taler://dev-experiment/insert-pending-refresh")
}
}
.buttonStyle(.bordered)
@@ -246,11 +230,7 @@ struct SettingsView: View {
checkDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("running integration test on
demo")
- do {
- try await
model.runIntegrationTestM(newVersion: false, test: false)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await
model.runIntegrationTestM(newVersion: false, test: false)
}
}
.buttonStyle(.bordered)
@@ -263,11 +243,7 @@ struct SettingsView: View {
checkDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("running integration test on
test")
- do {
- try await
model.runIntegrationTestM(newVersion: false, test: true)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await
model.runIntegrationTestM(newVersion: false, test: true)
}
}
.buttonStyle(.bordered)
@@ -280,11 +256,7 @@ struct SettingsView: View {
checkDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("running integration test V2 on
demo")
- do {
- try await
model.runIntegrationTestM(newVersion: true, test: false)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await
model.runIntegrationTestM(newVersion: true, test: false)
}
}
.buttonStyle(.bordered)
@@ -297,11 +269,7 @@ struct SettingsView: View {
checkDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("running integration test V2 on
test")
- do {
- try await
model.runIntegrationTestM(newVersion: true, test: true)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await
model.runIntegrationTestM(newVersion: true, test: true)
}
}
.buttonStyle(.bordered)
@@ -314,11 +282,7 @@ struct SettingsView: View {
checkDisabled = true // don't run twice
Task { // runs on MainActor
symLog.log("Running Infinite Transaction
Loop")
- do {
- try await
model.testingInfiniteTransaction(delayMs: 10_000, shouldFetch: true)
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ try? await
model.testingInfiniteTransaction(delayMs: 10_000, shouldFetch: true)
}
}
.buttonStyle(.bordered)
diff --git a/TalerWallet1/Views/Sheets/ErrorSheet.swift
b/TalerWallet1/Views/Sheets/ErrorSheet.swift
new file mode 100644
index 0000000..d6d2d1e
--- /dev/null
+++ b/TalerWallet1/Views/Sheets/ErrorSheet.swift
@@ -0,0 +1,130 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+/**
+ * @author Iván Ávalos
+ */
+import SwiftUI
+
+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?.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) {
+ let unknownError = String(localized: "Unknown error")
+
+ switch data {
+ case .message(let title, let message):
+ self.init(title: title, message: message, copyable: false,
onDismiss: onDismiss)
+ return
+ case .error(let error):
+ self.init(error: error, devMode: devMode, onDismiss: onDismiss)
+ return
+ }
+
+ self.init(title: unknownError, copyable: false, onDismiss: onDismiss)
+ }
+
+ var body: some View {
+ ScrollView {
+ VStack {
+ Image(systemName: "exclamationmark.circle")
+ .resizable()
+ .frame(width: 50, height: 50)
+ .aspectRatio(contentMode: .fit)
+ .foregroundStyle(.red)
+ .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,
+ 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/P2P_Sheets/P2pAcceptDone.swift
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pAcceptDone.swift
index f0ae796..6edc6eb 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pAcceptDone.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pAcceptDone.swift
@@ -34,16 +34,14 @@ struct P2pAcceptDone: View {
: SHEET_PAY_P2P_ACCEPT)
}
.task {
- do {
- if incoming {
- _ = try await
model.acceptPeerPushCreditM(transactionId)
- } else {
- _ = try await
model.confirmPeerPullDebitM(transactionId)
+ if incoming {
+ if let _ = try? await
model.acceptPeerPushCreditM(transactionId) {
+ dismissTop()
+ }
+ } else {
+ if let _ = try? await
model.confirmPeerPullDebitM(transactionId) {
+ dismissTop()
}
- dismissTop()
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- controller.playSound(0)
}
}
}
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
index ca2e431..e51f00a 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
@@ -73,11 +73,7 @@ struct P2pPayURIView: View {
LoadingView(scopeInfo: nil, message: message)
.task { do {
symLog.log(".task")
- let ppDebitResponse = try await
model.preparePeerPullDebitM(url.absoluteString)
- peerPullDebitResponse = ppDebitResponse
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- peerPullDebitResponse = nil
+ peerPullDebitResponse = try? await
model.preparePeerPullDebitM(url.absoluteString)
} }
}
}
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
index ee63a98..9037682 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
@@ -17,6 +17,7 @@ struct P2pReceiveURIView: View {
let url: URL
@EnvironmentObject private var model: WalletModel
+ @EnvironmentObject private var controller: Controller
@Environment(\.colorScheme) private var colorScheme
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
@AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
@@ -87,13 +88,11 @@ struct P2pReceiveURIView: View {
DebugViewC.shared.setSheetID(SHEET_RCV_P2P)
}
.task { // must be here and not at LoadingView(), because this needs
to run a 2nd time after ToS was accepted
- do { // TODO: cancelled
- symLog.log(".task")
- let ppResponse = try await
model.preparePeerPushCreditM(url.absoluteString)
- exchange = await model.getExchangeByUrl(url:
ppResponse.exchangeBaseUrl)
+ symLog.log(".task")
+ if let ppResponse = try? await
model.preparePeerPushCreditM(url.absoluteString) {
+ exchange = try? await model.getExchangeByUrl(url:
ppResponse.exchangeBaseUrl)
peerPushCreditResponse = ppResponse
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
+ } else {
peerPushCreditResponse = nil
}
}
diff --git a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
index 0f6158f..81e7a08 100644
--- a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
@@ -62,17 +62,12 @@ struct PayTemplateV: View {
}
func acceptAction(preparePayResult: PreparePayResult) {
Task { // runs on MainActor
- do {
- let confirmPayResult = try await
model.confirmPayM(preparePayResult.transactionId)
-// symLog.log(confirmPayResult as Any)
+ if let confirmPayResult = try? await
model.confirmPayM(preparePayResult.transactionId) {
+ // symLog.log(confirmPayResult as Any)
if confirmPayResult.type != "done" {
controller.playSound(0)
// TODO: show error
}
- } catch {
- controller.playSound(0)
- // TODO: error
- symLog.log(error.localizedDescription)
}
dismissTop()
}
@@ -94,8 +89,7 @@ struct PayTemplateV: View {
}
func preparePayForTemplate() async {
- do {
- let ppCheck = try await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary)
+ if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary) {
let amount = ppCheck.amountRaw
let currency = amount.currencyStr
let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
@@ -107,8 +101,6 @@ struct PayTemplateV: View {
let amountVoiceOver = amount.string(currencyInfo)
announce(this: "\(amountVoiceOver), \(feeLabel)")
preparePayResult = ppCheck
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
}
diff --git a/TalerWallet1/Views/Sheets/Payment/PaymentDone.swift
b/TalerWallet1/Views/Sheets/Payment/PaymentDone.swift
index 69de946..8ba4e78 100644
--- a/TalerWallet1/Views/Sheets/Payment/PaymentDone.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PaymentDone.swift
@@ -15,8 +15,8 @@ struct PaymentDone: View {
@State var paymentDone: Bool = false
- func reloadOneAction(_ transactionId: String) async throws -> Transaction {
- return try await model.getTransactionByIdT(transactionId)
+ func reloadOneAction(_ transactionId: String, viewHandles: Bool) async
throws -> Transaction {
+ return try await model.getTransactionByIdT(transactionId, viewHandles:
viewHandles)
}
func dismissTopAnimated(_ stack: CallStack) {
dismissTop()
@@ -46,9 +46,8 @@ struct PaymentDone: View {
} else {
LoadingView(scopeInfo: nil, message: "Paying...")
.task {
- do {
- let confirmPayResult = try await
model.confirmPayM(transactionId)
-// symLog.log(confirmPayResult as Any)
+ if let confirmPayResult = try? await
model.confirmPayM(transactionId) {
+ //
symLog.log(confirmPayResult as Any)
if confirmPayResult.type == "done" {
paymentDone = true
} else {
@@ -56,11 +55,6 @@ struct PaymentDone: View {
// TODO: show error
dismissTop()
}
- } catch {
- controller.playSound(0)
- // TODO: error
- symLog.log(error.localizedDescription)
- dismissTop()
}
}
}
diff --git a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
index 897bcae..3b7ab98 100644
--- a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
@@ -20,6 +20,7 @@ struct PaymentView: View {
@Binding var summary: String
@EnvironmentObject private var model: WalletModel
+ @EnvironmentObject private var controller: Controller
@AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
@State var preparePayResult: PreparePayResult? = nil
@@ -94,19 +95,17 @@ struct PaymentView: View {
} else {
LoadingView(scopeInfo: nil, message: url.host)
.task { // this runs only once
- do { // TODO: cancelled
- symLog.log(".task")
- if template {
- let result = try await
model.preparePayForTemplateM(url.absoluteString,
- amount:
amountToTransfer,
- summary:
summary)
+ symLog.log(".task")
+ if template {
+ if let result = try? await
model.preparePayForTemplateM(url.absoluteString,
+ amount:
amountToTransfer,
+
summary: summary) {
preparePayResult = result
- } else {
- let result = try await
model.preparePayForUriM(url.absoluteString)
+ }
+ } else {
+ if let result = try? await
model.preparePayForUriM(url.absoluteString) {
preparePayResult = result
}
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
}
}
diff --git a/TalerWallet1/Views/Sheets/Refund/RefundURIView.swift
b/TalerWallet1/Views/Sheets/Refund/RefundURIView.swift
index 284d9e7..ec6ff99 100644
--- a/TalerWallet1/Views/Sheets/Refund/RefundURIView.swift
+++ b/TalerWallet1/Views/Sheets/Refund/RefundURIView.swift
@@ -17,8 +17,8 @@ struct RefundURIView: View {
@State var refundTransactionId: String? = nil
- func reloadOneAction(_ transactionId: String) async throws -> Transaction {
- return try await model.getTransactionByIdT(transactionId)
+ func reloadOneAction(_ transactionId: String, viewHandles: Bool) async
throws -> Transaction {
+ return try await model.getTransactionByIdT(transactionId, viewHandles:
viewHandles)
}
var body: some View {
@@ -36,12 +36,9 @@ struct RefundURIView: View {
} else {
LoadingView(scopeInfo: nil, message: url.host)
.task {
- do {
- symLog.log(".task")
- let result = try await model.startRefundForUriM(url:
url.absoluteString)
+ symLog.log(".task")
+ if let result = try? await model.startRefundForUriM(url:
url.absoluteString) {
refundTransactionId = result
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
}
}
}
diff --git a/TalerWallet1/Views/Sheets/Sheet.swift
b/TalerWallet1/Views/Sheets/Sheet.swift
index 7c9edb8..a0f2da6 100644
--- a/TalerWallet1/Views/Sheets/Sheet.swift
+++ b/TalerWallet1/Views/Sheets/Sheet.swift
@@ -10,8 +10,15 @@ struct Sheet: View {
private let symLog = SymLogV(0)
@Environment(\.dismiss) var dismiss // call dismiss() to get rid of
the sheet
@EnvironmentObject private var debugViewC: DebugViewC
+ @EnvironmentObject private var model: WalletModel
@AppStorage("talerFontIndex") var talerFontIndex: Int = 0
+#if DEBUG
+ @AppStorage("developerMode") var developerMode: Bool = true
+#else
+ @AppStorage("developerMode") var developerMode: Bool = false
+#endif
+
var sheetView: AnyView
let logger = Logger(subsystem: "net.taler.gnu", category: "Sheet")
@@ -27,8 +34,16 @@ struct Sheet: View {
let idString = debugViewC.sheetID > 0 ? String(debugViewC.sheetID)
: "" // show nothing if 0
NavigationView {
- sheetView
- .navigationBarItems(leading: cancelButton)
+ Group {
+ if let error = model.error {
+ ErrorSheet(data: error, devMode: developerMode) {
+ dismissTop()
+ }
+ } else {
+ sheetView
+ .navigationBarItems(leading: cancelButton)
+ }
+ }
.navigationBarTitleDisplayMode(.automatic)
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}
@@ -45,5 +60,8 @@ struct Sheet: View {
.accessibilityLabel(Text("Sheet.ID.", comment:
"AccessibilityLabel"))
.accessibilityValue(idString)
}
+ .onDisappear {
+ model.cleanError()
+ }
}
}
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
index d71f08c..dfa6a0e 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
@@ -19,8 +19,8 @@ struct WithdrawAcceptDone: View {
@State private var transactionId: String? = nil
- func reloadOneAction(_ transactionId: String) async throws -> Transaction {
- return try await model.getTransactionByIdT(transactionId)
+ func reloadOneAction(_ transactionId: String, viewHandles: Bool) async
throws -> Transaction {
+ return try await model.getTransactionByIdT(transactionId,
viewHandles: viewHandles)
}
func dismissTopAnimated(_ stack: CallStack) {
dismissTop()
@@ -54,16 +54,12 @@ struct WithdrawAcceptDone: View {
symLog.log("onAppear")
DebugViewC.shared.setSheetID(SHEET_WITHDRAW_CONFIRM)
}.task {
- do {
- if let exchangeBaseUrl {
- let result = try await
model.sendAcceptIntWithdrawalM(exchangeBaseUrl, withdrawURL: url.absoluteString)
- let confirmTransferUrl = result!.confirmTransferUrl
+ if let exchangeBaseUrl {
+ if let result = try? await
model.sendAcceptIntWithdrawalM(exchangeBaseUrl, withdrawURL:
url.absoluteString) {
+ let confirmTransferUrl = result.confirmTransferUrl
symLog.log(confirmTransferUrl)
- transactionId = result!.transactionId
+ transactionId = result.transactionId
}
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- controller.playSound(0)
}
}
}
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
index 82fbb89..f9039d9 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
@@ -23,21 +23,15 @@ struct WithdrawTOSView: View {
@State var exchangeTOS: ExchangeTermsOfService?
func loadToS(_ language: String) async {
- do {
- if let exchangeBaseUrl {
- let acceptedFormat: [String] = [MARKDOWN, PLAINTEXT] //
MARKDOWN, HTML, PLAINTEXT
- let someTOS = try await
model.loadExchangeTermsOfServiceM(exchangeBaseUrl,
- acceptedFormat:
acceptedFormat,
- acceptLanguage:
language)
+ if let exchangeBaseUrl {
+ let acceptedFormat: [String] = [MARKDOWN, PLAINTEXT] //
MARKDOWN, HTML, PLAINTEXT
+ if let someTOS = try? await
model.loadExchangeTermsOfServiceM(exchangeBaseUrl,
+ acceptedFormat:
acceptedFormat,
+ acceptLanguage:
language) {
exchangeTOS = someTOS
- } else {
- // TODO: Yikes! No baseURL
-
-
-
}
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
+ } else {
+ // TODO: Yikes! No baseURL
}
}
@@ -48,19 +42,15 @@ struct WithdrawTOSView: View {
Content(symLog: symLog, tos: exchangeTOS, myListStyle:
$myListStyle,
language: languageCode, languageAction: loadToS) {
Task { // runs on MainActor
- do {
- if let exchangeBaseUrl {
- _ = try await
model.setExchangeTOSAcceptedM(exchangeBaseUrl, etag: exchangeTOS.currentEtag)
- if acceptAction != nil {
- acceptAction!()
- } else { // just go back - caller will reload
- self.presentationMode.wrappedValue.dismiss()
- }
- } else {
- // TODO: error
+ if let exchangeBaseUrl {
+ _ = try? await
model.setExchangeTOSAcceptedM(exchangeBaseUrl, etag: exchangeTOS.currentEtag)
+ if acceptAction != nil {
+ acceptAction!()
+ } else { // just go back - caller will reload
+ self.presentationMode.wrappedValue.dismiss()
}
- } catch { // TODO: Show Error
- symLog.log(error.localizedDescription)
+ } else {
+ // TODO: error
}
}
}
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
index 49d45ba..651b502 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -10,7 +10,7 @@ import taler_swift
import SymLog
// Called either when scanning a QR code or tapping the provided link, both
from the bank's website.
-// We show the user the withdrawal details in a sheet - but first the ToS must
be accepted.
+// We show the user the bank-integrated withdrawal details in a sheet - but
first the ToS must be accepted.
// After the user confirmed the withdrawal, we show a button to return to the
bank website to confirm there, too
struct WithdrawURIView: View {
private let symLog = SymLogV(0)
@@ -92,24 +92,21 @@ struct WithdrawURIView: View {
DebugViewC.shared.setSheetID(SHEET_WITHDRAWAL)
}
.task {
- do { // TODO: cancelled
- symLog.log(".task")
- let withdrawUriInfo = try await
model.getWithdrawalDetailsForUriM(url.absoluteString)
+ symLog.log(".task")
+ if let withdrawUriInfo = try? await
model.getWithdrawalDetailsForUriM(url.absoluteString) {
let amount = withdrawUriInfo.amount
let baseUrl = withdrawUriInfo.defaultExchangeBaseUrl
??
withdrawUriInfo.possibleExchanges.first?.exchangeBaseUrl
- if let baseUrl, let exc = await model.getExchangeByUrl(url:
baseUrl) {
- exchange = exc
- let details = try await
model.getWithdrawalDetailsForAmountM(baseUrl, amount: amount)
- withdrawalAmountDetails = details
-// agePicker.setAges(ages: details?.ageRestrictionOptions)
+ if let baseUrl {
+ exchange = try? await model.getExchangeByUrl(url: baseUrl)
+ if let details = try? await
model.getWithdrawalDetailsForAmountM(baseUrl, amount: amount) {
+ withdrawalAmountDetails = details
+ }
+ // agePicker.setAges(ages:
details?.ageRestrictionOptions)
} else { // TODO: error
symLog.log("no exchangeBaseUrl or no exchange")
withdrawalAmountDetails = nil
}
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- withdrawalAmountDetails = nil
}
}
}
diff --git a/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
b/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
index 3c39c1d..8968849 100644
--- a/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
@@ -25,6 +25,7 @@ struct WithdrawExchangeV: View {
let _ = Self._printChanges()
let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
#endif
+
Group {
if exchange != nil {
ManualWithdraw(stack: stack.push(),
@@ -39,14 +40,13 @@ struct WithdrawExchangeV: View {
}
.task {
if exchange == nil {
- do { // TODO: cancelled
- symLog.log(".task")
- let withdrawExchange = try await
model.loadWithdrawalExchangeForUriM(url.absoluteString)
+ symLog.log(".task")
+ if let withdrawExchange = try? await
model.loadWithdrawalExchangeForUriM(url.absoluteString) {
let baseUrl = withdrawExchange.exchangeBaseUrl
symLog.log("getExchangeByUrl(\(baseUrl))")
- if let exc = await model.getExchangeByUrl(url: baseUrl) {
+ if let exc = try? await model.getExchangeByUrl(url:
baseUrl) {
// let the controller collect CurrencyInfo from this
formerly unknown exchange
- let _ = await controller.getInfo(from: baseUrl, model:
model)
+ let _ = try? await controller.getInfo(from: baseUrl,
model: model)
if let amount = withdrawExchange.amount {
amountToTransfer = amount
} else {
@@ -56,11 +56,8 @@ struct WithdrawExchangeV: View {
}
exchange = exc
} else {
- // TODO: Error "Can't get Exchange / Payment Service
Provider Info"
+ exchange = nil
}
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- exchange = nil
}
}
}
diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
index da7ce3c..34bd72c 100644
--- a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
+++ b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
@@ -28,14 +28,14 @@ struct TransactionSummaryV: View {
private let symLog = SymLogV(0)
let stack: CallStack
let transactionId: String
- let reloadAction: ((_ transactionId: String) async throws -> Transaction)
+ let reloadAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Transaction)
let navTitle: String?
let doneAction: ((_ stack: CallStack) -> Void)?
- let abortAction: ((_ transactionId: String) async throws -> Void)?
- let deleteAction: ((_ transactionId: String) async throws -> Void)?
- let failAction: ((_ transactionId: String) async throws -> Void)?
- let suspendAction: ((_ transactionId: String) async throws -> Void)?
- let resumeAction: ((_ transactionId: String) async throws -> Void)?
+ let abortAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Void)?
+ let deleteAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Void)?
+ let failAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Void)?
+ let suspendAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Void)?
+ let resumeAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Void)?
@Environment(\.colorScheme) private var colorScheme
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
@@ -50,12 +50,10 @@ struct TransactionSummaryV: View {
@State var viewId = UUID()
func loadTransaction() async {
- do {
- let reloadedTransaction = try await reloadAction(transactionId)
+ if let reloadedTransaction = try? await reloadAction(transactionId,
false) {
symLog.log("reloaded transaction:
\(reloadedTransaction.common.txState.major)")
withAnimation() { transaction = reloadedTransaction; viewId =
UUID() } // redraw
- } catch {
- symLog.log(error.localizedDescription)
+ } else {
withAnimation() { transaction = Transaction(dummyCurrency:
DEMOCURRENCY); viewId = UUID() }
}
}
diff --git a/TalerWallet1/Views/Transactions/TransactionsListView.swift
b/TalerWallet1/Views/Transactions/TransactionsListView.swift
index 9944327..3f2dbc9 100644
--- a/TalerWallet1/Views/Transactions/TransactionsListView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionsListView.swift
@@ -15,7 +15,7 @@ struct TransactionsListView: View {
let transactions: [Transaction]
let showUpDown: Bool
let reloadAllAction: (_ stack: CallStack) async -> ()
- let reloadOneAction: ((_ transactionId: String) async throws ->
Transaction)
+ let reloadOneAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Transaction)
@State private var viewId = UUID()
@State private var upAction: () -> Void = {}
@@ -84,7 +84,7 @@ struct TransactionsArraySliceV: View {
let stack: CallStack
let scopeInfo: ScopeInfo
let transactions: [Transaction]
- let reloadOneAction: ((_ transactionId: String) async throws ->
Transaction)
+ let reloadOneAction: ((_ transactionId: String, _ viewHandles: Bool) async
throws -> Transaction)
@EnvironmentObject private var model: WalletModel
var body: some View {
diff --git a/TestFlight/WhatToTest.en-US.txt b/TestFlight/WhatToTest.en-US.txt
index 4391d6c..0aa1baf 100644
--- a/TestFlight/WhatToTest.en-US.txt
+++ b/TestFlight/WhatToTest.en-US.txt
@@ -1,3 +1,18 @@
+Version 0.9.7 (1)
+
+• better error handling
+- bugfix: wallet-core 0.10.6 cache handling, fee computations
+
+
+Version 0.9.6 (1)
+
+• New feature: Removed 'Banking' tab. Withdraw + deposit are now directly
available in Balances
+ Added Settings->Payment Services for exchange management (w.i.p.)
+• New feature: LocalConsole also for Taler Wallet
+- bugfix: (pending) refresh transactions are now shown correctly
+- bugfix: wallet-core 0.10.2 speeds up fee computations
+
+
Version 0.9.5 (3)
- bugfix: wallet-core 0.10.1 fixes exchange handling
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] branch master updated (c38068b -> 6b94fe0),
gnunet <=
- [taler-taler-ios] 02/17: Bump version to 0.9.6 (1), gnunet, 2024/04/11
- [taler-taler-ios] 03/17: updateExchangeEntry (temporarily) back to exchangeBaseUrl (instead of scopeInfo), gnunet, 2024/04/11
- [taler-taler-ios] 06/17: clientCancellationId, gnunet, 2024/04/11
- [taler-taler-ios] 07/17: Laying the foundations of improved error handling, gnunet, 2024/04/11
- [taler-taler-ios] 04/17: emitObservabilityEvents, gnunet, 2024/04/11
- [taler-taler-ios] 05/17: symLog after quickjs.sendMessage returned, gnunet, 2024/04/11
- [taler-taler-ios] 01/17: rename setConfig, gnunet, 2024/04/11
- [taler-taler-ios] 11/17: Prepare notification error handling, gnunet, 2024/04/11
- [taler-taler-ios] 13/17: Fixes for error handling rebase, gnunet, 2024/04/11
- [taler-taler-ios] 09/17: Implement error handling all around (+refactoring), gnunet, 2024/04/11