[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] 07/54: Big Model update, removed unneccessary thread-s
From: |
gnunet |
Subject: |
[taler-taler-ios] 07/54: Big Model update, removed unneccessary thread-safety code |
Date: |
Fri, 30 Jun 2023 22:33:39 +0200 |
This is an automated email from the git hooks/post-receive script.
marc-stibane pushed a commit to branch master
in repository taler-ios.
commit 2fbfa381a92830d15b953ab87da5391981b82005
Author: Marc Stibane <marc@taler.net>
AuthorDate: Sat Jun 17 14:53:31 2023 +0200
Big Model update, removed unneccessary thread-safety code
---
TalerWallet.xcodeproj/project.pbxproj | 8 ++
TalerWallet1/Controllers/Controller.swift | 4 +-
TalerWallet1/Model/BalancesModel.swift | 12 +-
TalerWallet1/Model/ExchangeModel.swift | 31 ++--
TalerWallet1/Model/PaymentURIModel.swift | 38 +----
TalerWallet1/Model/Peer2peerModel.swift | 11 +-
TalerWallet1/Model/PendingModel.swift | 12 +-
TalerWallet1/Model/SettingsModel.swift | 58 ++++----
TalerWallet1/Model/TransactionsModel.swift | 58 +++-----
TalerWallet1/Model/WalletInitModel.swift | 15 +-
TalerWallet1/Model/WalletModel.swift | 38 ++---
TalerWallet1/Model/WithdrawModel.swift | 98 +++----------
TalerWallet1/Views/Balances/BalancesListView.swift | 55 ++++----
.../Views/Balances/BalancesSectionView.swift | 52 ++++---
TalerWallet1/Views/Exchange/ExchangeListView.swift | 157 +++++++++++----------
.../Views/Exchange/ExchangeSectionView.swift | 15 +-
TalerWallet1/Views/Exchange/ManualWithdraw.swift | 12 +-
.../Views/Exchange/ManualWithdrawDone.swift | 19 +--
.../Views/HelperViews/QRCodeDetailView.swift | 59 ++++++++
TalerWallet1/Views/Main/WalletEmptyView.swift | 8 +-
TalerWallet1/Views/Payment/PaymentAcceptView.swift | 85 +++++------
TalerWallet1/Views/Payment/PaymentURIView.swift | 70 ++++++---
TalerWallet1/Views/Peer2peer/ReceivePurpose.swift | 4 +-
TalerWallet1/Views/Peer2peer/RequestPayment.swift | 3 +-
TalerWallet1/Views/Peer2peer/SendAmount.swift | 70 ++++++---
TalerWallet1/Views/Peer2peer/SendNow.swift | 41 +++---
TalerWallet1/Views/Peer2peer/SendPurpose.swift | 34 ++---
.../Settings/Pending/PendingOpsListView.swift | 28 ++--
TalerWallet1/Views/Settings/SettingsView.swift | 25 ++--
TalerWallet1/Views/Sheets/URLSheet.swift | 5 +-
.../Views/Transactions/TransactionDetailView.swift | 6 +-
.../Views/Transactions/TransactionsEmptyView.swift | 6 +-
.../Views/Transactions/TransactionsListView.swift | 10 +-
.../WithdrawAcceptDone.swift | 61 ++++++++
.../WithdrawAcceptView.swift | 94 +++++++-----
.../WithdrawProgressView.swift | 3 +-
.../WithdrawBankIntegrated/WithdrawTOSView.swift | 55 ++++----
.../WithdrawBankIntegrated/WithdrawURIView.swift | 84 +++++------
38 files changed, 751 insertions(+), 693 deletions(-)
diff --git a/TalerWallet.xcodeproj/project.pbxproj
b/TalerWallet.xcodeproj/project.pbxproj
index 445de65..d570d56 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -15,6 +15,8 @@
4E40E0BE29F25ABB00B85369 /* SendAmount.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4E40E0BD29F25ABB00B85369 /* SendAmount.swift */;
};
4E50B3502A1BEE8000F9F01C /* ManualWithdraw.swift in Sources */
= {isa = PBXBuildFile; fileRef = 4E50B34F2A1BEE8000F9F01C /*
ManualWithdraw.swift */; };
4E53A33729F50B7B00830EC2 /* CurrencyField.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4E53A33629F50B7B00830EC2 /* CurrencyField.swift
*/; };
+ 4E5A88F52A38A4FD00072618 /* QRCodeDetailView.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4E5A88F42A38A4FD00072618 /*
QRCodeDetailView.swift */; };
+ 4E5A88F72A3B9E5B00072618 /* WithdrawAcceptDone.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4E5A88F62A3B9E5B00072618 /*
WithdrawAcceptDone.swift */; };
4E6EDD852A3615BE0031D520 /* ManualDetails.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4E6EDD842A3615BE0031D520 /* ManualDetails.swift
*/; };
4E6EDD872A363D8D0031D520 /* ListStyle.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4E6EDD862A363D8D0031D520 /* ListStyle.swift */;
};
4E753A062A0952F8002D9328 /* DebugViewC.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4E753A052A0952F7002D9328 /* DebugViewC.swift */;
};
@@ -140,6 +142,8 @@
4E40E0BD29F25ABB00B85369 /* SendAmount.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name
= SendAmount.swift; path = TalerWallet1/Views/Peer2peer/SendAmount.swift;
sourceTree = SOURCE_ROOT; };
4E50B34F2A1BEE8000F9F01C /* ManualWithdraw.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= ManualWithdraw.swift; sourceTree = "<group>"; };
4E53A33629F50B7B00830EC2 /* CurrencyField.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= CurrencyField.swift; sourceTree = "<group>"; };
+ 4E5A88F42A38A4FD00072618 /* QRCodeDetailView.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= QRCodeDetailView.swift; sourceTree = "<group>"; };
+ 4E5A88F62A3B9E5B00072618 /* WithdrawAcceptDone.swift */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift;
path = WithdrawAcceptDone.swift; sourceTree = "<group>"; };
4E6EDD842A3615BE0031D520 /* ManualDetails.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= ManualDetails.swift; sourceTree = "<group>"; };
4E6EDD862A363D8D0031D520 /* ListStyle.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= ListStyle.swift; sourceTree = "<group>"; };
4E753A042A08E720002D9328 /* transactions.json */ = {isa =
PBXFileReference; lastKnownFileType = text.json; path = transactions.json;
sourceTree = "<group>"; };
@@ -433,6 +437,7 @@
children = (
4EB0953C2989CBFE0043A8A1 /*
WithdrawURIView.swift */,
4EB0953E2989CBFE0043A8A1 /*
WithdrawAcceptView.swift */,
+ 4E5A88F62A3B9E5B00072618 /*
WithdrawAcceptDone.swift */,
4EB0953F2989CBFE0043A8A1 /*
WithdrawProgressView.swift */,
4EB095402989CBFE0043A8A1 /*
WithdrawTOSView.swift */,
);
@@ -459,6 +464,7 @@
4E53A33629F50B7B00830EC2 /* CurrencyField.swift
*/,
4EA551242A2C923600FEC9A8 /*
CurrencyInputView.swift */,
4EEC157229F8242800D46A03 /*
QRGeneratorView.swift */,
+ 4E5A88F42A38A4FD00072618 /*
QRCodeDetailView.swift */,
4E6EDD862A363D8D0031D520 /* ListStyle.swift */,
4EB095482989CBFE0043A8A1 /*
TextFieldAlert.swift */,
4EB095492989CBFE0043A8A1 /* AmountView.swift */,
@@ -697,6 +703,7 @@
4EB0956A2989CBFE0043A8A1 /* Buttons.swift in
Sources */,
4EB095602989CBFE0043A8A1 /*
BalancesSectionView.swift in Sources */,
4EEC157329F8242800D46A03 /*
QRGeneratorView.swift in Sources */,
+ 4E5A88F72A3B9E5B00072618 /*
WithdrawAcceptDone.swift in Sources */,
4EB095222989CBCB0043A8A1 /* Transaction.swift
in Sources */,
4E9320432A14F6EA00A87B0E /* WalletColors.swift
in Sources */,
4EB0955D2989CBFE0043A8A1 /*
BalancesListView.swift in Sources */,
@@ -707,6 +714,7 @@
4EB095632989CBFE0043A8A1 /*
WithdrawAcceptView.swift in Sources */,
4EB0956D2989CBFE0043A8A1 /* LoadingView.swift
in Sources */,
4E50B3502A1BEE8000F9F01C /*
ManualWithdraw.swift in Sources */,
+ 4E5A88F52A38A4FD00072618 /*
QRCodeDetailView.swift in Sources */,
4E87C8732A31CB7F001C6406 /*
TransactionsEmptyView.swift in Sources */,
4E87C8752A34B411001C6406 /*
UncompletedRowView.swift in Sources */,
4E40E0BE29F25ABB00B85369 /* SendAmount.swift in
Sources */,
diff --git a/TalerWallet1/Controllers/Controller.swift
b/TalerWallet1/Controllers/Controller.swift
index 9a3db72..9e93489 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -43,8 +43,8 @@ class Controller: ObservableObject {
WalletCore.shared.versionInfo = versionInfo
backendState = .ready // dismiss the
launch animation
} catch { // rethrows
- symLog.log(error.localizedDescription)
- backendState = .error // TODO: ❗️Yikes
app cannot continue
+ symLog.log(error.localizedDescription) // TODO: .error
+ backendState = .error // ❗️Yikes app
cannot continue
throw error
}
} else {
diff --git a/TalerWallet1/Model/BalancesModel.swift
b/TalerWallet1/Model/BalancesModel.swift
index 525aabf..b538915 100644
--- a/TalerWallet1/Model/BalancesModel.swift
+++ b/TalerWallet1/Model/BalancesModel.swift
@@ -8,10 +8,8 @@ fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9
seconds for debugging
// MARK: -
class BalancesModel: WalletModel {
- @Published var balances: [Balance]
- override init(_ symbol: Int = -1) {
- balances = [] // empty, but not nil
+ override init(_ symbol: Int = -1) { // init with 0 to disable logging
for this class
super.init(symbol)
}
}
@@ -57,13 +55,13 @@ struct Balance: Decodable, Hashable {
extension BalancesModel {
/// fetch Balances from Wallet-Core. No networking involved
@MainActor func fetchBalancesM()
- async { // M for MainActor
+ async -> [Balance] { // M for MainActor
do {
let request = GetBalances()
- let response = try await sendRequestM(request, ASYNCDELAY)
- balances = response.balances // trigger view update
in BalancesListView
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response.balances // trigger view update in
BalancesListView
} catch {
- balances = []
+ return []
}
}
}
diff --git a/TalerWallet1/Model/ExchangeModel.swift
b/TalerWallet1/Model/ExchangeModel.swift
index fd2a5d5..17169d8 100644
--- a/TalerWallet1/Model/ExchangeModel.swift
+++ b/TalerWallet1/Model/ExchangeModel.swift
@@ -8,10 +8,7 @@ import SymLog
fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for
debugging
class ExchangeModel: WalletModel {
- @Published var exchanges: [Exchange]
-
override init(_ symbol: Int = -1) {
- exchanges = [] // empty, but not nil
super.init(symbol)
}
}
@@ -88,30 +85,22 @@ fileprivate struct AddExchange:
WalletBackendFormattedRequest {
// MARK: -
extension ExchangeModel {
/// ask wallet-core for its list of known exchanges
- @MainActor func updateListM()
- async throws { // M for MainActor
+ @MainActor func listExchangesM()
+ async -> [Exchange] { // M for MainActor
do {
let request = ListExchanges()
- let response = try await sendRequestM(request, ASYNCDELAY)
- exchanges = response.exchanges // trigger view update
in ExchangeListView
- } catch { // rethrows
- symLog?.log(error.localizedDescription)
- throw error
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response.exchanges
+ } catch {
+ return [] // empty, but not nil
}
}
/// add a new exchange with URL to the wallet's list of known exchanges
- func add(url: String) async throws {
- do {
- symLog?.log("adding exchange: \(url)") // TODO: notice
- let request = AddExchange(exchangeBaseUrl: url)
- _ = try await sendRequestT(request) // TODO: MainActor?
- symLog?.log("added exchange: \(url)")
- try await updateListM()
- } catch { // rethrows
- symLog?.log(error.localizedDescription)
- throw error
- }
+ func addExchange(url: String) async throws {
+ symLog?.log("adding exchange: \(url)") // TODO: .notice
+ let request = AddExchange(exchangeBaseUrl: url)
+ _ = try await sendRequest(request)
}
}
diff --git a/TalerWallet1/Model/PaymentURIModel.swift
b/TalerWallet1/Model/PaymentURIModel.swift
index dea406c..73f7036 100644
--- a/TalerWallet1/Model/PaymentURIModel.swift
+++ b/TalerWallet1/Model/PaymentURIModel.swift
@@ -8,22 +8,12 @@ import AnyCodable
//import SymLog
fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for
debugging
-enum PaymentState {
- case error
- case waitingForUriDetails
- case receivedUriDetails
- case waitingForPaymentAck
- case receivedPaymentAck
-}
-
class PaymentURIModel: WalletModel {
- @Published var paymentState: PaymentState?
+
override init(_ symbol: Int = -1) { // init with 0 to disable logging
for this class
super.init(symbol)
}
}
-
-
// MARK: - ContractTerms
struct ContractTerms: Codable {
let amount: Amount
@@ -149,30 +139,16 @@ extension PaymentURIModel {
@MainActor
func preparePayForUriM(_ talerPayUri: String) // M for MainActor
async throws -> PaymentDetailsForUri {
- do {
- paymentState = .waitingForUriDetails
- let request = PreparePayForUri(talerPayUri: talerPayUri)
- let response = try await sendRequestM(request, ASYNCDELAY) //
TODO: MainActor ?
- paymentState = .receivedUriDetails
- return response
- } catch { // rethrows
- paymentState = .error
- throw error
- }
+ let request = PreparePayForUri(talerPayUri: talerPayUri)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
@MainActor
func confirmPayM(_ proposalId: String) // M for MainActor
async throws -> ConfirmPayResult {
- do {
- paymentState = .waitingForPaymentAck
- let request = confirmPayForUri(proposalId: proposalId)
- let response = try await sendRequestM(request, ASYNCDELAY) //
TODO: MainActor ?
- paymentState = .receivedPaymentAck
- return response
- } catch { // rethrows
- paymentState = .error
- throw error
- }
+ let request = confirmPayForUri(proposalId: proposalId)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
}
diff --git a/TalerWallet1/Model/Peer2peerModel.swift
b/TalerWallet1/Model/Peer2peerModel.swift
index 490915c..b8ef429 100644
--- a/TalerWallet1/Model/Peer2peerModel.swift
+++ b/TalerWallet1/Model/Peer2peerModel.swift
@@ -22,9 +22,10 @@ struct PeerContractTerms: Codable {
// MARK: -
/// The result from CheckPeerPushDebit
struct CheckPeerPushDebitResponse: Codable {
- let amountEffective: Amount
+ let exchangeBaseUrl: String
let amountRaw: Amount
-// let maxExpirationDate: Timestamp // TODO: limit expiration (30
days or 7 days)
+ let amountEffective: Amount
+ let maxExpirationDate: Timestamp? // TODO: limit expiration (30
days or 7 days)
}
/// A request to check fees before sending coins to another wallet.
fileprivate struct CheckPeerPushDebit: WalletBackendFormattedRequest {
@@ -91,7 +92,7 @@ extension Peer2peerModel {
func checkPeerPushDebitM(_ amount: Amount) // M for MainActor
async throws -> CheckPeerPushDebitResponse {
let request = CheckPeerPushDebit(amount: amount)
- let response = try await sendRequestM(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY)
return response
}
/// query exchange for fees (invoice coins). Networking involved
@@ -99,7 +100,7 @@ extension Peer2peerModel {
func checkPeerPullCreditM(_ amount: Amount, exchangeBaseUrl: String?)
// M for MainActor
async throws -> CheckPeerPullCreditResponse {
let request = CheckPeerPullCredit(exchangeBaseUrl: exchangeBaseUrl,
amount: amount)
- let response = try await sendRequestM(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY)
return response
}
/// generate peer-push. Networking involved
@@ -108,7 +109,7 @@ extension Peer2peerModel {
async throws -> PeerPushResponse {
let request = InitiatePeerPushDebit(exchangeBaseUrl: baseURL,
partialContractTerms: terms)
- let response = try await sendRequestM(request, ASYNCDELAY)
+ let response = try await sendRequest(request, ASYNCDELAY)
return response
}
}
diff --git a/TalerWallet1/Model/PendingModel.swift
b/TalerWallet1/Model/PendingModel.swift
index 764f799..990b10d 100644
--- a/TalerWallet1/Model/PendingModel.swift
+++ b/TalerWallet1/Model/PendingModel.swift
@@ -9,10 +9,8 @@ import SymLog
fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for
debugging
class PendingModel: WalletModel {
- @Published var pendingOperations: [PendingOperation]
override init(_ symbol: Int = -1) {
- pendingOperations = [] // empty, but not nil
super.init(symbol)
}
}
@@ -51,12 +49,14 @@ struct PendingOperation: Codable, Hashable {
}
// MARK: -
extension PendingModel {
- @MainActor func updateM()
- async throws { // M for MainActor
+ @MainActor func getPendingOperationsM()
+ async -> [PendingOperation] { // M for MainActor
do {
let request = GetPendingOperations()
- let response = try await sendRequestM(request, ASYNCDELAY)
- pendingOperations = response.pendingOperations
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response.pendingOperations
+ } catch {
+ return []
}
}
}
diff --git a/TalerWallet1/Model/SettingsModel.swift
b/TalerWallet1/Model/SettingsModel.swift
index 0172cf6..10d35c0 100644
--- a/TalerWallet1/Model/SettingsModel.swift
+++ b/TalerWallet1/Model/SettingsModel.swift
@@ -7,10 +7,10 @@ import taler_swift
import SymLog
fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for
debugging
-fileprivate let DEMO_EXCHANGEBASEURL = DEMOEXCHANGE //
"https://exchange.demo.taler.net/"
-fileprivate let DEMO_BANKBASEURL = DEMOBANK //
"https://bank.demo.taler.net/"
+fileprivate let DEMO_EXCHANGEBASEURL = DEMOEXCHANGE
+fileprivate let DEMO_BANKBASEURL = DEMOBANK
fileprivate let DEMO_BANKAPIBASEURL = DEMOBANK +
"/demobanks/default/access-api/"
-fileprivate let DEMO_MERCHANTBASEURL = "https://backend.demo.taler.net/"
+fileprivate let DEMO_MERCHANTBASEURL = DEMOBACKEND
fileprivate let DEMO_MERCHANTAUTHTOKEN = "secret-token:sandbox"
// MARK: -
@@ -23,42 +23,32 @@ class SettingsModel: WalletModel {
extension SettingsModel {
@MainActor func loadTestKudosM()
async throws { // M for MainActor
- do {
- let amount = Amount(currency: DEMOCURRENCY, integer: 11, fraction:
0)
- let request = WalletBackendWithdrawTestBalance(amount: amount,
- bankBaseUrl:
DEMO_BANKBASEURL,
- exchangeBaseUrl:
DEMO_EXCHANGEBASEURL,
- bankAccessApiBaseUrl:
DEMO_BANKAPIBASEURL)
- let response = try await sendRequestM(request, ASYNCDELAY)
- symLog?.log("received: \(response)")
- } catch { // rethrows
- symLog?.log(error.localizedDescription)
- throw error
- }
+ let amount = Amount(currency: DEMOCURRENCY, integer: 11, fraction: 0)
+ let request = WalletBackendWithdrawTestBalance(amount: amount,
+ bankBaseUrl:
DEMO_BANKBASEURL,
+ exchangeBaseUrl:
DEMO_EXCHANGEBASEURL,
+ bankAccessApiBaseUrl:
DEMO_BANKAPIBASEURL)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ symLog?.log("received: \(response)")
}
@MainActor func runIntegrationTestM(newVersion: Bool)
async throws { // M for MainActor
- do {
- let amountW = Amount(currency: DEMOCURRENCY, integer: 3, fraction:
0)
- let amountS = Amount(currency: DEMOCURRENCY, integer: 1, fraction:
0)
- let request = WalletBackendRunIntegration(newVersion: newVersion,
- amountToWithdraw: amountW,
- amountToSpend: amountS,
- bankBaseUrl:
DEMO_BANKAPIBASEURL,
- bankAccessApiBaseUrl:
DEMO_BANKAPIBASEURL,
- exchangeBaseUrl:
DEMO_EXCHANGEBASEURL,
- merchantBaseUrl:
DEMO_MERCHANTBASEURL,
- merchantAuthToken:
DEMO_MERCHANTAUTHTOKEN)
- let _ = try await sendRequestT(request, ASYNCDELAY)
- symLog?.log("runIntegrationTest finished")
- } catch { // rethrows
- symLog?.log(error.localizedDescription)
- throw error
- }
+ let amountW = Amount(currency: DEMOCURRENCY, integer: 3, fraction: 0)
+ let amountS = Amount(currency: DEMOCURRENCY, integer: 1, fraction: 0)
+ let request = WalletBackendRunIntegration(newVersion: newVersion,
+ amountToWithdraw: amountW,
+ amountToSpend: amountS,
+ bankBaseUrl:
DEMO_BANKAPIBASEURL,
+ bankAccessApiBaseUrl:
DEMO_BANKAPIBASEURL,
+ exchangeBaseUrl:
DEMO_EXCHANGEBASEURL,
+ merchantBaseUrl:
DEMO_MERCHANTBASEURL,
+ merchantAuthToken:
DEMO_MERCHANTAUTHTOKEN)
+ let _ = try await sendRequest(request, ASYNCDELAY)
+ symLog?.log("runIntegrationTest finished")
}
}
-
+// MARK: -
/// A request to add a test balance to the wallet.
fileprivate struct WalletBackendWithdrawTestBalance:
WalletBackendFormattedRequest {
typealias Response = String
@@ -80,7 +70,7 @@ fileprivate struct WalletBackendWithdrawTestBalance:
WalletBackendFormattedReque
var bankAccessApiBaseUrl: String
}
}
-
+// MARK: -
/// A request to add a test balance to the wallet.
fileprivate struct WalletBackendRunIntegration: WalletBackendFormattedRequest {
struct Response: Decodable {}
diff --git a/TalerWallet1/Model/TransactionsModel.swift
b/TalerWallet1/Model/TransactionsModel.swift
index 668f3c3..bb90bdb 100644
--- a/TalerWallet1/Model/TransactionsModel.swift
+++ b/TalerWallet1/Model/TransactionsModel.swift
@@ -9,18 +9,12 @@ fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9
seconds for debugging
// MARK: -
class TransactionsModel: WalletModel {
- @Published var transactions: [Transaction]
static func specialTransactions(_ transactions: [Transaction]) ->
[Transaction] {
transactions.filter { transaction in
transaction.isSpecial
}
}
- var specialTransactions: [Transaction] {
- transactions.filter { transaction in
- transaction.isSpecial
- }
- }
static func completedTransactions(_ transactions: [Transaction]) ->
[Transaction] {
transactions.filter { transaction in
@@ -39,7 +33,6 @@ class TransactionsModel: WalletModel {
}
override init(_ symbol: Int = -1) {
- transactions = [] // empty, but not nil
super.init(symbol)
}
}
@@ -92,49 +85,42 @@ struct DeleteTransaction: WalletBackendFormattedRequest {
// MARK: -
extension TransactionsModel {
/// ask wallet-core for its list of transactions filtered by searchString
- func fetchTransactions(currency: String?) async { // might be
called from a background thread itself
- await fetchTransactionsM(currency: currency, searchString: nil)
- }
- /// fetch transactions from Wallet-Core. No networking involved
- @MainActor func fetchTransactionsM(currency: String? = nil, searchString:
String? = nil)
- async { // M for MainActor
+ func fetchTransactionsT(currency: String? = nil, searchString: String? =
nil)
+ async -> [Transaction] { //
might be called from a background thread itself
do {
let request = GetTransactions(currency: currency, search:
searchString)
- let response = try await sendRequestM(request, ASYNCDELAY)
- transactions = response.transactions // trigger view update
in TransactionsListView
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response.transactions
} catch {
- transactions = []
+ return []
}
}
+ /// fetch transactions from Wallet-Core. No networking involved
+ @MainActor func fetchTransactionsM(currency: String? = nil, searchString:
String? = nil)
+ async -> [Transaction] { // M for MainActor
+ await fetchTransactionsT(currency: currency, searchString:
searchString)
+ }
- func abortTransaction(transactionId: String) async throws { //
might be called from a background thread itself
- try await abortTransactionM(transactionId: transactionId) // call
deleteTransactionM on main thread
+ func abortTransactionT(transactionId: String)
+ async throws { //
might be called from a background thread itself
+ let request = AbortTransaction(transactionId: transactionId)
+ let _ = try await sendRequest(request, ASYNCDELAY)
}
/// delete the specified transaction from Wallet-Core. No networking
involved
@MainActor func abortTransactionM(transactionId: String)
- async throws { // M for MainActor
- do {
- let request = AbortTransaction(transactionId: transactionId)
- let _ = try await sendRequestT(request, ASYNCDELAY)
- } catch { // rethrows
- symLog?.log(error.localizedDescription)
- throw error
- }
+ async throws { // M for MainActor
+ try await abortTransactionT(transactionId: transactionId) //
call abortTransaction on main thread
}
- func deleteTransaction(transactionId: String) async throws { //
might be called from a background thread itself
- try await deleteTransactionM(transactionId: transactionId) //
call deleteTransactionM on main thread
+ func deleteTransactionT(transactionId: String)
+ async throws { //
might be called from a background thread itself
+ let request = DeleteTransaction(transactionId: transactionId)
+ let _ = try await sendRequest(request, ASYNCDELAY)
}
/// delete the specified transaction from Wallet-Core. No networking
involved
@MainActor func deleteTransactionM(transactionId: String)
- async throws { // M for MainActor
- do {
- let request = DeleteTransaction(transactionId: transactionId)
- let _ = try await sendRequestT(request, ASYNCDELAY)
- } catch { // rethrows
- symLog?.log(error.localizedDescription)
- throw error
- }
+ async throws { // M for MainActor
+ try await deleteTransactionT(transactionId: transactionId) //
call deleteTransaction on main thread
}
}
diff --git a/TalerWallet1/Model/WalletInitModel.swift
b/TalerWallet1/Model/WalletInitModel.swift
index d977890..8ce0bf4 100644
--- a/TalerWallet1/Model/WalletInitModel.swift
+++ b/TalerWallet1/Model/WalletInitModel.swift
@@ -49,16 +49,11 @@ extension WalletInitModel {
/// initalize Wallet-Core. Will do networking
func initWalletT() // T for any Thread
async throws -> VersionInfo? {
- do {
- let docPath = try docPath()
- let request = WalletBackendInitRequest(persistentStoragePath:
docPath)
- symLog?.log("info: not main thread")
- let response = try await sendRequestT(request, 0) // no Delay
- return response.versionInfo
- } catch { // rethrows
- symLog?.log("error: \(error)")
- throw error
- }
+ let docPath = try docPath()
+ let request = WalletBackendInitRequest(persistentStoragePath:
docPath)
+ symLog?.log("info: not main thread")
+ let response = try await sendRequest(request, 0) // no Delay
+ return response.versionInfo
}
private func docPath () throws -> String {
diff --git a/TalerWallet1/Model/WalletModel.swift
b/TalerWallet1/Model/WalletModel.swift
index 9fb0622..34626ca 100644
--- a/TalerWallet1/Model/WalletModel.swift
+++ b/TalerWallet1/Model/WalletModel.swift
@@ -10,30 +10,15 @@ fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9
seconds for debugging
// MARK: -
/// The "virtual" base class for all models
-class WalletModel: ObservableObject {
+class WalletModel {
static func className() -> String {"\(self)"}
var symLog: SymLogC?
- @Published var loading: Bool = false // update view
-
init(_ symbol: Int) { // init with 0 to
disable logging for this class
self.symLog = SymLogC(symbol == 0 ? 0 : -1, funcName: Self.className())
}
- @MainActor func sendRequestM<T: WalletBackendFormattedRequest> (_ request:
T, _ delay: UInt = 0)
- async throws -> T.Response { // M for MainActor
- loading = true // enter progressView
- do {
- let response = try await sendRequestT(request, delay)
- loading = false // exit progressView
- return response
- } catch { // rethrows
- loading = false // exit progressView
- throw error
- }
- }
-
- func sendRequestT<T: WalletBackendFormattedRequest> (_ request: T, _
delay: UInt = 0)
+ func sendRequest<T: WalletBackendFormattedRequest> (_ request: T, _ delay:
UInt = 0)
async throws -> T.Response { // T for any Thread
let sendTime = Date.now
do {
@@ -56,24 +41,21 @@ class WalletModel: ObservableObject {
}
}
- func getTransactionById(transactionId: String) async throws -> Transaction
{ // might be called from a background thread itself
- return try await getTransactionByIdM(transactionId: transactionId)
// call deleteTransactionM on main thread
+ func getTransactionByIdT(_ transactionId: String)
+ 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)
}
/// get the specified transaction from Wallet-Core. No networking involved
- @MainActor func getTransactionByIdM(transactionId: String)
+ @MainActor func getTransactionByIdM(_ transactionId: String)
async throws -> Transaction { // M for MainActor
- do {
- let request = GetTransactionById(transactionId: transactionId)
- let response = try await sendRequestT(request, ASYNCDELAY)
- return response
- } catch { // rethrows
- throw error
- }
+ return try await getTransactionByIdT(transactionId) // call
GetTransactionById on main thread
}
}
// MARK: -
/// A request to get a wallet transaction by ID.
-struct GetTransactionById: WalletBackendFormattedRequest {
+fileprivate struct GetTransactionById: WalletBackendFormattedRequest {
typealias Response = Transaction
func operation() -> String { return "getTransactionById" }
func args() -> Args { return Args(transactionId: transactionId) }
diff --git a/TalerWallet1/Model/WithdrawModel.swift
b/TalerWallet1/Model/WithdrawModel.swift
index b3a2161..96fc31a 100644
--- a/TalerWallet1/Model/WithdrawModel.swift
+++ b/TalerWallet1/Model/WithdrawModel.swift
@@ -7,22 +7,8 @@ import taler_swift
import SymLog
fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for
debugging
-enum WithdrawState {
- case error
- case waitingForUriDetails
- case receivedUriDetails
- case waitingForAmountDetails
- case receivedAmountDetails
- case waitingForTOS
- case receivedTOS
- case waitingForTOSAck
- case receivedTOSAck
- case waitingForWithdrAck
- case receivedWithdrAck
-}
-
class WithdrawModel: WalletModel {
- @Published var withdrawState: WithdrawState?
+
override init(_ symbol: Int = -1) { // init with 0 to disable logging
for this class
super.init(symbol)
}
@@ -166,87 +152,45 @@ extension WithdrawModel {
@MainActor
func loadWithdrawalDetailsForUriM(_ talerWithdrawUri: String)
// M for MainActor
async throws -> WithdrawUriInfoResponse {
- do {
- withdrawState = .waitingForUriDetails
- let request = GetWithdrawalDetailsForURI(talerWithdrawUri:
talerWithdrawUri)
- let response = try await sendRequestM(request, ASYNCDELAY)
// TODO: MainActor ?
- withdrawState = .receivedUriDetails
- return response
- } catch { // rethrows
- withdrawState = .error
- throw error
- }
+ let request = GetWithdrawalDetailsForURI(talerWithdrawUri:
talerWithdrawUri)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
@MainActor
func loadWithdrawalDetailsForAmountM(_ exchangeBaseUrl: String, amount:
Amount) // M for MainActor
async throws -> ManualWithdrawalDetails {
- do {
- withdrawState = .waitingForAmountDetails
- let request = GetWithdrawalDetailsForAmount(exchangeBaseUrl:
exchangeBaseUrl,
- amount:
amount)
- let response = try await sendRequestM(request, ASYNCDELAY)
// TODO: MainActor ?
- withdrawState = .receivedAmountDetails
- return response
- } catch { // rethrows
- withdrawState = .error
- throw error
- }
+ let request = GetWithdrawalDetailsForAmount(exchangeBaseUrl:
exchangeBaseUrl,
+ amount: amount)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
@MainActor
func loadExchangeTermsOfServiceM(_ exchangeBaseUrl: String) //
M for MainActor
async throws -> ExchangeTermsOfService {
- do {
- withdrawState = .waitingForTOS
- let request = GetExchangeTermsOfService(exchangeBaseUrl:
exchangeBaseUrl)
- let response = try await sendRequestM(request, ASYNCDELAY)
// TODO: MainActor ?
- withdrawState = .receivedTOS
- return response
- } catch { // rethrows
- withdrawState = .error
- throw error
- }
+ let request = GetExchangeTermsOfService(exchangeBaseUrl:
exchangeBaseUrl)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
@MainActor
func setExchangeTOSAcceptedM(_ exchangeBaseUrl: String, etag: String)
// M for MainActor
async throws -> Decodable {
- do {
- withdrawState = .waitingForTOSAck
- let request = SetExchangeTOSAccepted(exchangeBaseUrl:
exchangeBaseUrl, etag: etag)
- let response = try await sendRequestM(request, ASYNCDELAY)
// TODO: MainActor ?
- withdrawState = .receivedTOSAck
- return response
- } catch { // rethrows
- withdrawState = .error
- throw error
- }
+ let request = SetExchangeTOSAccepted(exchangeBaseUrl: exchangeBaseUrl,
etag: etag)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
@MainActor
func sendAcceptIntWithdrawalM(_ exchangeBaseUrl: String, withdrawURL:
String) // M for MainActor
async throws -> String? {
- do {
- withdrawState = .waitingForWithdrAck
- let request = AcceptBankIntegratedWithdrawal(talerWithdrawUri:
withdrawURL, exchangeBaseUrl: exchangeBaseUrl)
- let response = try await sendRequestM(request, ASYNCDELAY)
// TODO: MainActor ?
- withdrawState = .receivedWithdrAck
- return response.confirmTransferUrl
- } catch { // rethrows
- withdrawState = .error
- throw error
- }
+ let request = AcceptBankIntegratedWithdrawal(talerWithdrawUri:
withdrawURL, exchangeBaseUrl: exchangeBaseUrl)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response.confirmTransferUrl
}
@MainActor
func sendAcceptManualWithdrawalM(_ exchangeBaseUrl: String, amount:
Amount, restrictAge: Int?) // M for MainActor
- async throws -> AcceptManualWithdrawalResult? {
- do {
- withdrawState = .waitingForWithdrAck
- let request = AcceptManualWithdrawal(exchangeBaseUrl:
exchangeBaseUrl, amount: amount, restrictAge: restrictAge)
- let response = try await sendRequestM(request, ASYNCDELAY)
// TODO: MainActor ?
- withdrawState = .receivedWithdrAck
- return response
- } catch { // rethrows
- withdrawState = .error
- throw error
- }
+ async throws -> AcceptManualWithdrawalResult? {
+ let request = AcceptManualWithdrawal(exchangeBaseUrl: exchangeBaseUrl,
amount: amount, restrictAge: restrictAge)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
}
}
diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift
b/TalerWallet1/Views/Balances/BalancesListView.swift
index 15d0f1c..d4b46e0 100644
--- a/TalerWallet1/Views/Balances/BalancesListView.swift
+++ b/TalerWallet1/Views/Balances/BalancesListView.swift
@@ -11,13 +11,13 @@ import AVFoundation
struct BalancesListView: View {
private let symLog = SymLogV()
- let navTitle = String(localized: "GNU Taler") // + Wallet
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ let navTitle: String
- @ObservedObject var model: BalancesModel
- var hamburgerAction: () -> Void
+ @State var balances: [Balance] = []
+ let model: BalancesModel?
+ let hamburgerAction: () -> Void
- @State private var centsToTransfer: UInt64 = 0 // TODO: maybe
Decimal?
+ @State private var centsToTransfer: UInt64 = 0
@State private var showQRScanner: Bool = false
@State private var showCameraAlert: Bool = false
@@ -60,22 +60,38 @@ struct BalancesListView: View {
})
}
+ private func reloadAction() async {
+ if let model {
+ balances = await model.fetchBalancesM()
+ } else {
+ balances = []
+ }
+ }
+
var body: some View {
#if DEBUG
let _ = Self._printChanges()
let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
#endif
- let reloadAction = model.fetchBalancesM
- Content(symLog: symLog, model: model, centsToTransfer:
$centsToTransfer,
- reloadAction: reloadAction, myListStyle: $myListStyle)
+ Content(symLog: symLog, balances: $balances, centsToTransfer:
$centsToTransfer,
+ reloadAction: reloadAction)
.navigationTitle(navTitle)
+ .navigationBarTitleDisplayMode(.automatic)
.navigationBarItems(leading: HamburgerButton(action:
hamburgerAction),
trailing: QRButton(action:
checkCameraAvailable))
+ .overlay {
+ if balances.isEmpty {
+ WalletEmptyView()
+ }
+ }
.alert("Scanning QR-codes requires access to the camera",
isPresented: $showCameraAlert,
actions: { openSettingsButton
dismissAlertButton },
message: { Text("Please allow camera access in
settings.") })
+ .onAppear() {
+ DebugViewC.shared.setViewID(VIEW_BALANCES)
+ }
.sheet(isPresented: $showQRScanner) {
let sheet = AnyView(QRSheet())
Sheet(sheetView: sheet)
@@ -90,18 +106,18 @@ struct BalancesListView: View {
extension BalancesListView {
struct Content: View {
let symLog: SymLogV?
- @ObservedObject var model: BalancesModel
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
+ @Binding var balances: [Balance]
@Binding var centsToTransfer: UInt64
- var reloadAction: () async -> ()
- @Binding var myListStyle: MyListStyle
+ var reloadAction: () async -> Void
var body: some View {
#if DEBUG
let _ = Self._printChanges()
let _ = symLog?.vlog() // just to get the # to compare it
with .onAppear & onDisappear
#endif
- Group {
- List (model.balances, id: \.self) { balance in
+ Group { // necessary for .backslide transition (bug in SwiftUI)
+ List(balances, id: \.self) { balance in
let model = TransactionsModel.model(currency:
balance.available.currencyStr)
BalancesSectionView(balance: balance, centsToTransfer:
$centsToTransfer, model: model)
}
@@ -109,18 +125,7 @@ extension BalancesListView {
symLog?.log("refreshing")
await reloadAction() // this closure is already
async, no need for a Task
}
- .listStyle(myListStyle.style)
- .anyView
- }
- .navigationBarTitleDisplayMode(.automatic)
- .onAppear() {
- DebugViewC.shared.setViewID(VIEW_BALANCES)
- }
- .overlay {
- if model.balances.isEmpty {
- WalletEmptyView()
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
- }
+ .listStyle(myListStyle.style).anyView
}
// automatically fetch balances after receiving
transaction-state-transition ...
.onNotification(.TransactionStateTransition) { notification in
diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift
b/TalerWallet1/Views/Balances/BalancesSectionView.swift
index d9535c1..ce14f10 100644
--- a/TalerWallet1/Views/Balances/BalancesSectionView.swift
+++ b/TalerWallet1/Views/Balances/BalancesSectionView.swift
@@ -18,37 +18,46 @@ struct BalancesSectionView: View {
private let symLog = SymLogV()
var balance:Balance
@Binding var centsToTransfer: UInt64
- @ObservedObject var model: TransactionsModel
+ var model: TransactionsModel?
@State private var isShowingDetailView = false
@State private var buttonSelected: Int? = nil
+
+ @State private var transactions: [Transaction] = []
@State private var completedTransactions: [Transaction] = []
@State private var pendingTransactions: [Transaction] = []
@State private var uncompletedTransactions: [Transaction] = []
+ func dummyTransaction (_ transactionId: String) async throws {}
var body: some View {
let currency = balance.available.currencyStr
let reloadCompleted = {
- await model.fetchTransactions(currency: currency)
- completedTransactions =
TransactionsModel.completedTransactions(model.transactions)
+ if let model {
+ transactions = await model.fetchTransactionsT(currency:
currency)
+ completedTransactions =
TransactionsModel.completedTransactions(transactions)
+ }
}
let reloadPending = {
- await model.fetchTransactions(currency: currency)
- pendingTransactions =
TransactionsModel.pendingTransactions(model.transactions)
+ if let model {
+ transactions = await model.fetchTransactionsT(currency:
currency)
+ pendingTransactions =
TransactionsModel.pendingTransactions(transactions)
+ }
}
let reloadUncompleted = {
- await model.fetchTransactions(currency: currency)
- uncompletedTransactions =
TransactionsModel.uncompletedTransactions(model.transactions)
+ if let model {
+ transactions = await model.fetchTransactionsT(currency:
currency)
+ uncompletedTransactions =
TransactionsModel.uncompletedTransactions(transactions)
+ }
}
- let deleteAction = model.deleteTransaction
- let abortAction = model.abortTransaction
+ let deleteAction = model?.deleteTransactionT ?? dummyTransaction
+ let abortAction = model?.abortTransactionT ?? dummyTransaction
Section {
- if "KUDOS" == currency && !balance.available.isZero {
- Text("You can spend these KUDOS in the [Demo
Shop](https://shop.demo.taler.net), or send coins to another wallet.")
- .multilineTextAlignment(.leading)
- }
+// if "KUDOS" == currency && !balance.available.isZero {
+// Text("You can spend these KUDOS in the [Demo
Shop](https://shop.demo.taler.net), or send coins to another wallet.")
+// .multilineTextAlignment(.leading)
+// }
HStack(spacing: 0) {
NavigationLink(destination: LazyView {
SendAmount(amountAvailable: balance.available)
@@ -56,10 +65,8 @@ struct BalancesSectionView: View {
) { EmptyView() }.frame(width: 0).opacity(0).hidden()
NavigationLink(destination: LazyView {
- RequestPayment(model: Peer2peerModel.model(),
- scopeInfo: balance.scopeInfo,
- centsToTransfer: $centsToTransfer)
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+ RequestPayment(scopeInfo: balance.scopeInfo,
+ centsToTransfer: $centsToTransfer)
}, tag: 2, selection: $buttonSelected
) { EmptyView() }.frame(width: 0).opacity(0).hidden()
@@ -127,9 +134,11 @@ let _ = print("button: Uncompleted Transactions:
\(currency)")
Text(currency)
.font(.title)
} .task {
- await model.fetchTransactions(currency: currency)
- pendingTransactions =
TransactionsModel.pendingTransactions(model.transactions)
- uncompletedTransactions =
TransactionsModel.uncompletedTransactions(model.transactions)
+ if let model {
+ transactions = await model.fetchTransactionsT(currency:
currency)
+ pendingTransactions =
TransactionsModel.pendingTransactions(transactions)
+ uncompletedTransactions =
TransactionsModel.uncompletedTransactions(transactions)
+ }
}
} // body
}
@@ -137,7 +146,6 @@ let _ = print("button: Uncompleted Transactions:
\(currency)")
#if DEBUG
fileprivate struct BindingViewContainer : View {
@State var centsToTransfer: UInt64 = 333
- let model = TransactionsModel.model(currency: LONGCURRENCY)
var body: some View {
let scopeInfo = ScopeInfo(type: ScopeInfo.ScopeInfoType.exchange,
exchangeBaseUrl: DEMOEXCHANGE, currency: LONGCURRENCY)
@@ -148,7 +156,7 @@ fileprivate struct BindingViewContainer : View {
requiresUserInput: false,
scopeInfo: scopeInfo)
List {
- BalancesSectionView(balance: balance, centsToTransfer:
$centsToTransfer, model: model)
+ BalancesSectionView(balance: balance, centsToTransfer:
$centsToTransfer, model: nil)
}
}
}
diff --git a/TalerWallet1/Views/Exchange/ExchangeListView.swift
b/TalerWallet1/Views/Exchange/ExchangeListView.swift
index e7fd4fe..96c880e 100644
--- a/TalerWallet1/Views/Exchange/ExchangeListView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeListView.swift
@@ -9,68 +9,92 @@ import SymLog
/// This view shows the list of exchanges
struct ExchangeListView: View {
private let symLog = SymLogV()
- let navTitle = String(localized: "Exchanges")
+ let navTitle: String
- @ObservedObject var model: ExchangeModel
+ var model: ExchangeModel?
var hamburgerAction: () -> Void
+ @State private var exchanges: [Exchange] = []
- // source of truth for the value the user enters in currencyField
- @State private var centsToTransfer: UInt64 = 0 // TODO: different
values for different currencies
+ // source of truth for the value the user enters in currencyField for
exchange withdrawals
+ @State private var centsToTransfer: UInt64 = 0 // TODO: different
values for different currencies?
+
+ func reloadAction() async -> Void {
+ if let model {
+ exchanges = await model.listExchangesM()
+ } else {
+ exchanges = []
+ }
+ }
+
+ func addExchange(_ exUrl: String) -> Void {
+ Task {
+ if let model {
+ symLog.log("adding: \(exUrl)")
+ do {
+ try await model.addExchange(url: exUrl)
+ symLog.log("added: \(exUrl)")
+ } catch { // TODO: error handling - couldn't add exchangeURL
+ symLog.log("error: \(error)")
+ }
+ } else {
+ symLog.log("no model, cannot add \(exUrl)")
+ }
+ }
+ }
+
+ @State var showAlert: Bool = false
+ @State var newExchange: String = "https://exchange-age.taler.ar/"
var body: some View {
#if DEBUG
let _ = Self._printChanges()
let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
#endif
- let reloadAction = model.updateListM
- Content(symLog: symLog, model: model,
+ let plusAction: () -> Void = {
+// withAnimation { showAlert = true }
+ showAlert = true
+ }
+
+ //Text("Exchanges...")
+ Content(symLog: symLog,
+ exchanges: $exchanges,
centsToTransfer: $centsToTransfer,
reloadAction: reloadAction)
- .navigationBarItems(leading: HamburgerButton(action:
hamburgerAction))
- .navigationTitle(navTitle)
- .task {
- symLog.log(".task")
- do {
- try await reloadAction()
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ .navigationTitle(navTitle)
+ .navigationBarTitleDisplayMode(.automatic)
+ .navigationBarItems(leading: HamburgerButton(action: hamburgerAction),
+ trailing: PlusButton(action: plusAction))
+ .overlay {
+ if exchanges.isEmpty {
+ Text("No Exchanges yet...")
}
+ }
+ .task {
+ symLog.log(".task")
+ await reloadAction()
+ }
+ .textFieldAlert(isPresented: $showAlert, title: "Add Exchange",
+ doneText: "Add", text: $newExchange, action:
addExchange)
}
}
// MARK: -
-struct ExchangeAmount: Identifiable {
- let exchange: Exchange
- let amountAvailable: Amount
-
- var id: String { // needed for Identifiable
- exchange.exchangeBaseUrl
- }
-}
+//struct ExchangeAmount: Identifiable {
+// let exchange: Exchange
+// let amountAvailable: Amount
+//
+// var id: String { // needed for Identifiable
+// exchange.exchangeBaseUrl
+// }
+//}
// MARK: -
extension ExchangeListView {
struct Content: View {
let symLog: SymLogV?
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
- @ObservedObject var model: ExchangeModel
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
+ @Binding var exchanges: [Exchange]
@Binding var centsToTransfer: UInt64
- var reloadAction: () async throws -> ()
-
- @State var showAlert: Bool = false
- @State var newExchange: String = "https://exchange-age.taler.ar/"
-
- func addExchange(_ exUrl: String) -> Void {
- Task {
- do {
- symLog?.log("adding: \(exUrl)")
- try await model.add(url: exUrl)
- symLog?.log("added: \(exUrl)")
- } catch { // TODO: error handling - couldn't add exchangeURL
- symLog?.log("error: \(error)")
- }
- }
- }
+ var reloadAction: () async -> Void
func currenciesDict(_ exchanges: [Exchange]) -> [String : [Exchange]] {
var currencies: [String : [Exchange]] = [:]
@@ -86,44 +110,29 @@ extension ExchangeListView {
return currencies
}
- @State private var exchangeAmount: ExchangeAmount? = nil
+// @State private var exchangeAmount: ExchangeAmount? = nil
var body: some View {
- let plusAction: () -> Void = {
-// withAnimation { showAlert = true }
- showAlert = true
+ let dict = currenciesDict(exchanges)
+ let sortedDict = dict.sorted{ $0.key < $1.key}
+ Group { // necessary for .backslide transition (bug in SwiftUI)
+ List(sortedDict, id: \.key) { key, value in
+ ExchangeSectionView(currency: key, exchanges: value,
centsToTransfer: $centsToTransfer)
+ }
+ .refreshable {
+ symLog?.log("refreshing")
+ await reloadAction()
+ }
+ .listStyle(myListStyle.style).anyView
}
- VStack {
- if model.exchanges.isEmpty {
- Text("No Exchanges yet...")
- } else {
- ScrollViewReader { scrollView in //
- let dict = currenciesDict(model.exchanges)
- let sortedDict = dict.sorted{ $0.key < $1.key}
- List {
- ForEach(sortedDict, id: \.key) { key, value in
- ExchangeSectionView(currency: key, exchanges:
value, centsToTransfer: $centsToTransfer)
- }
- }
- .refreshable {
- do {
- symLog?.log("refreshing")
- try await reloadAction()
- } catch { // TODO: error
- symLog?.log(error.localizedDescription)
- }
- }
- .listStyle(myListStyle.style)
- .anyView
- }
- } // else
- }.onAppear() {
+ .onAppear() {
DebugViewC.shared.setViewID(VIEW_EXCHANGES)
}
- .navigationBarTitleDisplayMode(.automatic)
- .navigationBarItems(trailing: PlusButton(action: plusAction))
- .textFieldAlert(isPresented: $showAlert, title: "Add Exchange",
- doneText: "Add", text: $newExchange, action:
addExchange)
+ .onNotification(.ExchangeAdded) { notification in
+ // doesn't need to be received on main thread because we just
reload in the background anyway
+ symLog?.log(".onNotification(.ExchangeAdded) ==> reloading
exchanges")
+ Task { await reloadAction() }
+ }
} // body
}
}
diff --git a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
index cdcacbe..725b6b9 100644
--- a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
@@ -18,22 +18,15 @@ struct ExchangeRowView: View {
Text(baseURL.trimURL())
NavigationLink(destination: LazyView {
- EmptyView()
+ EmptyView() // TODO: Deposit
}, tag: 1, selection: $buttonSelected
- ) {
- EmptyView()
- } .frame(width: 0)
- .opacity(0)
+ ) { EmptyView() }.frame(width: 0).opacity(0)
NavigationLink(destination: LazyView {
ManualWithdraw(exchange: exchange,
model: model,
centsToTransfer: $centsToTransfer)
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}, tag: 2, selection: $buttonSelected
- ) {
- EmptyView()
- } .frame(width: 0)
- .opacity(0)
+ ) { EmptyView() }.frame(width: 0).opacity(0)
}.listRowSeparator(.hidden)
HStack { // buttons just set "buttonSelected" so the
NavigationLink will trigger
@@ -80,7 +73,7 @@ struct ExchangeSectionView: View {
// MARK: -
#if DEBUG
struct ExchangeRow_Container : View {
- @State private var centsToTransfer: UInt64 = 100 // TODO: maybe
Decimal?
+ @State private var centsToTransfer: UInt64 = 100
var body: some View {
let exchange1 = Exchange(exchangeBaseUrl: DEMO_AGE_EXCHANGE,
diff --git a/TalerWallet1/Views/Exchange/ManualWithdraw.swift
b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
index 194fd2d..752165d 100644
--- a/TalerWallet1/Views/Exchange/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
@@ -11,7 +11,7 @@ struct ManualWithdraw: View {
let navTitle = String(localized: "Withdraw Coins")
var exchange: Exchange
- @ObservedObject var model: WithdrawModel
+ var model: WithdrawModel?
@Binding var centsToTransfer: UInt64
@State var manualWithdrawalDetails: ManualWithdrawalDetails? = nil
@@ -45,7 +45,6 @@ struct ManualWithdraw: View {
ScrollView {
Text("from \(exchange.exchangeBaseUrl.trimURL())")
- .padding(.top)
.font(.title3)
CurrencyInputView(currencyField: currencyField, title:
String(localized: "Amount to withdraw:"))
@@ -119,8 +118,9 @@ let _ = print(selectedAge, restrictAge)
Spacer()
}
.frame(maxWidth: .infinity, alignment: .leading)
- .navigationTitle(navTitle)
.padding(.horizontal)
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+ .navigationTitle(navTitle)
.onAppear {
symLog.log("onAppear")
DebugViewC.shared.setViewID(VIEW_WITHDRAWAL)
@@ -128,8 +128,10 @@ let _ = print(selectedAge, restrictAge)
.task(id: centsToTransfer) {
let amount = Amount.amountFromCents(currency, centsToTransfer)
do {
- manualWithdrawalDetails = try await
model.loadWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl, amount: amount)
- agePicker.setAges(ages:
manualWithdrawalDetails?.ageRestrictionOptions)
+ if let model {
+ manualWithdrawalDetails = try await
model.loadWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl, amount: amount)
+// agePicker.setAges(ages:
manualWithdrawalDetails?.ageRestrictionOptions)
+ }
} catch { // TODO: error
symLog.log(error.localizedDescription)
manualWithdrawalDetails = nil
diff --git a/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
b/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
index 3d698bf..2e771ac 100644
--- a/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
+++ b/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
@@ -11,7 +11,7 @@ struct ManualWithdrawDone: View {
let navTitle = String(localized: "Wire Transfer")
var exchange: Exchange
- @ObservedObject var model: WithdrawModel
+ var model: WithdrawModel?
var centsToTransfer: UInt64
var restrictAge: Int?
@State var acceptManualWithdrawalResult: AcceptManualWithdrawalResult?
@@ -37,13 +37,15 @@ struct ManualWithdrawDone: View {
DebugViewC.shared.setViewID(VIEW_WITHDRAW_ACCEPT)
}.task {
do {
- let amount = Amount.amountFromCents(exchange.currency!,
centsToTransfer)
- let result = try await
model.sendAcceptManualWithdrawalM(exchange.exchangeBaseUrl,
-
amount: amount, restrictAge: restrictAge)
+ if let model {
+ let amount = Amount.amountFromCents(exchange.currency!,
centsToTransfer)
+ let result = try await
model.sendAcceptManualWithdrawalM(exchange.exchangeBaseUrl,
+
amount: amount, restrictAge: restrictAge)
print(result as Any)
- let transaction = try await
model.getTransactionById(transactionId: result!.transactionId)
- withdrawalTransaction = transaction
-// acceptManualWithdrawalResult = result
+ let transaction = try await
model.getTransactionByIdT(result!.transactionId)
+ withdrawalTransaction = transaction
+// acceptManualWithdrawalResult = result
+ }
} catch { // TODO: error
symLog.log(error.localizedDescription)
}
@@ -57,7 +59,6 @@ struct ManualWithdrawDone_Container : View {
@State private var centsToTransfer: UInt64 = 510
var body: some View {
- let model = WithdrawModel.model(baseURL: DEMOEXCHANGE)
let exchange = Exchange(exchangeBaseUrl: DEMOEXCHANGE,
currency: LONGCURRENCY,
paytoUris: [],
@@ -66,7 +67,7 @@ struct ManualWithdrawDone_Container : View {
ageRestrictionOptions: [],
permanent: false)
ManualWithdrawDone(exchange: exchange,
- model: model,
+ model: nil,
centsToTransfer: centsToTransfer)
}
}
diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
new file mode 100644
index 0000000..0d5366b
--- /dev/null
+++ b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
@@ -0,0 +1,59 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+import SwiftUI
+import taler_swift
+import AVFoundation
+
+
+struct QRCodeDetailView: View {
+ var talerURI: String
+
+ var body: some View {
+ if talerURI.count > 10 {
+ VStack {
+ Text("Let the payee scan this QR code to receive:")
+ .fixedSize(horizontal: false, vertical: true)
+ .padding(.top, 30)
+ .font(.title3)
+
+ QRGeneratorView(text: talerURI)
+// Text(talerURI)
+
+ Text("Alternatively, copy and send this URI:")
+ .fixedSize(horizontal: false, vertical: true)
+ .font(.title3)
+ .padding(.vertical)
+
+ Text(talerURI)
+ .padding(.bottom)
+
+ CopyShare(textToCopy: talerURI, dismissFirst: true)
+ .disabled(false)
+ }
+ }
+ }
+}
+
+
+#if DEBUG
+fileprivate struct ContentView: View {
+ @State var isOn = false
+
+ var body: some View {
+ VStack {
+
+ }
+ }
+}
+struct QRCodeDetailView_Previews: PreviewProvider {
+
+ static var previews: some View {
+// ContentView()
+ List {
+ QRCodeDetailView(talerURI:
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520")
+ }
+ }
+}
+#endif
diff --git a/TalerWallet1/Views/Main/WalletEmptyView.swift
b/TalerWallet1/Views/Main/WalletEmptyView.swift
index a6a810a..2b41daa 100644
--- a/TalerWallet1/Views/Main/WalletEmptyView.swift
+++ b/TalerWallet1/Views/Main/WalletEmptyView.swift
@@ -10,7 +10,7 @@ import SymLog
struct WalletEmptyView: View {
private let symLog = SymLogV()
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
var body: some View {
List {
@@ -27,10 +27,10 @@ struct WalletEmptyView: View {
Text("Just register a test account, then withdraw some coins.")
}
}
- .padding(.vertical)
+// .padding(.vertical)
.font(.title2)
- .listStyle(myListStyle.style)
- .anyView
+ .listStyle(myListStyle.style).anyView
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear() {
DebugViewC.shared.setViewID(VIEW_EMPTY) // 10
}
diff --git a/TalerWallet1/Views/Payment/PaymentAcceptView.swift
b/TalerWallet1/Views/Payment/PaymentAcceptView.swift
index 75cd0c1..fe30c78 100644
--- a/TalerWallet1/Views/Payment/PaymentAcceptView.swift
+++ b/TalerWallet1/Views/Payment/PaymentAcceptView.swift
@@ -9,53 +9,24 @@ import SymLog
struct PaymentAcceptView: View {
private let symLog = SymLogV()
- @ObservedObject var model: PaymentURIModel
- let detailsForAmount: PaymentDetailsForUri
+ let detailsForUri: PaymentDetailsForUri
+ let acceptAction: () -> Void
let navTitle = String(localized: "Accept Payment")
- @State private var confirmPayResult: ConfirmPayResult?
-
- func playSound(success: Bool) {
-// let url = URL(fileURLWithPath:
"/System/Library/Audio/UISounds/PaymentReceived.caf")
- let url = URL(fileURLWithPath:
"/System/Library/Audio/UISounds/payment_" + (success ? "success.caf"
-
: "failure.caf"))
- var soundID: SystemSoundID = 0
- AudioServicesCreateSystemSoundID(url as CFURL, &soundID)
- print(soundID)
- AudioServicesPlaySystemSound(soundID);
- }
- func acceptAction() {
- Task {
- do {
- confirmPayResult = try await
model.confirmPayM(detailsForAmount.proposalId)
- symLog.log(confirmPayResult as Any)
- if confirmPayResult?.type == "done" {
- // TODO: Show Hints that Payment was successfull
- playSound(success: true)
- } else {
- // TODO: show error
- playSound(success: false)
- }
- } catch { // TODO: error
- symLog.log(error.localizedDescription)
- }
- dismissTop()
- }
- }
@State private var disabled = false
var body: some View {
Group {
- let raw = detailsForAmount.amountRaw
- let effective = detailsForAmount.amountEffective
+ let raw = detailsForUri.amountRaw
+ let effective = detailsForUri.amountEffective
let fee = try! Amount.diff(raw, effective) // TODO: different
currencies
ThreeAmountsView(topTitle: "Amount to pay:",
topAmount: raw, fee: fee,
bottomTitle: "Coins to be spent:",
bottomAmount: effective,
large: true, pending: false, incoming: false,
- baseURL:
detailsForAmount.contractTerms.exchanges.first?.url)
+ baseURL:
detailsForUri.contractTerms.exchanges.first?.url)
// TODO: payment: popup with all possible exchanges, check fees
.safeAreaInset(edge: .bottom) {
Button(String(localized: "Accept"), action: acceptAction)
@@ -66,10 +37,42 @@ struct PaymentAcceptView: View {
.navigationTitle(navTitle)
}
}
-
-//struct PaymentAccept_Previews: PreviewProvider {
-// static var previews: some View {
-// let model: PaymentURIModel =
-// PaymentAcceptView(model: <#PaymentURIModel#>, detailsForAmount:
<#PaymentDetailsForUri#>)
-// }
-//}
+// MARK: -
+struct PaymentAccept_Previews: PreviewProvider {
+ static var previews: some View {
+ let merchant = Merchant(name: "Merchant")
+ let extra = Extra(articleName: "articleName")
+ let product = Product(description: "description")
+ let terms = ContractTerms(amount: try! Amount(fromString: LONGCURRENCY
+ ":2.2"),
+ maxFee: try! Amount(fromString: LONGCURRENCY
+ ":0.2"),
+ maxWireFee: try! Amount(fromString:
LONGCURRENCY + ":0.2"),
+ merchant: merchant,
+ extra: extra,
+ summary: "summary",
+ timestamp: Timestamp.now(),
+ payDeadline: Timestamp.tomorrow(),
+ refundDeadline: Timestamp.tomorrow(),
+ wireTransferDeadline: Timestamp.tomorrow(),
+ merchantBaseURL: "merchantBaseURL",
+ fulfillmentURL: "fulfillmentURL",
+ publicReorderURL: "publicReorderURL",
+ auditors: [],
+ exchanges: [],
+ orderID: "orderID",
+ nonce: "nonce",
+ merchantPub: "merchantPub",
+ products: [product],
+ hWire: "hWire",
+ wireMethod: "wireMethod",
+ wireFeeAmortization: 0)
+ let details = PaymentDetailsForUri(
+ amountRaw: try! Amount(fromString: LONGCURRENCY + ":2.2"),
+ amountEffective: try! Amount(fromString: LONGCURRENCY + ":2.4"),
+ noncePriv: "noncePriv",
+ proposalId: "proposalId",
+ contractTerms: terms,
+ contractTermsHash: "termsHash"
+ )
+ PaymentAcceptView(detailsForUri: details, acceptAction: {})
+ }
+}
diff --git a/TalerWallet1/Views/Payment/PaymentURIView.swift
b/TalerWallet1/Views/Payment/PaymentURIView.swift
index 8815be7..22048ca 100644
--- a/TalerWallet1/Views/Payment/PaymentURIView.swift
+++ b/TalerWallet1/Views/Payment/PaymentURIView.swift
@@ -3,41 +3,65 @@
* See LICENSE.md
*/
import SwiftUI
+import AVFoundation
import SymLog
struct PaymentURIView: View {
private let symLog = SymLogV()
var url: URL
- @ObservedObject var model: PaymentURIModel
- @State var detailsForUri: PaymentDetailsForUri?
+ var model: PaymentURIModel?
- let navTitle = String(localized: "Payment")
+ @State var detailsForUri: PaymentDetailsForUri? = nil
+
+ func playSound(success: Bool) {
+// let url = URL(fileURLWithPath:
"/System/Library/Audio/UISounds/PaymentReceived.caf")
+ let url = URL(fileURLWithPath:
"/System/Library/Audio/UISounds/payment_" + (success ? "success.caf"
+
: "failure.caf"))
+ var soundID: SystemSoundID = 0
+ AudioServicesCreateSystemSoundID(url as CFURL, &soundID)
+ print(soundID)
+ AudioServicesPlaySystemSound(soundID);
+ }
+
+ func acceptAction() {
+ Task {
+ do {
+ if let detailsForUri {
+ if let model {
+ let confirmPayResult = try await
model.confirmPayM(detailsForUri.proposalId)
+ symLog.log(confirmPayResult as Any)
+ if confirmPayResult.type == "done" {
+ // TODO: Show Hints that Payment was successfull
+ playSound(success: true)
+ } else {
+ // TODO: show error
+ playSound(success: false)
+ }
+ }
+ }
+ } catch { // TODO: error
+ symLog.log(error.localizedDescription)
+ }
+ dismissTop()
+ }
+ }
var body: some View {
let badURL = "Error in URL: \(url)"
VStack {
- if model.paymentState == nil {
- LoadingView(backButtonHidden: false)
- } else { switch model.paymentState {
- case .waitingForUriDetails:
- let _ = symLog.vlog("waitingForUriDetails")
- WithdrawProgressView(message: url.host ?? badURL)
- .navigationTitle("Contacting Exchange")
- case .receivedUriDetails:
- let _ = symLog.vlog("waitingForUser")
- PaymentAcceptView(model: model, detailsForAmount:
detailsForUri!)
- default:
- Text("Payment")
- .navigationTitle(navTitle)
- } }
+ if let detailsForUri {
+ PaymentAcceptView(detailsForUri: detailsForUri, acceptAction:
acceptAction)
+ .navigationTitle("Payment")
+ } else {
+ WithdrawProgressView(message: url.host ?? badURL)
+ .navigationTitle("Contacting Exchange")
+ }
}.task {
- do { // TODO: cancelled
+ do {
symLog.log(".task")
- detailsForUri = try await
model.preparePayForUriM(url.absoluteString)
-// print(detailsForUri?.status)
-// print(detailsForUri?.amountRaw.description)
-// print(detailsForUri?.amountEffective.description)
-// print(detailsForUri?.proposalId)
+ if let model {
+ detailsForUri = try await
model.preparePayForUriM(url.absoluteString)
+ }
} catch { // TODO: error
symLog.log(error.localizedDescription)
}
diff --git a/TalerWallet1/Views/Peer2peer/ReceivePurpose.swift
b/TalerWallet1/Views/Peer2peer/ReceivePurpose.swift
index 38be62b..cbbafbf 100644
--- a/TalerWallet1/Views/Peer2peer/ReceivePurpose.swift
+++ b/TalerWallet1/Views/Peer2peer/ReceivePurpose.swift
@@ -9,7 +9,7 @@ import SymLog
struct ReceivePurpose: View {
private let symLog = SymLogV()
@FocusState private var isFocused: Bool
- @StateObject var model = Peer2peerModel.model()
+ let model = Peer2peerModel.model()
@State var peerPullCheck: CheckPeerPullCreditResponse?
var scopeInfo: ScopeInfo
@@ -78,7 +78,6 @@ struct ReceivePurpose: View {
NavigationLink(destination: LazyView {
SendNow(amountToSend: amount, purpose: purpose,
expireDays: expireDays, model: model)
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}) {
Text(buttonTitle)
.font(buttonFont)
@@ -92,6 +91,7 @@ struct ReceivePurpose: View {
.padding(.horizontal)
}
.navigationTitle("Invoice another Wallet")
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear {
DebugViewC.shared.setSheetID(VIEW_INVOICE_PURPOSE)
print("❗️ ReceivePurpose onAppear")
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
index 0c37649..abb0726 100644
--- a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -10,7 +10,6 @@ struct RequestPayment: View {
private let symLog = SymLogV()
let navTitle = String(localized: "Request Payment")
- @ObservedObject var model: Peer2peerModel
var scopeInfo: ScopeInfo
@Binding var centsToTransfer: UInt64
@@ -43,7 +42,6 @@ struct RequestPayment: View {
) {
deactivateAction()
}
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}) {
Text("title2")
}
@@ -56,6 +54,7 @@ struct RequestPayment: View {
.frame(maxWidth: .infinity, alignment: .leading)
.navigationTitle(navTitle)
.padding(.horizontal)
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear { // make CurrencyField show the keyboard
DebugViewC.shared.setViewID(VIEW_INVOICE_P2P)
print("❗️Yikes \(navTitle) onAppear")
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift
b/TalerWallet1/Views/Peer2peer/SendAmount.swift
index e95aab9..fc39f8e 100644
--- a/TalerWallet1/Views/Peer2peer/SendAmount.swift
+++ b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -11,48 +11,61 @@ struct SendAmount: View {
let navTitle = String(localized: "Send Coins")
// @ObservedObject private var keyboardResponder = KeyboardResponder()
// @FocusState private var isFocused: Bool
+ let model = Peer2peerModel.model()
+ @State var peerPushCheck: CheckPeerPushDebitResponse?
let amountAvailable: Amount
let buttonFont: Font = .title2
- @State private var centsToTransfer: UInt64 = 0 // TODO: maybe
Decimal?
+ @State private var centsToTransfer: UInt64 = 0
@State private var purpose: String = ""
@State private var expireDays: UInt = 0
- var body: some View {
- let currencyField = CurrencyField(value: $centsToTransfer, currency:
amountAvailable.currencyStr)
+ private func fee(ppCheck: CheckPeerPushDebitResponse?) -> String {
+ do {
+ if let p2pcheck = ppCheck {
+ let fee = try p2pcheck.amountEffective - p2pcheck.amountRaw
+ return fee.readableDescription
+ }
+ } catch {}
+ return ""
+ }
- VStack(alignment: .leading, spacing: 6) {
- CurrencyInputView(currencyField: currencyField, title: "Amount to
send:")
+ var body: some View {
+#if DEBUG
+ let _ = Self._printChanges()
+ let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
+#endif
+ let currency = amountAvailable.currencyStr
+ let currencyField = CurrencyField(value: $centsToTransfer, currency:
currency)
+
+ let fee = fee(ppCheck: peerPushCheck)
+ ScrollView {
let available = amountAvailable.readableDescription
Text("Available: \(available)")
+ .font(.title3)
+ CurrencyInputView(currencyField: currencyField, title: "Amount to
send:")
+ Text("+ \(fee) payment fee")
+ .foregroundColor(.red)
Text("Choose where to send to:")
.padding(.top)
.font(.title3)
HStack {
let kbdShown: Bool = false //
keyboardResponder.keyboardHeight > 0
- let title1 = kbdShown ? "To bank" : "To a bank\naccount"
let title2 = kbdShown ? "To wallet" : "To another\nwallet"
let disabled = centsToTransfer == 0 // TODO: check
amountAvailable
- // Left button: To bank
- NavigationLink(destination: LazyView {
- Text("Bank pressed")
- }) {
- Text(title1)
- }
- .buttonStyle(TalerButtonStyle(type: .bordered))
- .disabled(disabled)
NavigationLink(destination: LazyView {
- SendPurpose(amountAvailable: amountAvailable,
- centsToSend: centsToTransfer,
- purpose: $purpose,
- expireDays: $expireDays,
- deactivateAction: {})
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+ SendPurpose(model: model,
+ amountAvailable: amountAvailable,
+ centsToSend: centsToTransfer,
+ fee: fee,
+ purpose: $purpose,
+ expireDays: $expireDays,
+ deactivateAction: {})
}) {
Text(title2)
}
@@ -63,15 +76,28 @@ struct SendAmount: View {
Spacer()
}
.frame(maxWidth: .infinity, alignment: .leading)
- .navigationTitle(navTitle)
.padding(.horizontal)
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+ .navigationTitle(navTitle)
.onAppear { // make CurrencyField show the keyboard
- DebugViewC.shared.setSheetID(SHEET_PAY_P2P)
+ symLog.log("onAppear")
+ DebugViewC.shared.setViewID(VIEW_SEND_P2P)
print("❗️Yikes SendAmount onAppear")
}
.onDisappear {
print("❗️Yikes SendAmount onDisappear")
}
+ .task(id: centsToTransfer) {
+ let amount = Amount.amountFromCents(currency, centsToTransfer)
+ do {
+ peerPushCheck = try await model.checkPeerPushDebitM(amount)
+ // TODO: set from exchange
+// agePicker.setAges(ages: peerPushCheck?.ageRestrictionOptions)
+ } catch { // TODO: error
+ symLog.log(error.localizedDescription)
+ peerPushCheck = nil
+ }
+ }
}
}
// MARK: -
diff --git a/TalerWallet1/Views/Peer2peer/SendNow.swift
b/TalerWallet1/Views/Peer2peer/SendNow.swift
index 628d791..3ead004 100644
--- a/TalerWallet1/Views/Peer2peer/SendNow.swift
+++ b/TalerWallet1/Views/Peer2peer/SendNow.swift
@@ -14,7 +14,7 @@ struct SendNow: View {
var purpose: String
var expireDays: UInt
- @ObservedObject var model: Peer2peerModel
+ var model: Peer2peerModel?
@State var peerPushResponse: PeerPushResponse?
@State var talerURI: String? = nil
@@ -25,23 +25,7 @@ struct SendNow: View {
LoadingView(backButtonHidden: true)
} else {
VStack() {
- Text("Let the payee scan this QR code to receive:")
- .fixedSize(horizontal: false, vertical: true)
- .padding(.top, 30)
- .font(.title3)
-
- QRGeneratorView(text: talerURI!)
-
- Text("Alternatively, copy and send this URI:")
- .fixedSize(horizontal: false, vertical: true)
- .font(.title3)
- .padding(.vertical)
-
- Text(talerURI!)
- .padding(.bottom)
-
- CopyShare(textToCopy: talerURI!, dismissFirst: true)
- .disabled(false)
+ QRCodeDetailView(talerURI: talerURI!)
Text("The QR code can also be copied and shared from
Transactions later")
.fixedSize(horizontal: false, vertical: true)
@@ -59,17 +43,20 @@ struct SendNow: View {
.navigationBarHidden(true) // no back button, no title
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment:
.leading)
.padding(.horizontal)
+
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}
}
.task {
symLog.log(".task")
do {
// generate talerURI
- let timestamp = Timestamp.inSomeDays(expireDays)
- let terms = PeerContractTerms(amount: amountToSend, summary:
purpose, purse_expiration: timestamp)
- let baseURL = DEMOEXCHANGE // TODO: use correct baseURL
- peerPushResponse = try await
model.initiatePeerPushDebitM(baseURL, terms: terms)
- talerURI = peerPushResponse?.talerUri
+ if let model {
+ let timestamp = Timestamp.inSomeDays(expireDays)
+ let terms = PeerContractTerms(amount: amountToSend,
summary: purpose, purse_expiration: timestamp)
+ let baseURL = DEMOEXCHANGE // TODO: use correct baseURL
+ peerPushResponse = try await
model.initiatePeerPushDebitM(baseURL, terms: terms)
+ talerURI = peerPushResponse?.talerUri
+ }
} catch { // TODO: error
symLog.log(error.localizedDescription)
}
@@ -80,8 +67,12 @@ struct SendNow: View {
//struct SendNow_Previews: PreviewProvider {
// static var previews: some View {
// Group {
-// SendNow()
-// SendNow(talerURI: "taler://pay-push/exchange.demo.taler.net")
+// SendNow(amountToSend: <#T##Amount#>,
+// purpose: <#T##String#>,
+// expireDays: <#T##UInt#>,
+// model: <#T##Peer2peerModel#>,
+// peerPushResponse: <#T##PeerPushResponse?#>,
+// talerURI:
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520")
// }
// }
//}
diff --git a/TalerWallet1/Views/Peer2peer/SendPurpose.swift
b/TalerWallet1/Views/Peer2peer/SendPurpose.swift
index cabeea8..298115e 100644
--- a/TalerWallet1/Views/Peer2peer/SendPurpose.swift
+++ b/TalerWallet1/Views/Peer2peer/SendPurpose.swift
@@ -9,11 +9,11 @@ import SymLog
struct SendPurpose: View {
private let symLog = SymLogV()
@FocusState private var isFocused: Bool
- @StateObject var model = Peer2peerModel.model()
- @State var peerPushCheck: CheckPeerPushDebitResponse?
+ var model: Peer2peerModel?
var amountAvailable: Amount
var centsToSend: UInt64
+ var fee: String
@Binding var purpose: String
@Binding var expireDays: UInt
var deactivateAction: () -> Void
@@ -26,20 +26,9 @@ struct SendPurpose: View {
return formatter.string(for: Decimal(centsToSend) / mag) ?? ""
}
- private func fee(ppCheck: CheckPeerPushDebitResponse?) -> String {
- do {
- if let p2pcheck = ppCheck {
- let fee = try p2pcheck.amountEffective - p2pcheck.amountRaw
- return fee.readableDescription
- }
- } catch {}
- return ""
- }
-
var body: some View {
let amount = Amount.amountFromCents(amountAvailable.currencyStr,
centsToSend)
- let fee = fee(ppCheck: peerPushCheck)
VStack (spacing: 6) {
Text(amount.readableDescription)
Text("+ \(fee) payment fee")
@@ -79,7 +68,6 @@ struct SendPurpose: View {
NavigationLink(destination: LazyView {
SendNow(amountToSend: amount, purpose: purpose,
expireDays: expireDays, model: model)
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}) {
Text(buttonTitle)
.font(buttonFont)
@@ -93,8 +81,9 @@ struct SendPurpose: View {
.padding(.horizontal)
}
.navigationTitle("To another Wallet")
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear {
- DebugViewC.shared.setSheetID(VIEW_SEND_PURPOSE)
+ DebugViewC.shared.setViewID(VIEW_SEND_PURPOSE)
print("❗️ SendPurpose onAppear")
}
.onDisappear {
@@ -104,7 +93,7 @@ struct SendPurpose: View {
.task {
symLog.log(".task")
do {
- peerPushCheck = try await model.checkPeerPushDebitM(amount)
+// peerPushCheck = try await model.checkPeerPushDebitM(amount)
} catch { // TODO: error
symLog.log(error.localizedDescription)
}
@@ -113,14 +102,21 @@ struct SendPurpose: View {
}
// MARK: -
+#if DEBUG
struct SendPurpose_Previews: PreviewProvider {
static var previews: some View {
@State var purpose: String = ""
@State var expireDays: UInt = 0
- let amount = Amount(currency: "TaLeR", integer: 10, fraction: 0)
- SendPurpose(amountAvailable: amount, centsToSend: 5,
- purpose: $purpose, expireDays: $expireDays) {
+ let amount = Amount(currency: LONGCURRENCY, integer: 10, fraction: 0)
+ SendPurpose(model: nil,
+ amountAvailable: amount,
+ centsToSend: 543,
+ fee: "0,43",
+ purpose: $purpose,
+ expireDays: $expireDays
+ ) {
print("deactivateAction")
}
}
}
+#endif
diff --git a/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
b/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
index 3a35398..8f29111 100644
--- a/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
+++ b/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
@@ -9,23 +9,20 @@ struct PendingOpsListView: View {
private let symLog = SymLogV(0)
let navTitle = String(localized: "Pending")
- @ObservedObject var model: PendingModel
+ @State var pendingOperations: [PendingOperation] = []
+ var model: PendingModel
var body: some View {
#if DEBUG
let _ = Self._printChanges()
let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
#endif
- let reloadAction = model.updateM
- Content(symLog: symLog, model: model, reloadAction: reloadAction)
+ let reloadAction = model.getPendingOperationsM
+ Content(symLog: symLog, pendingOperations: $pendingOperations,
reloadAction: reloadAction)
.navigationTitle(navTitle)
.task {
symLog.log(".task")
- do {
- try await reloadAction()
- } catch { // TODO: show error
- symLog.log(error.localizedDescription)
- }
+ pendingOperations = await reloadAction()
}
}
}
@@ -33,16 +30,15 @@ struct PendingOpsListView: View {
extension PendingOpsListView {
struct Content: View {
let symLog: SymLogV?
- @ObservedObject var model: PendingModel
- var reloadAction: () async throws -> ()
-
+ @Binding var pendingOperations: [PendingOperation]
+ var reloadAction: () async -> [PendingOperation]
var body: some View {
#if DEBUG
let _ = Self._printChanges()
let _ = symLog?.vlog() // just to get the # to compare it
with .onAppear & onDisappear
#endif
ScrollViewReader { scrollView in
- List(model.pendingOperations, id: \.self) { pendingOp in
+ List(pendingOperations, id: \.self) { pendingOp in
PendingOpView(pendingOp: pendingOp)
}
.listStyle(SidebarListStyle())
@@ -51,12 +47,8 @@ extension PendingOpsListView {
DebugViewC.shared.setViewID(VIEW_PENDING)
}
.refreshable {
- do {
- symLog?.log("refreshing")
- try await reloadAction()
- } catch { // TODO: error
- symLog?.log(error.localizedDescription)
- }
+ symLog?.log("refreshing")
+ pendingOperations = await reloadAction()
}
}
}
diff --git a/TalerWallet1/Views/Settings/SettingsView.swift
b/TalerWallet1/Views/Settings/SettingsView.swift
index db63b5a..94c88cf 100644
--- a/TalerWallet1/Views/Settings/SettingsView.swift
+++ b/TalerWallet1/Views/Settings/SettingsView.swift
@@ -19,11 +19,11 @@ import SymLog
struct SettingsView: View {
private let symLog = SymLogV()
- let navTitle = String(localized: "Settings")
+ let navTitle: String
@AppStorage("developerMode") var developerMode: Bool = false
@AppStorage("developDelay") var developDelay: Bool = false
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
var hamburgerAction: () -> Void
@@ -50,7 +50,7 @@ struct SettingsView: View {
Spacer()
Picker(selection: $myListStyle) {
ForEach(MyListStyle.allCases, id: \.self) {
- Text($0.displayName).tag($0)
+ Text($0.displayName.capitalized).tag($0)
.font(.title2)
}
} label: {}
@@ -159,8 +159,7 @@ struct SettingsView: View {
}
}
}
- .listStyle(myListStyle.style)
- .anyView
+ .listStyle(myListStyle.style).anyView
}
.navigationTitle(navTitle)
.navigationBarItems(leading: HamburgerButton(action: hamburgerAction))
@@ -190,11 +189,11 @@ extension Bundle {
return "v\(releaseVersionNumber ?? "1.0.0")"
}
}
-
-//struct SettingsView_Previews: PreviewProvider {
-// static var previews: some View {
-// SettingsView {
-//
-// }
-// }
-//}
+// MARK: -
+#if DEBUG
+struct SettingsView_Previews: PreviewProvider {
+ static var previews: some View {
+ SettingsView(navTitle: "Settings") { }
+ }
+}
+#endif
diff --git a/TalerWallet1/Views/Sheets/URLSheet.swift
b/TalerWallet1/Views/Sheets/URLSheet.swift
index 342447b..249c138 100644
--- a/TalerWallet1/Views/Sheets/URLSheet.swift
+++ b/TalerWallet1/Views/Sheets/URLSheet.swift
@@ -15,9 +15,8 @@ struct URLSheet: View {
var body: some View {
Group {
- if urlCommand == UrlCommand.withdraw {
- let model = WithdrawModel.model(baseURL: "global") //
TODO: get baseURL from command
- WithdrawURIView(url: urlToOpen, model: model)
+ if urlCommand == .withdraw {
+ WithdrawURIView(url: urlToOpen)
} else if urlCommand == UrlCommand.pay {
let model = PaymentURIModel.model()
PaymentURIView(url: urlToOpen, model: model)
diff --git a/TalerWallet1/Views/Transactions/TransactionDetailView.swift
b/TalerWallet1/Views/Transactions/TransactionDetailView.swift
index 7de0960..c048cc0 100644
--- a/TalerWallet1/Views/Transactions/TransactionDetailView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionDetailView.swift
@@ -8,7 +8,7 @@ import SymLog
struct TransactionDetailView: View {
private let symLog = SymLogV()
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
var transaction: Transaction
var deleteAction: ((_ transactionId: String) async throws -> Void)?
@@ -58,8 +58,7 @@ print(transition.newTxState.major)
// ResumeButton(common: common, resumeAction: resumeAction)
// } }
}
- .listStyle(myListStyle.style)
- .anyView
+ .listStyle(myListStyle.style).anyView
}
.navigationTitle(navTitle)
.onAppear {
@@ -125,6 +124,7 @@ print(transition.newTxState.major)
}
}
}
+
struct QRCodeDetails: View {
var transaction : Transaction
var body: some View {
diff --git a/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
b/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
index 1721663..eb7479f 100644
--- a/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
@@ -10,7 +10,7 @@ import SymLog
struct TransactionsEmptyView: View {
private let symLog = SymLogV()
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
let currency: String
@@ -22,8 +22,8 @@ struct TransactionsEmptyView: View {
}
.padding(.vertical)
.font(.title2)
- .listStyle(myListStyle.style)
- .anyView
+ .listStyle(myListStyle.style).anyView
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear() {
DebugViewC.shared.setViewID(VIEW_EMPTY) // 10
}
diff --git a/TalerWallet1/Views/Transactions/TransactionsListView.swift
b/TalerWallet1/Views/Transactions/TransactionsListView.swift
index e2e5ad1..0404d62 100644
--- a/TalerWallet1/Views/Transactions/TransactionsListView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionsListView.swift
@@ -7,7 +7,7 @@ import SymLog
struct TransactionsListView: View {
private let symLog = SymLogV()
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
let navTitle: String
let currency: String
@@ -22,11 +22,13 @@ struct TransactionsListView: View {
let _ = symLog.vlog() // just to get the # to compare it with
.onAppear & onDisappear
#endif
let count = transactions.count
+ // TODO: Unlock the power of grammatical agreement
// let title = AttributedString(localized: "^[\(count) Ticket](inflect:
true)")
let title: String = "\(count) \(navTitle)"
Content(symLog: symLog, currency: currency, transactions:
transactions, myListStyle: $myListStyle,
reloadAction: reloadAction, deleteAction: deleteAction,
abortAction: abortAction)
.navigationTitle(title)
+ .navigationBarTitleDisplayMode(.large) // .inline
.onAppear {
DebugViewC.shared.setViewID(VIEW_TRANSACTIONLIST)
}
@@ -94,10 +96,10 @@ extension TransactionsListView {
// .onDelete(perform: removeItems) // delete this row
from the list
}
.refreshable {
+ symLog?.log("refreshing")
await reloadAction()
}
- .listStyle(myListStyle.style)
- .anyView
+ .listStyle(myListStyle.style).anyView
.onAppear {
upAction = { withAnimation { scrollView.scrollTo(0) }}
downAction = { withAnimation {
scrollView.scrollTo(transactions.count - 1) }}
@@ -106,7 +108,6 @@ extension TransactionsListView {
.overlay {
if transactions.isEmpty {
TransactionsEmptyView(currency: currency)
-
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}
}
}
@@ -114,7 +115,6 @@ extension TransactionsListView {
ArrowUpButton(action: upAction)
ArrowDownButton(action: downAction)
})
- .navigationBarTitleDisplayMode(.large) // .inline
}
}
}
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
new file mode 100644
index 0000000..9e9ff1e
--- /dev/null
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
@@ -0,0 +1,61 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+import SwiftUI
+import taler_swift
+import SymLog
+
+struct WithdrawAcceptDone: View {
+ private let symLog = SymLogV()
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
+
+ let confirmTransferUrl: String?
+
+ let navTitle = String(localized: "Confirm with Bank")
+
+ var body: some View {
+ VStack {
+ Text(navTitle)
+ .font(.title)
+ .padding()
+ List {
+ if let confirmTransferUrl {
+ let destination = URL(string: confirmTransferUrl)!
+ // Show Hint that User should Confirm on bank website
+ Text("Waiting for bank confirmation")
+ .listRowSeparator(.hidden)
+
+
+ Link("Confirm with bank", destination: destination)
+ .buttonStyle(TalerButtonStyle(type: .prominent,
narrow: false, aligned: .center))
+ // balances will be updated by TransactionStateTransition
+ }
+ }
+ .listStyle(myListStyle.style).anyView
+
+ }
+ .interactiveDismissDisabled() // can only use "Done" button to
dismiss
+ .navigationBarHidden(true) // no back button, no title
+ .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+
+ .safeAreaInset(edge: .bottom) {
+ Button("Done", action: { dismissTop() })
+ .lineLimit(2)
+ .disabled(false)
+ .buttonStyle(TalerButtonStyle(type: .bordered, narrow: false,
aligned: .center))
+ .padding()
+ }
+ .navigationTitle(navTitle)
+ .onAppear() {
+ DebugViewC.shared.setSheetID(SHEET_WITHDRAW_CONFIRM)
+ }
+ }
+}
+// MARK: -
+struct WithdrawAcceptDone_Previews: PreviewProvider {
+ static var previews: some View {
+ WithdrawAcceptDone(confirmTransferUrl: DEMOBANK)
+ }
+}
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptView.swift
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptView.swift
index 72ce825..630f33d 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptView.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptView.swift
@@ -9,20 +9,27 @@ import SymLog
struct WithdrawAcceptView: View {
private let symLog = SymLogV()
let url: URL
- @ObservedObject var model: WithdrawModel
+ var model: WithdrawModel?
let navTitle = String(localized: "Accept Withdrawal")
let detailsForAmount: ManualWithdrawalDetails
let baseURL: String
+ @State private var buttonSelected: Int? = nil
+ @State private var confirmTransferUrl: String? = nil
+
func acceptAction() -> () {
Task {
do {
- let confirmTransferUrl = try await
model.sendAcceptIntWithdrawalM(baseURL, withdrawURL: url.absoluteString)
- symLog.log(confirmTransferUrl as Any)
- // TODO: Show Hints that User should Confirm on bank website
- // update balances to show pending withdrawal
- await BalancesModel.model(currency: "*").fetchBalancesM()
+ if let model {
+ if let transferUrl = try await
model.sendAcceptIntWithdrawalM(baseURL, withdrawURL: url.absoluteString) {
+ symLog.log(transferUrl)
+ confirmTransferUrl = transferUrl
+ buttonSelected = 1 // trigger NavigationLink
+ } else {
+ // TODO: error sendAcceptIntWithdrawal failed
+ }
+ }
} catch { // TODO: error
symLog.log(error.localizedDescription)
}
@@ -30,43 +37,56 @@ struct WithdrawAcceptView: View {
}
var body: some View {
- Group {
- let currState = model.withdrawState
- switch currState {
- case .receivedAmountDetails, .receivedTOS, .receivedTOSAck:
- let raw = detailsForAmount.amountRaw
- let effective = detailsForAmount.amountEffective
- let fee = try! Amount.diff(raw, effective) // TODO:
different currencies
- let outColor = WalletColors().transactionColor(false)
- let inColor = WalletColors().transactionColor(true)
-
- ThreeAmountsView(topTitle: String(localized: "Chosen
amount to withdraw:"),
- topAmount: raw, fee: fee,
- bottomTitle: String(localized: "Coins to
be withdrawn:"),
- bottomAmount: effective,
- large: false, pending: false, incoming:
true,
- baseURL: baseURL)
- .safeAreaInset(edge: .bottom) {
- Button(String(localized: "Accept"), action:
acceptAction)
- .buttonStyle(TalerButtonStyle(type: .prominent))
- .padding(.horizontal)
- }
- case .waitingForWithdrAck, .receivedWithdrAck:
- // TODO: SHEET_WITHDRAW_CONFIRM
- Text("waiting for bank confirmation")
- .navigationTitle("Confirm with Bank")
- .onAppear() {
-
DebugViewC.shared.setSheetID(SHEET_WITHDRAW_CONFIRM)
- }
+ List {
+ let raw = detailsForAmount.amountRaw
+ let effective = detailsForAmount.amountEffective
+ let fee = try! Amount.diff(raw, effective) // TODO: different
currencies
+ let outColor = WalletColors().transactionColor(false)
+ let inColor = WalletColors().transactionColor(true)
- default:
- let _ = symLog.vlog(currState as Any)
- ErrorView(errortext: "unknown state") // TODO: Error
+ HStack(spacing: 0) {
+ NavigationLink(destination: LazyView {
+ WithdrawAcceptDone(confirmTransferUrl: confirmTransferUrl)
+ }, tag: 1, selection: $buttonSelected
+ ) { EmptyView() }.frame(width: 0).opacity(0).hidden()
+
+ ThreeAmountsView(topTitle: String(localized: "Chosen amount to
withdraw:"),
+ topAmount: raw, fee: fee,
+ bottomTitle: String(localized: "Coins to be
withdrawn:"),
+ bottomAmount: effective,
+ large: false, pending: false, incoming: true,
+ baseURL: baseURL)
}
}
+ .safeAreaInset(edge: .bottom) {
+ Button("Confirm Withdrawal", action: acceptAction)
+ .lineLimit(2)
+ .disabled(false)
+ .buttonStyle(TalerButtonStyle(type: .prominent, narrow: false,
aligned: .center))
+ .padding()
+ }
.navigationTitle(navTitle)
+// .overlay {
+// VStack {
+// ErrorView(errortext: "unknown state") // TODO: Error
+// }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0,
maxHeight: .infinity)
+//
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+// }
.onAppear() {
DebugViewC.shared.setSheetID(SHEET_WITHDRAW_ACCEPT)
}
}
}
+// MARK: -
+struct WithdrawAcceptView_Previews: PreviewProvider {
+ static var previews: some View {
+ let details = ManualWithdrawalDetails(amountRaw: try!
Amount(fromString: LONGCURRENCY + ":2.4"),
+ amountEffective: try!
Amount(fromString: LONGCURRENCY + ":2.2"),
+ paytoUris: [],
+ tosAccepted: true)
+ WithdrawAcceptView(url: URL(string: DEMOSHOP)!,
+ model: nil,
+ detailsForAmount: details,
+ baseURL: DEMOEXCHANGE)
+ }
+}
diff --git
a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawProgressView.swift
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawProgressView.swift
index c872021..3599a9b 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawProgressView.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawProgressView.swift
@@ -8,7 +8,7 @@ struct WithdrawProgressView: View {
let message: String
var body: some View {
- VStack {
+ Form {
Spacer()
ProgressView()
Spacer()
@@ -17,6 +17,7 @@ struct WithdrawProgressView: View {
Spacer()
Spacer()
}
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
}
}
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
index 3d24025..4df29c3 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
@@ -7,12 +7,12 @@ import SymLog
struct WithdrawTOSView: View {
private let symLog = SymLogV()
- @AppStorage("listStyle") var myListStyle = MyListStyle.automatic
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
let navTitle = String(localized: "Terms of Service")
var exchangeBaseUrl: String
- @ObservedObject var model: WithdrawModel
+ var model: WithdrawModel?
@State var exchangeTOS: ExchangeTermsOfService?
let viewID: Int // either VIEW_WITHDRAW_TOS or SHEET_WITHDRAW_TOS
@@ -22,29 +22,29 @@ struct WithdrawTOSView: View {
var body: some View {
VStack {
- switch model.withdrawState {
- case .receivedAmountDetails, .waitingForTOS:
- WithdrawProgressView(message: exchangeBaseUrl.trimURL())
- .navigationTitle("Loading " + navTitle)
- case .receivedTOS, .waitingForTOSAck, .receivedTOSAck:
- Content(symLog: symLog, exchangeTOS: exchangeTOS,
myListStyle: $myListStyle) {
- Task {
- do {
- _ = try await
model.setExchangeTOSAcceptedM(exchangeBaseUrl, etag: exchangeTOS!.currentEtag)
- if acceptAction != nil {
- acceptAction!()
- } else {
-
self.presentationMode.wrappedValue.dismiss()
- }
- } catch { // TODO: Show Error
- symLog.log(error.localizedDescription)
+ Content(symLog: symLog, exchangeTOS: exchangeTOS, myListStyle:
$myListStyle) {
+ Task {
+ do {
+ if let model {
+ _ = try await
model.setExchangeTOSAcceptedM(exchangeBaseUrl, etag: exchangeTOS!.currentEtag)
+ if acceptAction != nil {
+ acceptAction!()
+ } else {
+ self.presentationMode.wrappedValue.dismiss()
}
}
+ } catch { // TODO: Show Error
+ symLog.log(error.localizedDescription)
}
- .navigationBarTitleDisplayMode(.large) // .inline
- .navigationTitle(navTitle)
- default:
- ErrorView(errortext: "unknown state") // TODO: ???
+ }
+ }
+ .navigationBarTitleDisplayMode(.large) // .inline
+ .navigationTitle(navTitle)
+ .overlay {
+ if exchangeTOS == nil {
+ WithdrawProgressView(message: exchangeBaseUrl.trimURL())
+ .navigationTitle("Loading " + navTitle)
+ }
}
}.onAppear() {
if viewID > SHEET_WITHDRAWAL {
@@ -54,8 +54,10 @@ struct WithdrawTOSView: View {
}
}.task {
do {
- let someTOS = try await
model.loadExchangeTermsOfServiceM(exchangeBaseUrl)
- exchangeTOS = someTOS
+ if let model {
+ let someTOS = try await
model.loadExchangeTermsOfServiceM(exchangeBaseUrl)
+ exchangeTOS = someTOS
+ }
} catch { // TODO: error
symLog.log(error.localizedDescription)
}
@@ -77,12 +79,11 @@ extension WithdrawTOSView {
List (components, id: \.self) { term in
Text(term)
}.safeAreaInset(edge: .bottom) {
- Button(String(localized: "Accept"), action: acceptAction)
+ Button(String(localized: "Accept ToS"), action:
acceptAction)
.buttonStyle(TalerButtonStyle(type: .prominent))
.padding(.horizontal)
}
- .listStyle(myListStyle.style)
- .anyView
+ .listStyle(myListStyle.style).anyView
} else {
ErrorView(errortext: String(localized: "unknown ToS")) //
TODO: ???
}
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
index 246daaa..5a51dfb 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -5,68 +5,68 @@
import SwiftUI
import SymLog
+// Will be called either by the user scanning a QR code or tapping the
provided link, both from the bank's website
+// we show the user the withdrawal details - but first the ToS must be accepted
+// after the user confirmed the withdrawal, we remind them to return to the
bank website to confirm there, too
struct WithdrawURIView: View {
private let symLog = SymLogV()
+ // the URL from the bank website
var url: URL
- @ObservedObject var model: WithdrawModel
-// @State var withdrawUriInfo: WithdrawUriInfoResponse?
- @State var exchangeBaseUrl: String?
+ let model = WithdrawModel.model(baseURL: "global") // TODO: get
baseURL from URL
+
+ // the exchange used for this withdrawal.
+ @State var exchangeBaseUrl: String = ""
@State var manualWithdrawalDetails: ManualWithdrawalDetails?
@State var didAcceptTOS: Bool = false
var body: some View {
let badURL = "Error in URL: \(url)"
VStack {
- let currState = model.withdrawState
- if currState == nil {
- LoadingView(backButtonHidden: false)
- } else {
- let _ = symLog.vlog(currState as Any)
- switch currState {
- case .waitingForUriDetails, .receivedUriDetails:
- WithdrawProgressView(message: url.host ?? badURL)
- .navigationTitle("Contacting Exchange")
- case .waitingForAmountDetails:
- WithdrawProgressView(message:
exchangeBaseUrl?.trimURL() ?? badURL)
- .navigationTitle("Found Exchange")
- default:
- // .receivedAmountDetails, .waitingForTOS, .receivedTOS,
.waitingForTOSAck, .receivedTOSAck
- // waitingForWithdrAck, receivedWithdrAck
- if !didAcceptTOS {
- // user must accept ToS first
- WithdrawTOSView(exchangeBaseUrl: exchangeBaseUrl!,
- model: model,
- viewID:
SHEET_WITHDRAW_TOS) {
- didAcceptTOS = true
- }
- } else {
- // show Amount details and let user accept
- WithdrawAcceptView(url: url, model: model,
- detailsForAmount:
manualWithdrawalDetails!,
- baseURL:
exchangeBaseUrl!)
- }
+ if !didAcceptTOS { // user must accept ToS first
+ WithdrawTOSView(exchangeBaseUrl: exchangeBaseUrl,
+ model: model,
+ viewID: SHEET_WITHDRAW_TOS) {
+ didAcceptTOS = true
}
+ } else { // show Amount details and let user accept
+ WithdrawAcceptView(url: url, model: model,
+ detailsForAmount: manualWithdrawalDetails!,
+ baseURL: exchangeBaseUrl)
}
- }.onAppear() {
+ }
+ .overlay {
+ if !exchangeBaseUrl.hasPrefix(HTTPS) {
+ WithdrawProgressView(message: url.host ?? badURL)
+ .navigationTitle("Contacting Exchange")
+ } else if manualWithdrawalDetails == nil {
+ WithdrawProgressView(message: exchangeBaseUrl.trimURL())
+ .navigationTitle("Found Exchange")
+ }
+ }
+ .onAppear() {
DebugViewC.shared.setSheetID(SHEET_WITHDRAWAL)
- }.task {
+ }
+ .task {
do { // TODO: cancelled
symLog.log(".task")
let withdrawUriInfo = try await
model.loadWithdrawalDetailsForUriM(url.absoluteString)
let amount = withdrawUriInfo.amount
if let baseURL = withdrawUriInfo.defaultExchangeBaseUrl {
exchangeBaseUrl = baseURL
- } else {
- exchangeBaseUrl =
withdrawUriInfo.possibleExchanges.first?.exchangeBaseUrl
+ } else if let first = withdrawUriInfo.possibleExchanges.first {
+ exchangeBaseUrl = first.exchangeBaseUrl
}
- symLog.log("amount: \(amount), baseURL: \(String(describing:
exchangeBaseUrl))")
- // TODO: let user choose exchange from list
- manualWithdrawalDetails = try await
model.loadWithdrawalDetailsForAmountM(exchangeBaseUrl!, amount: amount)
-
- symLog.log("raw: \(manualWithdrawalDetails!.amountRaw),
effective: \(manualWithdrawalDetails!.amountEffective)")
- if manualWithdrawalDetails!.tosAccepted {
- didAcceptTOS = true
+ if exchangeBaseUrl.hasPrefix(HTTPS) {
+ symLog.log("amount: \(amount), baseURL:
\(String(describing: exchangeBaseUrl))")
+ // TODO: let user choose exchange from list
+ manualWithdrawalDetails = try await
model.loadWithdrawalDetailsForAmountM(exchangeBaseUrl, amount: amount)
+ symLog.log("raw: \(manualWithdrawalDetails!.amountRaw),
effective: \(manualWithdrawalDetails!.amountEffective)")
+ if manualWithdrawalDetails!.tosAccepted {
+ didAcceptTOS = true
+ }
+ } else {
+ // TODO: error no exchange!
}
} catch { // TODO: error
symLog.log(error.localizedDescription)
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] 19/54: remove dismissFirst, (continued)
- [taler-taler-ios] 19/54: remove dismissFirst, gnunet, 2023/06/30
- [taler-taler-ios] 14/54: Made Model a Singleton, gnunet, 2023/06/30
- [taler-taler-ios] 40/54: TransactionType, gnunet, 2023/06/30
- [taler-taler-ios] 26/54: PeerPullDebit, gnunet, 2023/06/30
- [taler-taler-ios] 16/54: Dummy, gnunet, 2023/06/30
- [taler-taler-ios] 34/54: sizeCategory, task, gnunet, 2023/06/30
- [taler-taler-ios] 06/54: Notifications, gnunet, 2023/06/30
- [taler-taler-ios] 42/54: BalanceRow, gnunet, 2023/06/30
- [taler-taler-ios] 15/54: Suspend-Resume, gnunet, 2023/06/30
- [taler-taler-ios] 21/54: Sounds, P2P receive, gnunet, 2023/06/30
- [taler-taler-ios] 07/54: Big Model update, removed unneccessary thread-safety code,
gnunet <=
- [taler-taler-ios] 41/54: playSound, gnunet, 2023/06/30
- [taler-taler-ios] 30/54: bugfix, gnunet, 2023/06/30
- [taler-taler-ios] 43/54: confirmTransferUrl, gnunet, 2023/06/30
- [taler-taler-ios] 33/54: log only release builds, gnunet, 2023/06/30
- [taler-taler-ios] 27/54: Logging, gnunet, 2023/06/30
- [taler-taler-ios] 38/54: actions, gnunet, 2023/06/30
- [taler-taler-ios] 28/54: playSound, gnunet, 2023/06/30
- [taler-taler-ios] 32/54: Adjust DebugView for Notch, gnunet, 2023/06/30
- [taler-taler-ios] 20/54: viewID + comments, gnunet, 2023/06/30
- [taler-taler-ios] 31/54: bump Testflight version, gnunet, 2023/06/30