gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-ios] 14/54: Made Model a Singleton


From: gnunet
Subject: [taler-taler-ios] 14/54: Made Model a Singleton
Date: Fri, 30 Jun 2023 22:33:46 +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 6d1028c0b4fceeafd3a890850ed4ebc20dde19cf
Author: Marc Stibane <marc@taler.net>
AuthorDate: Wed Jun 21 09:29:57 2023 +0200

    Made Model a Singleton
---
 TalerWallet.xcodeproj/project.pbxproj              | 104 ++++++++++--------
 TalerWallet1/Backend/Transaction.swift             |  21 ++--
 TalerWallet1/Backend/WalletCore.swift              |  17 ++-
 TalerWallet1/Controllers/Controller.swift          |  15 ++-
 TalerWallet1/Controllers/DebugViewC.swift          |   2 +
 TalerWallet1/Controllers/TalerWallet1App.swift     |   4 +-
 .../Helper/{URL+iban.swift => URL+id+iban.swift}   |   0
 ...ew+dismissTop.swift => View+Notification.swift} |  34 +-----
 TalerWallet1/Helper/View+dismissTop.swift          |  57 ----------
 .../{BalancesModel.swift => Model+Balances.swift}  |  75 +++++--------
 .../{ExchangeModel.swift => Model+Exchange.swift}  |  29 ++---
 .../{Peer2peerModel.swift => Model+P2P.swift}      |  90 +++++++++++-----
 .../{PaymentURIModel.swift => Model+Payment.swift} |  28 +----
 .../{PendingModel.swift => Model+Pending.swift}    |  25 +----
 .../{SettingsModel.swift => Model+Settings.swift}  |   8 +-
 ...actionsModel.swift => Model+Transactions.swift} |  27 +----
 .../{WithdrawModel.swift => Model+Withdraw.swift}  |  27 +----
 TalerWallet1/Model/WalletInitModel.swift           |  72 -------------
 TalerWallet1/Model/WalletModel.swift               |  73 ++++++++++++-
 TalerWallet1/Views/Balances/BalancesListView.swift |  20 ++--
 .../Views/Balances/BalancesSectionView.swift       | 119 +++++++++++----------
 TalerWallet1/Views/Exchange/ExchangeListView.swift |  24 ++---
 .../Views/Exchange/ExchangeSectionView.swift       |   2 -
 TalerWallet1/Views/Exchange/ManualWithdraw.swift   |  13 +--
 .../Views/Exchange/ManualWithdrawDone.swift        |  22 ++--
 .../Views/HelperViews/QRCodeDetailView.swift       |  20 ++--
 TalerWallet1/Views/Main/MainView.swift             |   2 -
 TalerWallet1/Views/Payment/PaymentURIView.swift    |  30 +++---
 .../{ReceivePurpose.swift => PaymentPurpose.swift} |  70 +++++-------
 TalerWallet1/Views/Peer2peer/RequestPayment.swift  |  33 +++---
 TalerWallet1/Views/Peer2peer/SendAmount.swift      |  41 ++++---
 TalerWallet1/Views/Peer2peer/SendNow.swift         |  61 ++++++-----
 TalerWallet1/Views/Peer2peer/SendPurpose.swift     |  47 ++++----
 .../Settings/Pending/PendingOpsListView.swift      |   6 +-
 TalerWallet1/Views/Settings/SettingsView.swift     |   7 +-
 .../P2P_Sheets/P2pAcceptDone.swift}                |  24 ++---
 .../Sheets/P2P_Sheets/P2pReceiveURIView.swift      |  80 ++++++++++++++
 TalerWallet1/Views/Sheets/URLSheet.swift           |  18 +++-
 TalerWallet1/Views/Transactions/ThreeAmounts.swift |   3 +-
 .../Views/Transactions/TransactionDetailView.swift |   5 +-
 .../WithdrawAcceptDone.swift                       |  12 +--
 .../WithdrawBankIntegrated/WithdrawTOSView.swift   |  19 ++--
 .../WithdrawBankIntegrated/WithdrawURIView.swift   |   5 +-
 43 files changed, 635 insertions(+), 756 deletions(-)

diff --git a/TalerWallet.xcodeproj/project.pbxproj 
b/TalerWallet.xcodeproj/project.pbxproj
index 4d3cbfe..1000193 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -8,10 +8,15 @@
 
 /* Begin PBXBuildFile section */
                4E16E12329F3BB99008B9C86 /* CurrencyFormatter.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4E16E12229F3BB99008B9C86 /* 
CurrencyFormatter.swift */; };
-               4E363CBC2A237E0900D7E98C /* URL+iban.swift in Sources */ = {isa 
= PBXBuildFile; fileRef = 4E363CBB2A237E0900D7E98C /* URL+iban.swift */; };
+               4E363CBC2A237E0900D7E98C /* URL+id+iban.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E363CBB2A237E0900D7E98C /* URL+id+iban.swift 
*/; };
                4E363CBE2A23CB2100D7E98C /* AnyTransition+backslide.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4E363CBD2A23CB2100D7E98C /* 
AnyTransition+backslide.swift */; };
                4E363CC02A24754200D7E98C /* Settings.bundle in Resources */ = 
{isa = PBXBuildFile; fileRef = 4E363CBF2A24754200D7E98C /* Settings.bundle */; 
};
                4E363CC22A2621C200D7E98C /* LocalizedAlertError.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4E363CC12A2621C200D7E98C /* 
LocalizedAlertError.swift */; };
+               4E3B4BC12A41E6C200CC88B8 /* P2pReceiveURIView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4E3B4BC02A41E6C200CC88B8 /* 
P2pReceiveURIView.swift */; };
+               4E3B4BC32A42252300CC88B8 /* P2pAcceptDone.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E3B4BC22A42252300CC88B8 /* P2pAcceptDone.swift 
*/; };
+               4E3B4BC52A428AF700CC88B8 /* Model+Balances.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4E3B4BC42A428AF700CC88B8 /* 
Model+Balances.swift */; };
+               4E3B4BC72A429F2A00CC88B8 /* View+Notification.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4E3B4BC62A429F2A00CC88B8 /* 
View+Notification.swift */; };
+               4E3B4BC92A42BC4800CC88B8 /* Model+Exchange.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4E3B4BC82A42BC4800CC88B8 /* 
Model+Exchange.swift */; };
                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 
*/; };
@@ -27,7 +32,7 @@
                4E8E25332A1CD39700A27BFA /* EqualIconWidthDomain.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4E8E25322A1CD39700A27BFA /* 
EqualIconWidthDomain.swift */; };
                4E9320432A14F6EA00A87B0E /* WalletColors.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E9320422A14F6EA00A87B0E /* WalletColors.swift 
*/; };
                4E9320452A1645B600A87B0E /* RequestPayment.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4E9320442A1645B600A87B0E /* 
RequestPayment.swift */; };
-               4E9320472A164BC700A87B0E /* ReceivePurpose.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4E9320462A164BC700A87B0E /* 
ReceivePurpose.swift */; };
+               4E9320472A164BC700A87B0E /* PaymentPurpose.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4E9320462A164BC700A87B0E /* 
PaymentPurpose.swift */; };
                4E9796902A3765ED006F73BC /* AgePicker.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E97968F2A3765ED006F73BC /* AgePicker.swift */; 
};
                4EA1ABBE29A3833A008821EA /* PublicConstants.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EA1ABBD29A3833A008821EA /* 
PublicConstants.swift */; };
                4EA551252A2C923600FEC9A8 /* CurrencyInputView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EA551242A2C923600FEC9A8 /* 
CurrencyInputView.swift */; };
@@ -47,33 +52,30 @@
                4EB0950A2989CB7C0043A8A1 /* TalerStrings.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095072989CB7C0043A8A1 /* TalerStrings.swift 
*/; };
                4EB0950B2989CB7C0043A8A1 /* View+dismissTop.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095082989CB7C0043A8A1 /* 
View+dismissTop.swift */; };
                4EB0950E2989CB9A0043A8A1 /* quickjs.swift in Sources */ = {isa 
= PBXBuildFile; fileRef = 4EB0950D2989CB9A0043A8A1 /* quickjs.swift */; };
-               4EB095152989CBB00043A8A1 /* SettingsModel.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095102989CBB00043A8A1 /* SettingsModel.swift 
*/; };
+               4EB095152989CBB00043A8A1 /* Model+Settings.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095102989CBB00043A8A1 /* 
Model+Settings.swift */; };
                4EB095162989CBB00043A8A1 /* WalletModel.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095112989CBB00043A8A1 /* WalletModel.swift 
*/; };
-               4EB095192989CBB00043A8A1 /* WalletInitModel.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095142989CBB00043A8A1 /* 
WalletInitModel.swift */; };
                4EB0951F2989CBCB0043A8A1 /* WalletBackendRequest.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EB0951B2989CBCB0043A8A1 /* 
WalletBackendRequest.swift */; };
                4EB095202989CBCB0043A8A1 /* WalletCore.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0951C2989CBCB0043A8A1 /* WalletCore.swift */; 
};
                4EB095212989CBCB0043A8A1 /* WalletBackendError.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB0951D2989CBCB0043A8A1 /* 
WalletBackendError.swift */; };
                4EB095222989CBCB0043A8A1 /* Transaction.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0951E2989CBCB0043A8A1 /* Transaction.swift 
*/; };
                4EB0954F2989CBFE0043A8A1 /* SettingsView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095252989CBFE0043A8A1 /* SettingsView.swift 
*/; };
                4EB095502989CBFE0043A8A1 /* SettingsItem.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095262989CBFE0043A8A1 /* SettingsItem.swift 
*/; };
-               4EB095512989CBFE0043A8A1 /* ExchangeModel.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095282989CBFE0043A8A1 /* ExchangeModel.swift 
*/; };
                4EB095522989CBFE0043A8A1 /* ExchangeListView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB095292989CBFE0043A8A1 /* 
ExchangeListView.swift */; };
                4EB095532989CBFE0043A8A1 /* PaymentAcceptView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB0952B2989CBFE0043A8A1 /* 
PaymentAcceptView.swift */; };
-               4EB095542989CBFE0043A8A1 /* PaymentURIModel.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB0952C2989CBFE0043A8A1 /* 
PaymentURIModel.swift */; };
+               4EB095542989CBFE0043A8A1 /* Model+Payment.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0952C2989CBFE0043A8A1 /* Model+Payment.swift 
*/; };
                4EB095552989CBFE0043A8A1 /* PaymentURIView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB0952D2989CBFE0043A8A1 /* 
PaymentURIView.swift */; };
                4EB095562989CBFE0043A8A1 /* TransactionsListView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EB0952F2989CBFE0043A8A1 /* 
TransactionsListView.swift */; };
                4EB095572989CBFE0043A8A1 /* TransactionRowView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB095302989CBFE0043A8A1 /* 
TransactionRowView.swift */; };
                4EB095582989CBFE0043A8A1 /* TransactionDetailView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EB095312989CBFE0043A8A1 /* 
TransactionDetailView.swift */; };
-               4EB095592989CBFE0043A8A1 /* TransactionsModel.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB095322989CBFE0043A8A1 /* 
TransactionsModel.swift */; };
+               4EB095592989CBFE0043A8A1 /* Model+Transactions.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB095322989CBFE0043A8A1 /* 
Model+Transactions.swift */; };
                4EB0955A2989CBFE0043A8A1 /* URLSheet.swift in Sources */ = {isa 
= PBXBuildFile; fileRef = 4EB095332989CBFE0043A8A1 /* URLSheet.swift */; };
-               4EB0955B2989CBFE0043A8A1 /* BalancesModel.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095352989CBFE0043A8A1 /* BalancesModel.swift 
*/; };
                4EB0955C2989CBFE0043A8A1 /* BalanceRowView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095362989CBFE0043A8A1 /* 
BalanceRowView.swift */; };
                4EB0955D2989CBFE0043A8A1 /* BalancesListView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB095372989CBFE0043A8A1 /* 
BalancesListView.swift */; };
                4EB0955E2989CBFE0043A8A1 /* PendingRowView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095382989CBFE0043A8A1 /* 
PendingRowView.swift */; };
                4EB0955F2989CBFE0043A8A1 /* WalletEmptyView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095392989CBFE0043A8A1 /* 
WalletEmptyView.swift */; };
                4EB095602989CBFE0043A8A1 /* BalancesSectionView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EB0953A2989CBFE0043A8A1 /* 
BalancesSectionView.swift */; };
                4EB095612989CBFE0043A8A1 /* WithdrawURIView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB0953C2989CBFE0043A8A1 /* 
WithdrawURIView.swift */; };
-               4EB095622989CBFE0043A8A1 /* WithdrawModel.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0953D2989CBFE0043A8A1 /* WithdrawModel.swift 
*/; };
+               4EB095622989CBFE0043A8A1 /* Model+Withdraw.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB0953D2989CBFE0043A8A1 /* 
Model+Withdraw.swift */; };
                4EB095642989CBFE0043A8A1 /* WithdrawProgressView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EB0953F2989CBFE0043A8A1 /* 
WithdrawProgressView.swift */; };
                4EB095652989CBFE0043A8A1 /* WithdrawTOSView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095402989CBFE0043A8A1 /* 
WithdrawTOSView.swift */; };
                4EB095662989CBFE0043A8A1 /* SideBarView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095422989CBFE0043A8A1 /* SideBarView.swift 
*/; };
@@ -84,7 +86,7 @@
                4EB0956B2989CBFE0043A8A1 /* TextFieldAlert.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EB095482989CBFE0043A8A1 /* 
TextFieldAlert.swift */; };
                4EB0956C2989CBFE0043A8A1 /* AmountView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB095492989CBFE0043A8A1 /* AmountView.swift */; 
};
                4EB0956D2989CBFE0043A8A1 /* LoadingView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0954A2989CBFE0043A8A1 /* LoadingView.swift 
*/; };
-               4EB0956E2989CBFE0043A8A1 /* PendingModel.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0954C2989CBFE0043A8A1 /* PendingModel.swift 
*/; };
+               4EB0956E2989CBFE0043A8A1 /* Model+Pending.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0954C2989CBFE0043A8A1 /* Model+Pending.swift 
*/; };
                4EB0956F2989CBFE0043A8A1 /* PendingOpView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EB0954D2989CBFE0043A8A1 /* PendingOpView.swift 
*/; };
                4EB095702989CBFE0043A8A1 /* PendingOpsListView.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EB0954E2989CBFE0043A8A1 /* 
PendingOpsListView.swift */; };
                4EB3136129FEE79B007D68BC /* SendNow.swift in Sources */ = {isa 
= PBXBuildFile; fileRef = 4EB3136029FEE79B007D68BC /* SendNow.swift */; };
@@ -92,7 +94,7 @@
                4EBA82AB2A3EB2CA00E5F39A /* TransactionButton.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4EBA82AA2A3EB2CA00E5F39A /* 
TransactionButton.swift */; };
                4EBA82AD2A3F580500E5F39A /* QuiteSomeCoins.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EBA82AC2A3F580500E5F39A /* 
QuiteSomeCoins.swift */; };
                4EC90C782A1B528B0071DC58 /* ExchangeSectionView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EC90C772A1B528B0071DC58 /* 
ExchangeSectionView.swift */; };
-               4ECB62802A0BA6DF004ABBB7 /* Peer2peerModel.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4ECB627F2A0BA6DF004ABBB7 /* 
Peer2peerModel.swift */; };
+               4ECB62802A0BA6DF004ABBB7 /* Model+P2P.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */; 
};
                4ECB62822A0BB01D004ABBB7 /* SelectDays.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */; 
};
                4ED2F94B2A278F5100453B40 /* ThreeAmounts.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmounts.swift 
*/; };
                4EEC157329F8242800D46A03 /* QRGeneratorView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EEC157229F8242800D46A03 /* 
QRGeneratorView.swift */; };
@@ -135,11 +137,16 @@
 
 /* Begin PBXFileReference section */
                4E16E12229F3BB99008B9C86 /* CurrencyFormatter.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= CurrencyFormatter.swift; sourceTree = "<group>"; };
-               4E363CBB2A237E0900D7E98C /* URL+iban.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "URL+iban.swift"; sourceTree = "<group>"; };
+               4E363CBB2A237E0900D7E98C /* URL+id+iban.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "URL+id+iban.swift"; sourceTree = "<group>"; };
                4E363CBD2A23CB2100D7E98C /* AnyTransition+backslide.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = "AnyTransition+backslide.swift"; sourceTree = 
"<group>"; };
                4E363CBF2A24754200D7E98C /* Settings.bundle */ = {isa = 
PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = 
Settings.bundle; sourceTree = "<group>"; };
                4E363CC12A2621C200D7E98C /* LocalizedAlertError.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = LocalizedAlertError.swift; sourceTree = "<group>"; };
                4E3AE7EF29A7E8F40070BEC4 /* Taler Wallet.entitlements */ = {isa 
= PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Taler 
Wallet.entitlements"; sourceTree = "<group>"; };
+               4E3B4BC02A41E6C200CC88B8 /* P2pReceiveURIView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= P2pReceiveURIView.swift; sourceTree = "<group>"; };
+               4E3B4BC22A42252300CC88B8 /* P2pAcceptDone.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= P2pAcceptDone.swift; sourceTree = "<group>"; };
+               4E3B4BC42A428AF700CC88B8 /* Model+Balances.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+Balances.swift"; sourceTree = "<group>"; };
+               4E3B4BC62A429F2A00CC88B8 /* View+Notification.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "View+Notification.swift"; sourceTree = "<group>"; };
+               4E3B4BC82A42BC4800CC88B8 /* Model+Exchange.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+Exchange.swift"; sourceTree = "<group>"; };
                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>"; };
@@ -156,7 +163,7 @@
                4E8E25322A1CD39700A27BFA /* EqualIconWidthDomain.swift */ = 
{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
EqualIconWidthDomain.swift; sourceTree = "<group>"; };
                4E9320422A14F6EA00A87B0E /* WalletColors.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WalletColors.swift; sourceTree = "<group>"; };
                4E9320442A1645B600A87B0E /* RequestPayment.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= RequestPayment.swift; sourceTree = "<group>"; };
-               4E9320462A164BC700A87B0E /* ReceivePurpose.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ReceivePurpose.swift; sourceTree = "<group>"; };
+               4E9320462A164BC700A87B0E /* PaymentPurpose.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PaymentPurpose.swift; sourceTree = "<group>"; };
                4E97968F2A3765ED006F73BC /* AgePicker.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= AgePicker.swift; sourceTree = "<group>"; };
                4EA1ABBD29A3833A008821EA /* PublicConstants.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
PublicConstants.swift; sourceTree = "<group>"; };
                4EA551242A2C923600FEC9A8 /* CurrencyInputView.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
CurrencyInputView.swift; sourceTree = "<group>"; };
@@ -176,33 +183,30 @@
                4EB095072989CB7C0043A8A1 /* TalerStrings.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= TalerStrings.swift; sourceTree = "<group>"; };
                4EB095082989CB7C0043A8A1 /* View+dismissTop.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "View+dismissTop.swift"; sourceTree = "<group>"; };
                4EB0950D2989CB9A0043A8A1 /* quickjs.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= quickjs.swift; sourceTree = "<group>"; };
-               4EB095102989CBB00043A8A1 /* SettingsModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= SettingsModel.swift; sourceTree = "<group>"; };
+               4EB095102989CBB00043A8A1 /* Model+Settings.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+Settings.swift"; sourceTree = "<group>"; };
                4EB095112989CBB00043A8A1 /* WalletModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WalletModel.swift; sourceTree = "<group>"; };
-               4EB095142989CBB00043A8A1 /* WalletInitModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WalletInitModel.swift; sourceTree = "<group>"; };
                4EB0951B2989CBCB0043A8A1 /* WalletBackendRequest.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = WalletBackendRequest.swift; sourceTree = "<group>"; };
                4EB0951C2989CBCB0043A8A1 /* WalletCore.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WalletCore.swift; sourceTree = "<group>"; };
                4EB0951D2989CBCB0043A8A1 /* WalletBackendError.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = WalletBackendError.swift; sourceTree = "<group>"; };
                4EB0951E2989CBCB0043A8A1 /* Transaction.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= Transaction.swift; sourceTree = "<group>"; };
                4EB095252989CBFE0043A8A1 /* SettingsView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= SettingsView.swift; sourceTree = "<group>"; };
                4EB095262989CBFE0043A8A1 /* SettingsItem.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= SettingsItem.swift; sourceTree = "<group>"; };
-               4EB095282989CBFE0043A8A1 /* ExchangeModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ExchangeModel.swift; sourceTree = "<group>"; };
                4EB095292989CBFE0043A8A1 /* ExchangeListView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ExchangeListView.swift; sourceTree = "<group>"; };
                4EB0952B2989CBFE0043A8A1 /* PaymentAcceptView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PaymentAcceptView.swift; sourceTree = "<group>"; };
-               4EB0952C2989CBFE0043A8A1 /* PaymentURIModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PaymentURIModel.swift; sourceTree = "<group>"; };
+               4EB0952C2989CBFE0043A8A1 /* Model+Payment.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+Payment.swift"; sourceTree = "<group>"; };
                4EB0952D2989CBFE0043A8A1 /* PaymentURIView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PaymentURIView.swift; sourceTree = "<group>"; };
                4EB0952F2989CBFE0043A8A1 /* TransactionsListView.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = TransactionsListView.swift; sourceTree = "<group>"; };
                4EB095302989CBFE0043A8A1 /* TransactionRowView.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = TransactionRowView.swift; sourceTree = "<group>"; };
                4EB095312989CBFE0043A8A1 /* TransactionDetailView.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = TransactionDetailView.swift; sourceTree = "<group>"; };
-               4EB095322989CBFE0043A8A1 /* TransactionsModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= TransactionsModel.swift; sourceTree = "<group>"; };
+               4EB095322989CBFE0043A8A1 /* Model+Transactions.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = "Model+Transactions.swift"; sourceTree = "<group>"; };
                4EB095332989CBFE0043A8A1 /* URLSheet.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= URLSheet.swift; sourceTree = "<group>"; };
-               4EB095352989CBFE0043A8A1 /* BalancesModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= BalancesModel.swift; sourceTree = "<group>"; };
                4EB095362989CBFE0043A8A1 /* BalanceRowView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= BalanceRowView.swift; sourceTree = "<group>"; };
                4EB095372989CBFE0043A8A1 /* BalancesListView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= BalancesListView.swift; sourceTree = "<group>"; };
                4EB095382989CBFE0043A8A1 /* PendingRowView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PendingRowView.swift; sourceTree = "<group>"; };
                4EB095392989CBFE0043A8A1 /* WalletEmptyView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WalletEmptyView.swift; sourceTree = "<group>"; };
                4EB0953A2989CBFE0043A8A1 /* BalancesSectionView.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = BalancesSectionView.swift; sourceTree = "<group>"; };
                4EB0953C2989CBFE0043A8A1 /* WithdrawURIView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WithdrawURIView.swift; sourceTree = "<group>"; };
-               4EB0953D2989CBFE0043A8A1 /* WithdrawModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WithdrawModel.swift; sourceTree = "<group>"; };
+               4EB0953D2989CBFE0043A8A1 /* Model+Withdraw.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+Withdraw.swift"; sourceTree = "<group>"; };
                4EB0953F2989CBFE0043A8A1 /* WithdrawProgressView.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = WithdrawProgressView.swift; sourceTree = "<group>"; };
                4EB095402989CBFE0043A8A1 /* WithdrawTOSView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= WithdrawTOSView.swift; sourceTree = "<group>"; };
                4EB095422989CBFE0043A8A1 /* SideBarView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= SideBarView.swift; sourceTree = "<group>"; };
@@ -213,7 +217,7 @@
                4EB095482989CBFE0043A8A1 /* TextFieldAlert.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= TextFieldAlert.swift; sourceTree = "<group>"; };
                4EB095492989CBFE0043A8A1 /* AmountView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= AmountView.swift; sourceTree = "<group>"; };
                4EB0954A2989CBFE0043A8A1 /* LoadingView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= LoadingView.swift; sourceTree = "<group>"; };
-               4EB0954C2989CBFE0043A8A1 /* PendingModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PendingModel.swift; sourceTree = "<group>"; };
+               4EB0954C2989CBFE0043A8A1 /* Model+Pending.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+Pending.swift"; sourceTree = "<group>"; };
                4EB0954D2989CBFE0043A8A1 /* PendingOpView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= PendingOpView.swift; sourceTree = "<group>"; };
                4EB0954E2989CBFE0043A8A1 /* PendingOpsListView.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = PendingOpsListView.swift; sourceTree = "<group>"; };
                4EB3136029FEE79B007D68BC /* SendNow.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= SendNow.swift; sourceTree = "<group>"; };
@@ -221,7 +225,7 @@
                4EBA82AA2A3EB2CA00E5F39A /* TransactionButton.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= TransactionButton.swift; sourceTree = "<group>"; };
                4EBA82AC2A3F580500E5F39A /* QuiteSomeCoins.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
QuiteSomeCoins.swift; sourceTree = "<group>"; };
                4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = ExchangeSectionView.swift; sourceTree = "<group>"; };
-               4ECB627F2A0BA6DF004ABBB7 /* Peer2peerModel.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= Peer2peerModel.swift; sourceTree = "<group>"; };
+               4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= "Model+P2P.swift"; sourceTree = "<group>"; };
                4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= SelectDays.swift; sourceTree = "<group>"; };
                4ED2F94A2A278F5100453B40 /* ThreeAmounts.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ThreeAmounts.swift; sourceTree = "<group>"; };
                4EEC157229F8242800D46A03 /* QRGeneratorView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= QRGeneratorView.swift; sourceTree = "<group>"; };
@@ -264,6 +268,15 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+               4E3B4BBF2A41E64000CC88B8 /* P2P_Sheets */ = {
+                       isa = PBXGroup;
+                       children = (
+                               4E3B4BC02A41E6C200CC88B8 /* 
P2pReceiveURIView.swift */,
+                               4E3B4BC22A42252300CC88B8 /* P2pAcceptDone.swift 
*/,
+                       );
+                       path = P2P_Sheets;
+                       sourceTree = "<group>";
+               };
                4EB094EE298979840043A8A1 /* TalerWallet1 */ = {
                        isa = PBXGroup;
                        children = (
@@ -319,7 +332,8 @@
                                4EB095062989CB7C0043A8A1 /* TalerDater.swift */,
                                4EB095072989CB7C0043A8A1 /* TalerStrings.swift 
*/,
                                4EB095082989CB7C0043A8A1 /* 
View+dismissTop.swift */,
-                               4E363CBB2A237E0900D7E98C /* URL+iban.swift */,
+                               4E3B4BC62A429F2A00CC88B8 /* 
View+Notification.swift */,
+                               4E363CBB2A237E0900D7E98C /* URL+id+iban.swift 
*/,
                                4E9320422A14F6EA00A87B0E /* WalletColors.swift 
*/,
                                4E8E25322A1CD39700A27BFA /* 
EqualIconWidthDomain.swift */,
                        );
@@ -338,15 +352,14 @@
                        isa = PBXGroup;
                        children = (
                                4EB095112989CBB00043A8A1 /* WalletModel.swift 
*/,
-                               4EB095142989CBB00043A8A1 /* 
WalletInitModel.swift */,
-                               4EB095352989CBFE0043A8A1 /* BalancesModel.swift 
*/,
-                               4EB095282989CBFE0043A8A1 /* ExchangeModel.swift 
*/,
-                               4ECB627F2A0BA6DF004ABBB7 /* 
Peer2peerModel.swift */,
-                               4EB0954C2989CBFE0043A8A1 /* PendingModel.swift 
*/,
-                               4EB0952C2989CBFE0043A8A1 /* 
PaymentURIModel.swift */,
-                               4EB095102989CBB00043A8A1 /* SettingsModel.swift 
*/,
-                               4EB095322989CBFE0043A8A1 /* 
TransactionsModel.swift */,
-                               4EB0953D2989CBFE0043A8A1 /* WithdrawModel.swift 
*/,
+                               4E3B4BC42A428AF700CC88B8 /* 
Model+Balances.swift */,
+                               4E3B4BC82A42BC4800CC88B8 /* 
Model+Exchange.swift */,
+                               4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */,
+                               4EB0954C2989CBFE0043A8A1 /* Model+Pending.swift 
*/,
+                               4EB0952C2989CBFE0043A8A1 /* Model+Payment.swift 
*/,
+                               4EB095102989CBB00043A8A1 /* 
Model+Settings.swift */,
+                               4EB095322989CBFE0043A8A1 /* 
Model+Transactions.swift */,
+                               4EB0953D2989CBFE0043A8A1 /* 
Model+Withdraw.swift */,
                        );
                        path = Model;
                        sourceTree = "<group>";
@@ -493,7 +506,7 @@
                                4E7940DD29FC307C00A9AEA1 /* SendPurpose.swift 
*/,
                                4EB3136029FEE79B007D68BC /* SendNow.swift */,
                                4E9320442A1645B600A87B0E /* 
RequestPayment.swift */,
-                               4E9320462A164BC700A87B0E /* 
ReceivePurpose.swift */,
+                               4E9320462A164BC700A87B0E /* 
PaymentPurpose.swift */,
                        );
                        path = Peer2peer;
                        sourceTree = "<group>";
@@ -505,6 +518,7 @@
                                4EEC157929F9427F00D46A03 /* QRSheet.swift */,
                                4E753A072A0B6A5F002D9328 /* ShareSheet.swift */,
                                4EB095332989CBFE0043A8A1 /* URLSheet.swift */,
+                               4E3B4BBF2A41E64000CC88B8 /* P2P_Sheets */,
                        );
                        path = Sheets;
                        sourceTree = "<group>";
@@ -699,7 +713,6 @@
                        buildActionMask = 2147483647;
                        files = (
                                4ECB62822A0BB01D004ABBB7 /* SelectDays.swift in 
Sources */,
-                               4EB095512989CBFE0043A8A1 /* ExchangeModel.swift 
in Sources */,
                                4E9796902A3765ED006F73BC /* AgePicker.swift in 
Sources */,
                                4EB095032989C9BC0043A8A1 /* Controller.swift in 
Sources */,
                                4EB095682989CBFE0043A8A1 /* MainView.swift in 
Sources */,
@@ -714,15 +727,15 @@
                                4EB095532989CBFE0043A8A1 /* 
PaymentAcceptView.swift in Sources */,
                                4EB095212989CBCB0043A8A1 /* 
WalletBackendError.swift in Sources */,
                                4EB0955E2989CBFE0043A8A1 /* 
PendingRowView.swift in Sources */,
-                               4EB0955B2989CBFE0043A8A1 /* BalancesModel.swift 
in Sources */,
                                4EB0956D2989CBFE0043A8A1 /* LoadingView.swift 
in Sources */,
                                4E50B3502A1BEE8000F9F01C /* 
ManualWithdraw.swift in Sources */,
+                               4E3B4BC92A42BC4800CC88B8 /* 
Model+Exchange.swift in Sources */,
                                4E5A88F52A38A4FD00072618 /* 
QRCodeDetailView.swift in Sources */,
                                4E87C8732A31CB7F001C6406 /* 
TransactionsEmptyView.swift in Sources */,
                                4E87C8752A34B411001C6406 /* 
UncompletedRowView.swift in Sources */,
                                4E40E0BE29F25ABB00B85369 /* SendAmount.swift in 
Sources */,
                                4E8E25332A1CD39700A27BFA /* 
EqualIconWidthDomain.swift in Sources */,
-                               4EB095542989CBFE0043A8A1 /* 
PaymentURIModel.swift in Sources */,
+                               4EB095542989CBFE0043A8A1 /* Model+Payment.swift 
in Sources */,
                                4EB0954F2989CBFE0043A8A1 /* SettingsView.swift 
in Sources */,
                                4EB095552989CBFE0043A8A1 /* 
PaymentURIView.swift in Sources */,
                                4EB095612989CBFE0043A8A1 /* 
WithdrawURIView.swift in Sources */,
@@ -741,24 +754,27 @@
                                4EB0956B2989CBFE0043A8A1 /* 
TextFieldAlert.swift in Sources */,
                                4EBA82AD2A3F580500E5F39A /* 
QuiteSomeCoins.swift in Sources */,
                                4EB431672A1E55C700C5690E /* 
ManualWithdrawDone.swift in Sources */,
-                               4E9320472A164BC700A87B0E /* 
ReceivePurpose.swift in Sources */,
+                               4E9320472A164BC700A87B0E /* 
PaymentPurpose.swift in Sources */,
                                4E753A082A0B6A5F002D9328 /* ShareSheet.swift in 
Sources */,
                                4EB0956C2989CBFE0043A8A1 /* AmountView.swift in 
Sources */,
+                               4E3B4BC32A42252300CC88B8 /* P2pAcceptDone.swift 
in Sources */,
                                4E363CBE2A23CB2100D7E98C /* 
AnyTransition+backslide.swift in Sources */,
-                               4EB095592989CBFE0043A8A1 /* 
TransactionsModel.swift in Sources */,
+                               4EB095592989CBFE0043A8A1 /* 
Model+Transactions.swift in Sources */,
                                4EB0955F2989CBFE0043A8A1 /* 
WalletEmptyView.swift in Sources */,
                                4E16E12329F3BB99008B9C86 /* 
CurrencyFormatter.swift in Sources */,
-                               4EB095192989CBB00043A8A1 /* 
WalletInitModel.swift in Sources */,
                                4EB095092989CB7C0043A8A1 /* TalerDater.swift in 
Sources */,
+                               4E3B4BC52A428AF700CC88B8 /* 
Model+Balances.swift in Sources */,
                                4E363CC22A2621C200D7E98C /* 
LocalizedAlertError.swift in Sources */,
                                4EB0950E2989CB9A0043A8A1 /* quickjs.swift in 
Sources */,
                                4E53A33729F50B7B00830EC2 /* CurrencyField.swift 
in Sources */,
-                               4EB095152989CBB00043A8A1 /* SettingsModel.swift 
in Sources */,
+                               4EB095152989CBB00043A8A1 /* 
Model+Settings.swift in Sources */,
                                4EB095692989CBFE0043A8A1 /* ErrorView.swift in 
Sources */,
-                               4EB0956E2989CBFE0043A8A1 /* PendingModel.swift 
in Sources */,
+                               4E3B4BC72A429F2A00CC88B8 /* 
View+Notification.swift in Sources */,
+                               4EB0956E2989CBFE0043A8A1 /* Model+Pending.swift 
in Sources */,
                                4EB095522989CBFE0043A8A1 /* 
ExchangeListView.swift in Sources */,
                                4EB095642989CBFE0043A8A1 /* 
WithdrawProgressView.swift in Sources */,
                                4EEC157A29F9427F00D46A03 /* QRSheet.swift in 
Sources */,
+                               4E3B4BC12A41E6C200CC88B8 /* 
P2pReceiveURIView.swift in Sources */,
                                4E6EDD872A363D8D0031D520 /* ListStyle.swift in 
Sources */,
                                4EB095582989CBFE0043A8A1 /* 
TransactionDetailView.swift in Sources */,
                                4EB095202989CBCB0043A8A1 /* WalletCore.swift in 
Sources */,
@@ -769,13 +785,13 @@
                                4EB095162989CBB00043A8A1 /* WalletModel.swift 
in Sources */,
                                4EB0955A2989CBFE0043A8A1 /* URLSheet.swift in 
Sources */,
                                4ED2F94B2A278F5100453B40 /* ThreeAmounts.swift 
in Sources */,
-                               4EB095622989CBFE0043A8A1 /* WithdrawModel.swift 
in Sources */,
+                               4EB095622989CBFE0043A8A1 /* 
Model+Withdraw.swift in Sources */,
                                4EC90C782A1B528B0071DC58 /* 
ExchangeSectionView.swift in Sources */,
                                4E7940DE29FC307C00A9AEA1 /* SendPurpose.swift 
in Sources */,
-                               4ECB62802A0BA6DF004ABBB7 /* 
Peer2peerModel.swift in Sources */,
+                               4ECB62802A0BA6DF004ABBB7 /* Model+P2P.swift in 
Sources */,
                                4EB0950A2989CB7C0043A8A1 /* TalerStrings.swift 
in Sources */,
                                4EA551252A2C923600FEC9A8 /* 
CurrencyInputView.swift in Sources */,
-                               4E363CBC2A237E0900D7E98C /* URL+iban.swift in 
Sources */,
+                               4E363CBC2A237E0900D7E98C /* URL+id+iban.swift 
in Sources */,
                                4E9320452A1645B600A87B0E /* 
RequestPayment.swift in Sources */,
                                4EB095502989CBFE0043A8A1 /* SettingsItem.swift 
in Sources */,
                                4EB0955C2989CBFE0043A8A1 /* 
BalanceRowView.swift in Sources */,
diff --git a/TalerWallet1/Backend/Transaction.swift 
b/TalerWallet1/Backend/Transaction.swift
index fc77b17..0ca3188 100644
--- a/TalerWallet1/Backend/Transaction.swift
+++ b/TalerWallet1/Backend/Transaction.swift
@@ -102,8 +102,8 @@ struct TransactionCommon: Decodable {
         case payment
         case refund
         case refresh
-        case reward
-//        case tip
+        case reward         // get paid for e.g. survey participation
+//        case tip            // tip personnel at restaurants
         case peerPushDebit = "peer-push-debit"              // send coins to 
peer, show QR
         case scanPushCredit = "peer-push-credit"            // scan QR, 
receive coins from peer
         case peerPullCredit = "peer-pull-credit"            // request payment 
from peer, show QR
@@ -329,13 +329,13 @@ enum Transaction: Decodable, Hashable, Identifiable {
             case .refund:       return String(localized: "Refund")
             case .refresh:      return String(localized: "Refresh")
             case .reward:       return String(localized: "Reward")
-            case .peerPushDebit:  return String(localized: "P2P Send")
-            case .scanPushCredit: return String(localized: "P2P Receive")
-            case .peerPullCredit: return String(localized: "P2P Invoice")
-            case .scanPullDebit:  return String(localized: "P2P Payment")
+            case .peerPushDebit:  return String(localized: "P2P Send", 
comment: "send coins to another wallet")
+            case .scanPushCredit: return String(localized: "P2P Receive", 
comment: "scan to receive coins sent from another wallet")
+            case .peerPullCredit: return String(localized: "P2P Invoice", 
comment: "send invoice to another wallet")
+            case .scanPullDebit:  return String(localized: "P2P Payment", 
comment: "scan invoice to pay to another wallet")
         }
     }
-    
+
     static func == (lhs: Transaction, rhs: Transaction) -> Bool {
         return lhs.id == rhs.id
     }
@@ -360,13 +360,16 @@ enum Transaction: Decodable, Hashable, Identifiable {
     var isP2pOutgoing: Bool { isSendCoins || isPayInvoice}
     var isP2pIncoming: Bool { isSendInvoice || isRcvCoins}
 
-    var isDone       : Bool { common.txState.major == .done }
     var isPending    : Bool { common.txState.major == .pending }
+    var isDone       : Bool { common.txState.major == .done }
     var isAborting   : Bool { common.txState.major == .aborting }
     var isAborted    : Bool { common.txState.major == .aborted }
+    var isSuspended  : Bool { common.txState.major == .suspended }
+    var isDialog     : Bool { common.txState.major == .dialog }
+    var isAbSuspended: Bool { common.txState.major == .suspendedAborting }
     var isFailed     : Bool { common.txState.major == .failed }
     var isExpired    : Bool { common.txState.major == .expired }
-    var isSpecial    : Bool { isPending || isAborting || isAborted || isFailed 
|| isExpired }
+    var isSpecial    : Bool { !(isDone || isPending) }
 
     var isAbortable  : Bool { common.txActions.contains(.abort) }
     var isFailable   : Bool { common.txActions.contains(.fail) }
diff --git a/TalerWallet1/Backend/WalletCore.swift 
b/TalerWallet1/Backend/WalletCore.swift
index 684aaa7..ba43541 100644
--- a/TalerWallet1/Backend/WalletCore.swift
+++ b/TalerWallet1/Backend/WalletCore.swift
@@ -6,6 +6,7 @@ import SwiftUI              // FOUNDATION has no AppStorage
 import AnyCodable
 import FTalerWalletcore
 import SymLog
+import os
 
 /// Delegate for the wallet backend.
 protocol WalletBackendDelegate {
@@ -22,13 +23,14 @@ class WalletCore: QuickjsMessageHandler {
     private var queue: DispatchQueue
     private var semaphore: DispatchSemaphore
 
-    private var quickjs: Quickjs
+    private let quickjs: Quickjs
     private var requestsMade: UInt          // counter for array of completion 
closures
     private var completions: [UInt : (Date, (UInt, Date, Data?, 
WalletBackendResponseError?) -> Void)] = [:]
     var delegate: WalletBackendDelegate?
 
     var versionInfo: VersionInfo?           // shown in SettingsView
     var developDelay: Bool?                 // if set in SettingsView will 
delay wallet-core after each action
+    let logger = Logger (subsystem: "net.taler.gnu", category: "wallet-core")
 
     private struct FullRequest: Encodable {
         let operation: String
@@ -163,6 +165,9 @@ extension WalletCore {
 //            symLog.log("\(pendingOp): \(id)")
         } else if id.hasPrefix("withdraw:") {
             // TODO: handle withdraw
+//            symLog.log("\(pendingOp): \(id)")
+        } else if id.hasPrefix("peer-pull-credit:") {
+            // TODO: handle peer-pull-credit
 //            symLog.log("\(pendingOp): \(id)")
         } else if id.hasPrefix("peer-push-debit:") {
             // TODO: handle peer-push-debit
@@ -176,8 +181,10 @@ print("\n❗️ \(pendingOp): \(id)\n")        // this is a 
new pendingOp I have
     private func handleStateTransition(_ jsonData: Data) throws {
         do {
             let decoded = try JSONDecoder().decode(TransactionTransition.self, 
from: jsonData)
-            postNotification(.TransactionStateTransition,
-                             userInfo: [TRANSACTIONTRANSITION: decoded])
+            if decoded.newTxState != decoded.oldTxState {
+                postNotification(.TransactionStateTransition,
+                                 userInfo: [TRANSACTIONTRANSITION: decoded])
+            }
         } catch {       // rethrows
             symLog.log(jsonData)       // TODO: .error
             throw WalletBackendError.deserializationError
@@ -315,7 +322,7 @@ extension WalletCore {
             sendRequest(request: reqData) { requestId, timeSent, result, error 
in
                 let timeUsed = Date.now - timeSent
                 let millisecs = timeUsed.milliseconds
-print("Request \(requestId) took \(millisecs) ms")
+                self.logger.log("Request \(requestId) took \(millisecs) ms")
                 var err: Error? = nil
                 if let json = result {
                     do {
@@ -339,7 +346,7 @@ print("Request \(requestId) took \(millisecs) ms")
                         } else {
                             self.symLog.log(json)       // TODO: .error
                         }
-                        err = error     // this will be thrown, otherwise keep 
nil
+                        err = error     // this will be thrown in 
continuation.resume(throwing:), otherwise keep nil
                     }
                 } else {
                     if let error = error {
diff --git a/TalerWallet1/Controllers/Controller.swift 
b/TalerWallet1/Controllers/Controller.swift
index 9e93489..3dc051f 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -14,10 +14,12 @@ enum BackendState {
     case error
 }
 
-enum UrlCommand {
+enum UrlCommand: String {
     case unknown
     case withdraw
     case pay
+    case payPull = "pay-pull"
+    case payPush = "pay-push"
 }
 
 // MARK: -
@@ -33,13 +35,12 @@ class Controller: ObservableObject {
         backendState = .instantiated
     }
 
-    @MainActor func initWalletCoreM()
+    @MainActor func initWalletCoreM(_ model: WalletModel)
       async throws {           // M for MainActor
         if backendState == .instantiated {
             backendState = .initing
             do {
-                let walletInitModel = WalletInitModel()
-                let versionInfo = try await walletInitModel.initWalletT()
+                let versionInfo = try await model.initWalletCoreT()
                 WalletCore.shared.versionInfo = versionInfo
                 backendState = .ready                       // dismiss the 
launch animation
             } catch {       // rethrows
@@ -48,7 +49,7 @@ class Controller: ObservableObject {
                 throw error
             }
         } else {
-            symLog.log("Yikes❗️ wallet-core already initialized")     // TODO: 
.warning
+            symLog.log("Yikes❗️ wallet-core already initialized")     // TODO: 
.fault
         }
     }
 }
@@ -93,6 +94,10 @@ extension Controller {
                 return UrlCommand.withdraw
             case "pay":
                 return UrlCommand.pay
+            case "pay-pull":
+                return UrlCommand.payPull
+            case "pay-push":
+                return UrlCommand.payPush
             default:
                 symLog.log("unknown command taler://\(command)")
         }
diff --git a/TalerWallet1/Controllers/DebugViewC.swift 
b/TalerWallet1/Controllers/DebugViewC.swift
index ec5b3db..ff0fe47 100644
--- a/TalerWallet1/Controllers/DebugViewC.swift
+++ b/TalerWallet1/Controllers/DebugViewC.swift
@@ -84,6 +84,8 @@ public let SHEET_PAY_P2P = SHEET_RCV_REWARD + 10              
      // 160 Pay P
 // MARK: P2P Receive Coins
 // p2p push credit - openURL (Link or scan QR)
 public let SHEET_RCV_P2P = SHEET_PAY_P2P + 10                       // 170 
Receive P2P Coins
+public let SHEET_RCV_P2P_TOS = SHEET_RCV_P2P + 1                    // 171 
Receive P2P TOSView
+public let SHEET_RCV_P2P_ACCEPT = SHEET_RCV_P2P_TOS + 1             // 172 
Receive P2P AcceptView
 
 //public let SHEET_REFUND =
 
diff --git a/TalerWallet1/Controllers/TalerWallet1App.swift 
b/TalerWallet1/Controllers/TalerWallet1App.swift
index da2a626..8bd6783 100644
--- a/TalerWallet1/Controllers/TalerWallet1App.swift
+++ b/TalerWallet1/Controllers/TalerWallet1App.swift
@@ -22,6 +22,7 @@ struct TalerWallet1App: App {
     private let walletCore = WalletCore.shared
     // our main controller
     private let controller = Controller.shared
+    private let model = WalletModel.shared
     private let debugViewC = DebugViewC.shared
 
     func scheduleAppRefresh() {
@@ -36,12 +37,13 @@ struct TalerWallet1App: App {
                 .environmentObject(debugViewC)      // change viewID / sheetID
                 .environmentObject(viewState)       // popToRoot
                 .environmentObject(controller)
+                .environmentObject(model)
                     /// external events are taler:// or payto:// URLs passed 
to this app
                     /// we handle them in .onOpenURL in MainView.swift
                 .handlesExternalEvents(preferring: ["*"], allowing: ["*"])
                 .task {
                     symLog.log("task -> initWalletCore")
-                    try! await controller.initWalletCoreM()      // will (and 
should) crash on failure
+                    try! await controller.initWalletCoreM(model)      // will 
(and should) crash on failure
                     symLog.log("task -> initWalletCore done")
                 }
                 .onReceive(NotificationCenter.default.publisher(for: 
UIApplication.didBecomeActiveNotification, object: nil)) { _ in
diff --git a/TalerWallet1/Helper/URL+iban.swift 
b/TalerWallet1/Helper/URL+id+iban.swift
similarity index 100%
rename from TalerWallet1/Helper/URL+iban.swift
rename to TalerWallet1/Helper/URL+id+iban.swift
diff --git a/TalerWallet1/Helper/View+dismissTop.swift 
b/TalerWallet1/Helper/View+Notification.swift
similarity index 66%
copy from TalerWallet1/Helper/View+dismissTop.swift
copy to TalerWallet1/Helper/View+Notification.swift
index ffd9c31..00760bf 100644
--- a/TalerWallet1/Helper/View+dismissTop.swift
+++ b/TalerWallet1/Helper/View+Notification.swift
@@ -1,5 +1,5 @@
 //  MIT License
-//  Copyright © Nicolai Harbo
+//  Copyright © John Sundell
 //
 //  Permission is hereby granted, free of charge, to any person obtaining a 
copy of this software
 //  and associated documentation files (the "Software"), to deal in the 
Software without restriction,
@@ -18,14 +18,13 @@
 //
 import SwiftUI
 
-// John Sundell
 extension View {
     func onNotification(
         _ notificationName: Notification.Name,
         perform action: @escaping () -> Void
     ) -> some View {
         onReceive(NotificationCenter.default
-                    .publisher(for: notificationName)
+            .publisher(for: notificationName)
         ) { _ in
             action()
         }
@@ -46,8 +45,8 @@ extension View {
         perform action: @escaping () -> Void
     ) -> some View {
         onReceive(NotificationCenter.default
-                    .publisher(for: notificationName)
-                    .receive(on: RunLoop.main)
+            .publisher(for: notificationName)
+            .receive(on: RunLoop.main)
         ) { _ in
             action()
         }
@@ -74,28 +73,3 @@ extension View {
         )
     }
 }
-
-/// This is just a workaround for a SwiftUI bug
-/// A presented sheet (SwiftUI view) doesn't always close when calling 
"dismiss()" provided by @Environment(\.dismiss),
-/// so we are walking the view stack to find the top presentedViewController 
(UIKit) and dismiss it.
-extension View {
-    public func dismissTop(animated: Bool = true) {
-        let windows = UIApplication.shared.connectedScenes.compactMap {
-            ($0 as? UIWindowScene)?.keyWindow       // TODO: iPad might have 
more than 1 window
-        }
-        if var topController = windows.first?.rootViewController {
-            var gotPresented = false
-            while let presentedViewController = 
topController.presentedViewController {
-                topController = presentedViewController
-                gotPresented = true
-            }
-            if gotPresented {
-                topController.dismiss(animated: animated)
-            } else {
-                print("Yikes❗️ Trying to dismiss the rootViewController!")
-            }
-        } else {
-            print("Yikes❗️ There is no window/rootViewController!")
-        }
-    }
-}
diff --git a/TalerWallet1/Helper/View+dismissTop.swift 
b/TalerWallet1/Helper/View+dismissTop.swift
index ffd9c31..40f0084 100644
--- a/TalerWallet1/Helper/View+dismissTop.swift
+++ b/TalerWallet1/Helper/View+dismissTop.swift
@@ -18,63 +18,6 @@
 //
 import SwiftUI
 
-// John Sundell
-extension View {
-    func onNotification(
-        _ notificationName: Notification.Name,
-        perform action: @escaping () -> Void
-    ) -> some View {
-        onReceive(NotificationCenter.default
-                    .publisher(for: notificationName)
-        ) { _ in
-            action()
-        }
-    }
-    func onNotification(
-        _ notificationName: Notification.Name,
-        perform action: @escaping (_ notification: Notification) -> Void
-    ) -> some View {
-        onReceive(NotificationCenter.default
-            .publisher(for: notificationName)
-        ) { notification in
-            action(notification)
-        }
-    }
-
-    func onNotificationM(       // M for main thread
-        _ notificationName: Notification.Name,
-        perform action: @escaping () -> Void
-    ) -> some View {
-        onReceive(NotificationCenter.default
-                    .publisher(for: notificationName)
-                    .receive(on: RunLoop.main)
-        ) { _ in
-            action()
-        }
-    }
-
-    func onNotificationM(       // M for main thread
-        _ notificationName: Notification.Name,
-        perform action: @escaping (_ notification: Notification) -> Void
-    ) -> some View {
-        onReceive(NotificationCenter.default
-            .publisher(for: notificationName)
-            .receive(on: RunLoop.main)
-        ) { notification in
-            action(notification)
-        }
-    }
-
-    func onAppEnteredBackground(
-        perform action: @escaping () -> Void
-    ) -> some View {
-        onNotification(
-            UIApplication.didEnterBackgroundNotification,
-            perform: action
-        )
-    }
-}
-
 /// This is just a workaround for a SwiftUI bug
 /// A presented sheet (SwiftUI view) doesn't always close when calling 
"dismiss()" provided by @Environment(\.dismiss),
 /// so we are walking the view stack to find the top presentedViewController 
(UIKit) and dismiss it.
diff --git a/TalerWallet1/Model/BalancesModel.swift 
b/TalerWallet1/Model/Model+Balances.swift
similarity index 50%
rename from TalerWallet1/Model/BalancesModel.swift
rename to TalerWallet1/Model/Model+Balances.swift
index 0940c4e..7b81539 100644
--- a/TalerWallet1/Model/BalancesModel.swift
+++ b/TalerWallet1/Model/Model+Balances.swift
@@ -6,80 +6,53 @@ import Foundation
 import taler_swift
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
-// MARK: -
-class BalancesModel: WalletModel {
-
-    override init(_ symbol: Int = -1) {     // init with 0 to disable logging 
for this class
-        super.init(0)//symbol)
-    }
-}
-// MARK: -
-/// A request to get the balances held in the wallet.
-fileprivate struct GetBalances: WalletBackendFormattedRequest {
-    func operation() -> String { return "getBalances" }
-    func args() -> Args { return Args() }
-
-    struct Args: Encodable {}                           // no arguments needed
-
-    struct Response: Decodable {                        // list of balances
-        var balances: [Balance]
-    }
-}
 // MARK: -
 /// A currency balance
 struct Balance: Decodable, Hashable {
     var available: Amount
-    var pendingIncoming: Amount
-    var pendingOutgoing: Amount
-    var hasPendingTransactions: Bool
-    var requiresUserInput: Bool
     var scopeInfo: ScopeInfo
+    var requiresUserInput: Bool
+    var hasPendingTransactions: Bool
 
     public static func == (lhs: Balance, rhs: Balance) -> Bool {
         return lhs.available == rhs.available &&
-            lhs.pendingIncoming == rhs.pendingIncoming &&
-            lhs.pendingOutgoing == rhs.pendingOutgoing &&
-            lhs.hasPendingTransactions == rhs.hasPendingTransactions &&
-            lhs.requiresUserInput == rhs.requiresUserInput
+        lhs.scopeInfo == rhs.scopeInfo &&
+        lhs.requiresUserInput == rhs.requiresUserInput &&
+        lhs.hasPendingTransactions == rhs.hasPendingTransactions
     }
 
     public func hash(into hasher: inout Hasher) {
         hasher.combine(available)
-        hasher.combine(pendingIncoming)
-        hasher.combine(pendingOutgoing)
-        hasher.combine(hasPendingTransactions)
+        hasher.combine(scopeInfo)
         hasher.combine(requiresUserInput)
+        hasher.combine(hasPendingTransactions)
     }
 }
 // MARK: -
-extension BalancesModel {
+/// A request to get the balances held in the wallet.
+fileprivate struct Balances: WalletBackendFormattedRequest {
+    func operation() -> String { return "getBalances" }
+    func args() -> Args { return Args() }
+
+    struct Args: Encodable {}                           // no arguments needed
+
+    struct Response: Decodable {                        // list of balances
+        var balances: [Balance]
+    }
+}
+// MARK: -
+extension WalletModel {
     /// fetch Balances from Wallet-Core. No networking involved
-    @MainActor func fetchBalancesM()
+    @MainActor func balancesM()
       async -> [Balance] {          // M for MainActor
         do {
-            let request = GetBalances()
+            let request = Balances()
+            logger.info("balancesM")
             let response = try await sendRequest(request, ASYNCDELAY)
             return response.balances                // trigger view update in 
BalancesListView
         } catch {
+            logger.error("balancesM failed: \(error)")
             return []
         }
     }
 }
-
-// MARK: -
-extension BalancesModel {
-    private static var currencies: [String] = []            // names of 
currencies
-    private static var models: [BalancesModel] = []         // one model per 
currency
-
-    static func model(currency: String) -> BalancesModel {
-        if let index = BalancesModel.currencies.firstIndex(of:currency) {
-            let model = BalancesModel.models[index]
-            return model
-        } else {        // new currency
-            let model = BalancesModel()
-            BalancesModel.models.append(model)
-            BalancesModel.currencies.append(currency)
-            return model
-        }
-    }
-}
diff --git a/TalerWallet1/Model/ExchangeModel.swift 
b/TalerWallet1/Model/Model+Exchange.swift
similarity index 80%
rename from TalerWallet1/Model/ExchangeModel.swift
rename to TalerWallet1/Model/Model+Exchange.swift
index 58bf12a..fac7dae 100644
--- a/TalerWallet1/Model/ExchangeModel.swift
+++ b/TalerWallet1/Model/Model+Exchange.swift
@@ -7,11 +7,6 @@ import taler_swift
 import SymLog
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
-class ExchangeModel: WalletModel {
-    override init(_ symbol: Int = -1) {
-        super.init(0)//symbol)
-    }
-}
 // MARK: -
 /// The result from wallet-core's ListExchanges
 struct Exchange: Codable, Hashable, Identifiable {
@@ -83,39 +78,27 @@ fileprivate struct AddExchange: 
WalletBackendFormattedRequest {
     struct Response: Decodable {}
 }
 // MARK: -
-extension ExchangeModel {
+extension WalletModel {
     /// ask wallet-core for its list of known exchanges
     @MainActor func listExchangesM()
       async -> [Exchange] {         // M for MainActor
         do {
             let request = ListExchanges()
+            logger.info("ListExchanges")
             let response = try await sendRequest(request, ASYNCDELAY)
             return response.exchanges
         } catch {
+            logger.error("listExchangesM failed: \(error)")
             return []               // empty, but not nil
         }
     }
 
     /// add a new exchange with URL to the wallet's list of known exchanges
-    func addExchange(url: String) async throws  {
+    func addExchange(url: String)
+      async throws  {
         symLog?.log("adding exchange: \(url)")       // TODO: .notice
         let request = AddExchange(exchangeBaseUrl: url)
+        logger.info("adding exchange: \(url)")
         _ = try await sendRequest(request)
     }
 }
-
-// MARK: -
-extension ExchangeModel {
-    private static var models: [ExchangeModel] = []     // a list of models 
even though I currently need only one
-
-    static func model() -> ExchangeModel {
-        if ExchangeModel.models.count > 0 {
-            let model = ExchangeModel.models[0]
-            return model
-        } else {        // new model
-            let model = ExchangeModel()
-            ExchangeModel.models.append(model)
-            return model
-        }
-    }
-}
diff --git a/TalerWallet1/Model/Peer2peerModel.swift 
b/TalerWallet1/Model/Model+P2P.swift
similarity index 63%
rename from TalerWallet1/Model/Peer2peerModel.swift
rename to TalerWallet1/Model/Model+P2P.swift
index 9074ec1..4e1760d 100644
--- a/TalerWallet1/Model/Peer2peerModel.swift
+++ b/TalerWallet1/Model/Model+P2P.swift
@@ -8,11 +8,6 @@ import AnyCodable
 //import SymLog
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
-class Peer2peerModel: WalletModel {
-    override init(_ symbol: Int = -1) {     // init with 0 to disable logging 
for this class
-        super.init(0)//symbol)
-    }
-}
 // MARK: - PeerContractTerms
 struct PeerContractTerms: Codable {
     let amount: Amount
@@ -77,7 +72,45 @@ fileprivate struct InitiatePeerPushDebit: 
WalletBackendFormattedRequest {
     typealias Response = PeerPushResponse
     func operation() -> String { return "initiatePeerPushDebit" }
     func args() -> Args { return Args(exchangeBaseUrl: exchangeBaseUrl,
-                                 partialContractTerms: partialContractTerms) }
+                                      partialContractTerms: 
partialContractTerms) }
+
+    var exchangeBaseUrl: String?
+    var partialContractTerms: PeerContractTerms
+    struct Args: Encodable {
+        var exchangeBaseUrl: String?
+        var partialContractTerms: PeerContractTerms
+    }
+}
+
+struct PreparePeerPushCreditResponse: Codable {
+    let contractTerms: PeerContractTerms
+    let amountRaw: Amount
+    let amountEffective: Amount
+    let peerPushPaymentIncomingId: String
+}
+/// A request to receive coins from another wallet.
+fileprivate struct PreparePeerPushCredit: WalletBackendFormattedRequest {
+    typealias Response = PreparePeerPushCreditResponse
+    func operation() -> String { return "preparePeerPushCredit" }
+    func args() -> Args { return Args(talerUri: talerUri) }
+
+    var talerUri: String
+    struct Args: Encodable {
+        var talerUri: String
+    }
+}
+// MARK: -
+/// The result from InitiatePeerPullCredit
+struct PeerPullResponse: Codable {
+    let talerUri: String
+    let transactionId: String
+}
+/// A request to send a payment request to another wallet.
+fileprivate struct InitiatePeerPullCredit: WalletBackendFormattedRequest {
+    typealias Response = PeerPullResponse
+    func operation() -> String { return "initiatePeerPullCredit" }
+    func args() -> Args { return Args(exchangeBaseUrl: exchangeBaseUrl,
+                                      partialContractTerms: 
partialContractTerms) }
 
     var exchangeBaseUrl: String?
     var partialContractTerms: PeerContractTerms
@@ -87,7 +120,7 @@ fileprivate struct InitiatePeerPushDebit: 
WalletBackendFormattedRequest {
     }
 }
 // MARK: -
-extension Peer2peerModel {
+extension WalletModel {
     /// query exchange for fees (sending coins). Networking involved
     @MainActor
     func checkPeerPushDebitM(_ amount: Amount)       // M for MainActor
@@ -96,6 +129,16 @@ extension Peer2peerModel {
           let response = try await sendRequest(request, ASYNCDELAY)
           return response
     }
+    /// generate peer-push. Networking involved
+    @MainActor
+    func initiatePeerPushDebitM(_ baseURL: String?, terms: PeerContractTerms)  
     // M for MainActor
+    async throws -> PeerPushResponse {
+        let request = InitiatePeerPushDebit(exchangeBaseUrl: baseURL,
+                                       partialContractTerms: terms)
+        let response = try await sendRequest(request, ASYNCDELAY)
+        return response
+    }
+
     /// query exchange for fees (invoice coins). Networking involved
     @MainActor
     func checkPeerPullCreditM(_ amount: Amount, exchangeBaseUrl: String?)      
 // M for MainActor
@@ -104,31 +147,22 @@ extension Peer2peerModel {
         let response = try await sendRequest(request, ASYNCDELAY)
         return response
     }
-    /// generate peer-push. Networking involved
+    /// generate peer-pull. Networking involved
     @MainActor
-    func initiatePeerPushDebitM(_ baseURL: String?, terms: PeerContractTerms)  
     // M for MainActor
-      async throws -> PeerPushResponse {
-        let request = InitiatePeerPushDebit(exchangeBaseUrl: baseURL,
-                                       partialContractTerms: terms)
+    func initiatePeerPullCreditM(_ baseURL: String?, terms: PeerContractTerms) 
      // M for MainActor
+      async throws -> PeerPullResponse {
+        let request = InitiatePeerPullCredit(exchangeBaseUrl: baseURL,
+                                        partialContractTerms: terms)
         let response = try await sendRequest(request, ASYNCDELAY)
         return response
     }
-}
 
-// MARK: -
-extension Peer2peerModel {
-    private static var exchanges: [String] = []         // names of exchanges
-    private static var models: [Peer2peerModel] = []    // one model per 
exchange
-
-    static func model(baseURL: String) -> Peer2peerModel {
-        if let index = Peer2peerModel.exchanges.firstIndex(of:baseURL) {
-            let model = Peer2peerModel.models[index]
-            return model
-        } else {        // new model
-            let model = Peer2peerModel()
-            Peer2peerModel.models.append(model)
-            Peer2peerModel.exchanges.append(baseURL)
-            return model
-        }
+    /// prepare peer-pull. Networking involved
+    @MainActor
+    func preparePeerPushCreditM(_ talerUri: String)       // M for MainActor
+    async throws -> PreparePeerPushCreditResponse {
+        let request = PreparePeerPushCredit(talerUri: talerUri)
+        let response = try await sendRequest(request, ASYNCDELAY)
+        return response
     }
 }
diff --git a/TalerWallet1/Model/PaymentURIModel.swift 
b/TalerWallet1/Model/Model+Payment.swift
similarity index 85%
rename from TalerWallet1/Model/PaymentURIModel.swift
rename to TalerWallet1/Model/Model+Payment.swift
index 8f758d6..940b126 100644
--- a/TalerWallet1/Model/PaymentURIModel.swift
+++ b/TalerWallet1/Model/Model+Payment.swift
@@ -8,12 +8,6 @@ import AnyCodable
 //import SymLog
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
-class PaymentURIModel: WalletModel {
-
-    override init(_ symbol: Int = -1) {     // init with 0 to disable logging 
for this class
-        super.init(0)//symbol)
-    }
-}
 // MARK: - ContractTerms
 struct ContractTerms: Codable {
     let amount: Amount
@@ -59,7 +53,6 @@ struct ContractTerms: Codable {
         case wireFeeAmortization = "wire_fee_amortization"
     }
 }
-
 // MARK: - Auditor
 struct Auditor: Codable {
     let name: String
@@ -72,7 +65,6 @@ struct Auditor: Codable {
         case url
     }
 }
-
 // MARK: - Exchange
 struct ExchangeForPay: Codable {
     let url: String
@@ -83,7 +75,6 @@ struct ExchangeForPay: Codable {
         case masterPub = "master_pub"
     }
 }
-
 // MARK: - Extra
 struct Extra: Codable {
     let articleName: String
@@ -92,7 +83,6 @@ struct Extra: Codable {
         case articleName = "article_name"
     }
 }
-
 // MARK: -
 /// The result from PreparePayForUri
 struct PaymentDetailsForUri: Codable {
@@ -134,7 +124,7 @@ fileprivate struct confirmPayForUri: 
WalletBackendFormattedRequest {
     }
 }
 // MARK: -
-extension PaymentURIModel {
+extension WalletModel {
     /// load payment details. Networking involved
     @MainActor
     func preparePayForUriM(_ talerPayUri: String)       // M for MainActor
@@ -151,19 +141,3 @@ extension PaymentURIModel {
           return response
     }
 }
-
-// MARK: -
-extension PaymentURIModel {
-    private static var models: [PaymentURIModel] = []     // a list of models 
even though I currently need only one
-
-    static func model() -> PaymentURIModel {
-        if PaymentURIModel.models.count > 0 {
-            let model = PaymentURIModel.models[0]
-            return model
-        } else {        // new model
-            let model = PaymentURIModel()
-            PaymentURIModel.models.append(model)
-            return model
-        }
-    }
-}
diff --git a/TalerWallet1/Model/PendingModel.swift 
b/TalerWallet1/Model/Model+Pending.swift
similarity index 70%
rename from TalerWallet1/Model/PendingModel.swift
rename to TalerWallet1/Model/Model+Pending.swift
index 9021301..eb9f447 100644
--- a/TalerWallet1/Model/PendingModel.swift
+++ b/TalerWallet1/Model/Model+Pending.swift
@@ -8,12 +8,6 @@ import taler_swift
 import SymLog
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
-class PendingModel: WalletModel {
-
-    override init(_ symbol: Int = -1) {
-        super.init(0)//symbol)
-    }
-}
 // MARK: -
 /// A request to list the backend's currently pending operations.
 fileprivate struct GetPendingOperations: WalletBackendFormattedRequest {
@@ -45,10 +39,9 @@ struct PendingOperation: Codable, Hashable {
         hasher.combine(isDue)
         hasher.combine(timestampDue)
     }
-
 }
 // MARK: -
-extension PendingModel {
+extension WalletModel {
     @MainActor func getPendingOperationsM()
       async -> [PendingOperation] {   // M for MainActor
         do {
@@ -60,19 +53,3 @@ extension PendingModel {
         }
     }
 }
-
-// MARK: -
-extension PendingModel {
-    private static var models: [PendingModel] = []     // a list of models 
even though I currently need only one
-
-    static func model() -> PendingModel {
-        if PendingModel.models.count > 0 {
-            let model = PendingModel.models[0]
-            return model
-        } else {        // new model
-            let model = PendingModel()
-            PendingModel.models.append(model)
-            return model
-        }
-    }
-}
diff --git a/TalerWallet1/Model/SettingsModel.swift 
b/TalerWallet1/Model/Model+Settings.swift
similarity index 95%
rename from TalerWallet1/Model/SettingsModel.swift
rename to TalerWallet1/Model/Model+Settings.swift
index 0ca0d8a..188d4a0 100644
--- a/TalerWallet1/Model/SettingsModel.swift
+++ b/TalerWallet1/Model/Model+Settings.swift
@@ -14,13 +14,7 @@ fileprivate let DEMO_MERCHANTBASEURL = DEMOBACKEND
 fileprivate let DEMO_MERCHANTAUTHTOKEN = "secret-token:sandbox"
 
 // MARK: -
-class SettingsModel: WalletModel {
-    override init(_ symbol: Int = -1) {     // init with 0 to disable logging 
for this class
-        super.init(0)//symbol)
-    }
-}
-// MARK: -
-extension SettingsModel {
+extension WalletModel {
     @MainActor func loadTestKudosM()
       async throws {          // M for MainActor
         let amount = Amount(currency: DEMOCURRENCY, integer: 11, fraction: 0)
diff --git a/TalerWallet1/Model/TransactionsModel.swift 
b/TalerWallet1/Model/Model+Transactions.swift
similarity index 84%
rename from TalerWallet1/Model/TransactionsModel.swift
rename to TalerWallet1/Model/Model+Transactions.swift
index 0f4917a..4c4fd92 100644
--- a/TalerWallet1/Model/TransactionsModel.swift
+++ b/TalerWallet1/Model/Model+Transactions.swift
@@ -8,8 +8,7 @@ import SymLog
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
 // MARK: -
-class TransactionsModel: WalletModel {
-
+extension WalletModel {
     static func specialTransactions(_ transactions: [Transaction]) -> 
[Transaction] {
         transactions.filter { transaction in
             transaction.isSpecial
@@ -31,10 +30,6 @@ class TransactionsModel: WalletModel {
             !transaction.isDone && !transaction.isPending
         }
     }
-
-    override init(_ symbol: Int = -1) {
-        super.init(0)//symbol)
-    }
 }
 
 // MARK: -
@@ -83,7 +78,7 @@ struct DeleteTransaction: WalletBackendFormattedRequest {
 }
 
 // MARK: -
-extension TransactionsModel {
+extension WalletModel {
     /// ask wallet-core for its list of transactions filtered by searchString
     func fetchTransactionsT(currency: String? = nil, searchString: String? = 
nil)
       async -> [Transaction] {                                          // 
might be called from a background thread itself
@@ -123,21 +118,3 @@ extension TransactionsModel {
         try await deleteTransactionT(transactionId: transactionId)      // 
call deleteTransaction on main thread
     }
 }
-
-// MARK: -
-extension TransactionsModel {
-    private static var currencies: [String] = []            // names of 
currencies
-    private static var models: [TransactionsModel] = []     // one model per 
currency
-
-    static func model(currency: String) -> TransactionsModel {
-        if let index = TransactionsModel.currencies.firstIndex(of:currency) {
-            let model = TransactionsModel.models[index]
-            return model
-        } else {        // new currency
-            let model = TransactionsModel()
-            TransactionsModel.models.append(model)
-            TransactionsModel.currencies.append(currency)
-            return model
-        }
-    }
-}
diff --git a/TalerWallet1/Model/WithdrawModel.swift 
b/TalerWallet1/Model/Model+Withdraw.swift
similarity index 90%
rename from TalerWallet1/Model/WithdrawModel.swift
rename to TalerWallet1/Model/Model+Withdraw.swift
index 6198915..a420b58 100644
--- a/TalerWallet1/Model/WithdrawModel.swift
+++ b/TalerWallet1/Model/Model+Withdraw.swift
@@ -7,13 +7,6 @@ import taler_swift
 import SymLog
 fileprivate let ASYNCDELAY: UInt = 0   //set e.g to 6 or 9 seconds for 
debugging
 
-class WithdrawModel: WalletModel {
-
-    override init(_ symbol: Int = -1) {     // init with 0 to disable logging 
for this class
-        super.init(0)//symbol)
-    }
-}
-
 // MARK: -
 /// The result from getWithdrawalDetailsForUri
 struct WithdrawUriInfoResponse: Decodable {
@@ -147,7 +140,7 @@ fileprivate struct AcceptManualWithdrawal: 
WalletBackendFormattedRequest {
     }
 }
 // MARK: -
-extension WithdrawModel {
+extension WalletModel {
     /// load withdrawal details. Networking involved
     @MainActor
     func loadWithdrawalDetailsForUriM(_ talerWithdrawUri: String)              
 // M for MainActor
@@ -193,21 +186,3 @@ extension WithdrawModel {
         return response
     }
 }
-
-// MARK: -
-extension WithdrawModel {
-    private static var exchanges: [String] = []         // names of exchanges
-    private static var models: [WithdrawModel] = []     // one model per 
exchange
-
-    static func model(baseURL: String) -> WithdrawModel {
-        if let index = WithdrawModel.exchanges.firstIndex(of:baseURL) {
-            let model = WithdrawModel.models[index]
-            return model
-        } else {        // new model
-            let model = WithdrawModel()
-            WithdrawModel.models.append(model)
-            WithdrawModel.exchanges.append(baseURL)
-            return model
-        }
-    }
-}
diff --git a/TalerWallet1/Model/WalletInitModel.swift 
b/TalerWallet1/Model/WalletInitModel.swift
deleted file mode 100644
index 28393bd..0000000
--- a/TalerWallet1/Model/WalletInitModel.swift
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
- * See LICENSE.md
- */
-import Foundation
-import SymLog
-
-private let DATABASE = "talerwalletdb-v30"
-
-class WalletInitModel: WalletModel {
-    override init(_ symbol: Int = -1) {     // init with 0 to disable logging 
for this class
-        super.init(0)//symbol)
-    }
-}
-// MARK: -
-///  A request to initialize Wallet-core
-fileprivate struct WalletBackendInitRequest: WalletBackendFormattedRequest {
-    func operation() -> String { return "init" }
-    func args() -> Args {
-        return Args(persistentStoragePath: persistentStoragePath,
-//                    cryptoWorkerType: "sync",
-                    logLevel: "info")       //  "trace", "info", "warn", 
"error", "none"
-    }
-
-    struct Args: Encodable {
-        var persistentStoragePath: String
-//        var cryptoWorkerType: String
-        var logLevel: String
-    }
-
-    var persistentStoragePath: String
-
-    struct Response: Decodable {
-        var versionInfo: VersionInfo
-    }
-}
-// MARK: -
-/// The info returned from Wallet-core init
-struct VersionInfo: Decodable {
-    var hash: String
-    var version: String
-    var exchange: String
-    var merchant: String
-    var bank: String
-    var devMode: Bool
-}
-// MARK: -
-extension WalletInitModel {
-    /// initalize Wallet-Core. Will do networking
-    func initWalletT()              // T for any Thread
-      async throws -> VersionInfo? {
-          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 {
-        let documentUrls = FileManager.default.urls(for: .documentDirectory, 
in: .userDomainMask)
-        if (documentUrls.count > 0) {
-            var storageDir = documentUrls[0]
-            storageDir.appendPathComponent(DATABASE, isDirectory: false)
-            storageDir.appendPathExtension("json")
-            return storageDir.path
-        } else {    // should never happen
-            symLog?.log("Yikes❗️ documentURLs empty")     // TODO: symLog.error
-            throw WalletBackendError.initializationError
-        }
-    }
-}
-
diff --git a/TalerWallet1/Model/WalletModel.swift 
b/TalerWallet1/Model/WalletModel.swift
index 34626ca..6a912d6 100644
--- a/TalerWallet1/Model/WalletModel.swift
+++ b/TalerWallet1/Model/WalletModel.swift
@@ -4,25 +4,29 @@
  */
 import Foundation
 import SymLog
+import os
 
+fileprivate let DATABASE = "talerwalletdb-v30"
 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 {
+class WalletModel: ObservableObject {
+    public static let shared = WalletModel(-1)
     static func className() -> String {"\(self)"}
     var symLog: SymLogC?
+    let logger = Logger (subsystem: "net.taler.gnu", category: "wallet-core")
 
     init(_ symbol: Int) {                               // init with 0 to 
disable logging for this class
         self.symLog = SymLogC(symbol == 0 ? 0 : -1, funcName: Self.className())
     }
 
     func sendRequest<T: WalletBackendFormattedRequest> (_ request: T, _ delay: 
UInt = 0)
-    async throws -> T.Response {    // T for any Thread
+      async throws -> T.Response {    // T for any Thread
+        symLog?.log("sending: \(request)")
         let sendTime = Date.now
         do {
-            symLog?.log("sending: \(request)")
             let (response, id) = try await 
WalletCore.shared.sendFormattedRequest(request: request)
             let timeUsed = Date.now - sendTime
             let asyncDelay: UInt = delay > 0 ? delay : UInt(ASYNCDELAY)
@@ -66,4 +70,67 @@ fileprivate struct GetTransactionById: 
WalletBackendFormattedRequest {
         var transactionId: String
     }
 }
+// MARK: -
+/// The info returned from Wallet-core init
+struct VersionInfo: Decodable {
+    var hash: String
+    var version: String
+    var exchange: String
+    var merchant: String
+    var bank: String
+    var devMode: Bool
+}
+// MARK: -
+///  A request to initialize Wallet-core
+fileprivate struct InitRequest: WalletBackendFormattedRequest {
+    func operation() -> String { return "init" }
+    func args() -> Args {
+        return Args(persistentStoragePath: persistentStoragePath,
+//                       cryptoWorkerType: "sync",
+                                 logLevel: "info") // trace, info, warn, 
error, none
+    }
+
+    struct Args: Encodable {
+        var persistentStoragePath: String
+//        var cryptoWorkerType: String
+        var logLevel: String
+    }
+
+    var persistentStoragePath: String
+
+    struct Response: Decodable {
+        var versionInfo: VersionInfo
+    }
+}
+// MARK: -
+extension WalletModel {
+    /// initalize Wallet-Core. Will do networking
+    func initWalletCoreT() async throws -> VersionInfo {
+        do {        // T for any Thread
+            let docPath = try docPath()
+            let request = InitRequest(persistentStoragePath: docPath)
+            logger.info("initWalletCoreT")
+            let response = try await sendRequest(request, 0)    // no Delay
+            return response.versionInfo
+        } catch {
+            logger.error("initWalletCoreT failed: \(error)")
+            throw error
+        }
+    }
 
+    private func docPath () throws -> String {
+        let documentUrls = FileManager.default.urls(for: .documentDirectory, 
in: .userDomainMask)
+        if (documentUrls.count > 0) {
+            var storageDir = documentUrls[0]
+            storageDir.appendPathComponent(DATABASE, isDirectory: false)
+            storageDir.appendPathExtension("json")
+            let docPath = storageDir.path
+            logger.debug("\(docPath)")
+            return docPath
+        } else {    // should never happen
+            symLog?.log("Yikes❗️ documentURLs empty")
+            logger.error("documentURLs empty")
+            throw WalletBackendError.initializationError
+        }
+    }
+}
diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift 
b/TalerWallet1/Views/Balances/BalancesListView.swift
index 43398ce..09a0119 100644
--- a/TalerWallet1/Views/Balances/BalancesListView.swift
+++ b/TalerWallet1/Views/Balances/BalancesListView.swift
@@ -12,13 +12,13 @@ import AVFoundation
 struct BalancesListView: View {
     private let symLog = SymLogV(0)
     let navTitle: String
+    let hamburgerAction: () -> Void
 
     @State var balances: [Balance] = []
-    let model: BalancesModel?
-    let hamburgerAction: () -> Void
+    @EnvironmentObject private var model: WalletModel
 
     @State private var centsToTransfer: UInt64 = 0
-    @State private var purpose: String = ""
+    @State private var summary: String = ""
     @State private var showQRScanner: Bool = false
     @State private var showCameraAlert: Bool = false
 
@@ -62,11 +62,7 @@ struct BalancesListView: View {
     }
 
     private func reloadAction() async {
-        if let model {
-            balances = await model.fetchBalancesM()
-        } else {
-            balances = []
-        }
+        balances = await model.balancesM()
     }
 
     var body: some View {
@@ -75,7 +71,7 @@ struct BalancesListView: View {
         let _ = symLog.vlog()       // just to get the # to compare it with 
.onAppear & onDisappear
 #endif
         Content(symLog: symLog, balances: $balances,
-                centsToTransfer: $centsToTransfer, purpose: $purpose,
+                centsToTransfer: $centsToTransfer, summary: $summary,
                 reloadAction: reloadAction)
             .navigationTitle(navTitle)
             .navigationBarTitleDisplayMode(.automatic)
@@ -111,7 +107,7 @@ extension BalancesListView {
         @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
         @Binding var balances: [Balance]
         @Binding var centsToTransfer: UInt64
-        @Binding var purpose: String
+        @Binding var summary: String
         var reloadAction: () async -> Void
 
         var body: some View {
@@ -121,11 +117,9 @@ extension BalancesListView {
 #endif
             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,
-                                        purpose: $purpose,
-                                          model: model)
+                                        summary: $summary)
                 }
                 .refreshable {
                     symLog?.log("refreshing")
diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift 
b/TalerWallet1/Views/Balances/BalancesSectionView.swift
index 813e614..fef89da 100644
--- a/TalerWallet1/Views/Balances/BalancesSectionView.swift
+++ b/TalerWallet1/Views/Balances/BalancesSectionView.swift
@@ -18,8 +18,9 @@ struct BalancesSectionView: View {
     private let symLog = SymLogV()
     var balance:Balance
     @Binding var centsToTransfer: UInt64
-    @Binding var purpose: String
-    var model: TransactionsModel?
+    @Binding var summary: String
+
+    @EnvironmentObject private var model: WalletModel
 
     @State private var isShowingDetailView = false
     @State private var buttonSelected: Int? = nil
@@ -29,15 +30,33 @@ struct BalancesSectionView: View {
     @State private var pendingTransactions: [Transaction] = []
     @State private var uncompletedTransactions: [Transaction] = []
 
-    func dummyTransaction (_ transactionId: String) async throws {}
+//    func dummyTransaction (_ transactionId: String) async throws {}
     func reloadOneAction(_ transactionId: String) async throws -> Transaction {
-        if let model {
-            return try await model.getTransactionByIdT(transactionId)
-        } else {
-            throw WalletBackendError.walletCoreError
+        return try await model.getTransactionByIdT(transactionId)
+    }
+
+    func computePending(currency: String) -> (Amount, Amount) {
+        var incoming = Amount(currency: currency, value: 0)
+        var outgoing = Amount(currency: currency, value: 0)
+        for transaction in pendingTransactions {
+            let effective = transaction.common.amountEffective
+            if currency == effective.currencyStr {
+                do {
+                    if transaction.common.incoming() {
+                        incoming = try incoming + effective
+                    } else {
+                        outgoing = try outgoing + effective
+                    }
+                } catch {
+                    // TODO: log error
+                    symLog.log(error.localizedDescription)
+                }
+            }
         }
+        return (incoming, outgoing)
     }
 
+
     var body: some View {
 #if DEBUG
         let _ = Self._printChanges()
@@ -45,27 +64,19 @@ struct BalancesSectionView: View {
 #endif
         let currency = balance.available.currencyStr
         let reloadCompleted = {
-            if let model {
-                transactions = await model.fetchTransactionsT(currency: 
currency)
-                completedTransactions = 
TransactionsModel.completedTransactions(transactions)
-            }
+            transactions = await model.fetchTransactionsT(currency: currency)
+            completedTransactions = 
WalletModel.completedTransactions(transactions)
         }
         let reloadPending = {
-            if let model {
-                transactions = await model.fetchTransactionsT(currency: 
currency)
-                pendingTransactions = 
TransactionsModel.pendingTransactions(transactions)
-            }
+            transactions = await model.fetchTransactionsT(currency: currency)
+            pendingTransactions = WalletModel.pendingTransactions(transactions)
         }
         let reloadUncompleted = {
-            if let model {
-                transactions = await model.fetchTransactionsT(currency: 
currency)
-                uncompletedTransactions = 
TransactionsModel.uncompletedTransactions(transactions)
-            }
+            transactions = await model.fetchTransactionsT(currency: currency)
+            uncompletedTransactions = 
WalletModel.uncompletedTransactions(transactions)
         }
-        let deleteAction = model?.deleteTransactionT ?? dummyTransaction
-        let abortAction = model?.abortTransactionT ?? dummyTransaction
-
-        let p2pModel = Peer2peerModel.model(baseURL: currency)
+        let deleteAction = model.deleteTransactionT // dummyTransaction
+        let abortAction = model.abortTransactionT
 
         Section {
 //            if "KUDOS" == currency && !balance.available.isZero {
@@ -74,18 +85,16 @@ struct BalancesSectionView: View {
 //            }
             HStack(spacing: 0) {
                 NavigationLink(destination: LazyView {
-                    SendAmount(model: p2pModel,
-                     amountAvailable: balance.available,
-                     centsToTransfer: $centsToTransfer,
-                             purpose: $purpose)
+                    SendAmount(amountAvailable: balance.available,
+                               centsToTransfer: $centsToTransfer,
+                                       summary: $summary)
                   }, tag: 1, selection: $buttonSelected
                 ) { EmptyView() }.frame(width: 0).opacity(0).hidden()
 
                 NavigationLink(destination: LazyView {
-                    RequestPayment(model: p2pModel,
-                               scopeInfo: balance.scopeInfo,
-                         centsToTransfer: $centsToTransfer,
-                                 purpose: $purpose)
+                    RequestPayment(scopeInfo: balance.scopeInfo,
+                             centsToTransfer: $centsToTransfer,
+                                     summary: $summary)
                   }, tag: 2, selection: $buttonSelected
                 ) { EmptyView() }.frame(width: 0).opacity(0).hidden()
 
@@ -100,22 +109,22 @@ struct BalancesSectionView: View {
                 ) { EmptyView() }.frame(width: 0).opacity(0).hidden()
 
                 BalanceRowView(amount: balance.available, sendAction: {
-print("button: Send \(currency)")
+//print("button: Send \(currency)")
                         buttonSelected = 1      // will trigger SendAmount 
NavigationLink
                     }, recvAction: {
-print("button: Request Payment: \(currency)")
+//print("button: Request Payment: \(currency)")
                         buttonSelected = 2      // will trigger RequestPayment 
NavigationLink
                     }, rowAction: {
-print("button: Transactions: \(currency)")
+//print("button: Transactions: \(currency)")
                         buttonSelected = 3      // will trigger 
TransactionList NavigationLink
                     })
             }
             let hasPending = pendingTransactions.count > 0
             if hasPending {
-                let hasPendingIn = !balance.pendingIncoming.isZero
-                let hasPendingOut = !balance.pendingOutgoing.isZero
+                let (pendingIncoming, pendingOutgoing) = 
computePending(currency: currency)
+
                 NavigationLink {
-let _ = print("button: Pending Transactions: \(currency)")
+//let _ = print("button: Pending Transactions: \(currency)")
                     LazyView {
                         TransactionsListView(navTitle: String(localized: 
"Pending"), currency: currency,
                                          transactions: pendingTransactions,
@@ -126,11 +135,17 @@ let _ = print("button: Pending Transactions: \(currency)")
                     }
                 } label: {
                     VStack(spacing: 6) {
-                        if hasPendingIn {
-                            PendingRowView(amount: balance.pendingIncoming, 
incoming: true)
+                        var rows = 0
+                        if !pendingIncoming.isZero {
+                            PendingRowView(amount: pendingIncoming, incoming: 
true)
+                            let _ = (rows+=1)
+                        }
+                        if !pendingOutgoing.isZero {
+                            PendingRowView(amount: pendingOutgoing, incoming: 
false)
+                            let _ = (rows+=1)
                         }
-                        if hasPendingOut {
-                            PendingRowView(amount: balance.pendingOutgoing, 
incoming: false)
+                        if rows == 0 {
+                            Text("Some pending transactions")
                         }
                     }
                 }
@@ -138,7 +153,7 @@ let _ = print("button: Pending Transactions: \(currency)")
             let hasUncompleted = uncompletedTransactions.count > 0
             if hasUncompleted {
                 NavigationLink {
-let _ = print("button: Uncompleted Transactions: \(currency)")
+//let _ = print("button: Uncompleted Transactions: \(currency)")
                     LazyView {
                         TransactionsListView(navTitle: String(localized: 
"Uncompleted"), currency: currency,
                                              transactions: 
uncompletedTransactions,
@@ -156,11 +171,10 @@ let _ = print("button: Uncompleted Transactions: 
\(currency)")
             Text(currency)
                 .font(.title)
         } .task {
-            if let model {
-                transactions = await model.fetchTransactionsT(currency: 
currency)
-                pendingTransactions = 
TransactionsModel.pendingTransactions(transactions)
-                uncompletedTransactions = 
TransactionsModel.uncompletedTransactions(transactions)
-            }
+            let response = await model.fetchTransactionsT(currency: currency)
+            transactions = response
+            pendingTransactions = WalletModel.pendingTransactions(response)
+            uncompletedTransactions = 
WalletModel.uncompletedTransactions(response)
         }
     } // body
 }
@@ -168,21 +182,18 @@ let _ = print("button: Uncompleted Transactions: 
\(currency)")
 #if DEBUG
 fileprivate struct BindingViewContainer : View {
     @State var centsToTransfer: UInt64 = 333
-    @State private var purpose: String = "bla-bla"
+    @State private var summary: String = "bla-bla"
 
     var body: some View {
         let scopeInfo = ScopeInfo(type: ScopeInfo.ScopeInfoType.exchange, 
exchangeBaseUrl: DEMOEXCHANGE, currency: LONGCURRENCY)
         let balance = Balance(available: try! Amount(fromString: LONGCURRENCY 
+ ":0.1"),
-                        pendingIncoming: try! Amount(fromString: LONGCURRENCY 
+ ":4.8"),
-                        pendingOutgoing: try! Amount(fromString: LONGCURRENCY 
+ ":3.25"),
-                 hasPendingTransactions: true,
+                              scopeInfo: scopeInfo,
                       requiresUserInput: false,
-                              scopeInfo: scopeInfo)
+                 hasPendingTransactions: true)
         List {
             BalancesSectionView(balance: balance,
                         centsToTransfer: $centsToTransfer,
-                                purpose: $purpose,
-                                  model: nil)
+                                summary: $summary)
         }
     }
 }
diff --git a/TalerWallet1/Views/Exchange/ExchangeListView.swift 
b/TalerWallet1/Views/Exchange/ExchangeListView.swift
index 46644bd..83ba3b3 100644
--- a/TalerWallet1/Views/Exchange/ExchangeListView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeListView.swift
@@ -10,35 +10,27 @@ import SymLog
 struct ExchangeListView: View {
     private let symLog = SymLogV(0)
     let navTitle: String
-
-    var model: ExchangeModel?
     var hamburgerAction: () -> Void
 
+    @EnvironmentObject private var model: WalletModel
+
     @State private var exchanges: [Exchange] = []
 
     // 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)")
+            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)")
             }
         }
     }
diff --git a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift 
b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
index a7c9fad..4b6b635 100644
--- a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
@@ -13,7 +13,6 @@ struct ExchangeRowView: View {
     @State private var buttonSelected: Int? = nil
     var body: some View {
         let baseURL = exchange.exchangeBaseUrl
-        let model = WithdrawModel.model(baseURL: baseURL)
 
         HStack(spacing: 0) {    // can't use the built in Label because it 
adds the accessory arrow
             Text(baseURL.trimURL())
@@ -24,7 +23,6 @@ struct ExchangeRowView: View {
             ) { EmptyView() }.frame(width: 0).opacity(0)
             NavigationLink(destination: LazyView {
                 ManualWithdraw(exchange: exchange,
-                               model: model,
                                centsToTransfer: $centsToTransfer)
             }, tag: 2, selection: $buttonSelected
             ) { EmptyView() }.frame(width: 0).opacity(0)
diff --git a/TalerWallet1/Views/Exchange/ManualWithdraw.swift 
b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
index ab849a0..77034c2 100644
--- a/TalerWallet1/Views/Exchange/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
@@ -11,9 +11,10 @@ struct ManualWithdraw: View {
     private let symLog = SymLogV()
 
     let exchange: Exchange
-    let model: WithdrawModel?
     @Binding var centsToTransfer: UInt64
 
+    @EnvironmentObject private var model: WalletModel
+
     @State var manualWithdrawalDetails: ManualWithdrawalDetails? = nil
 
 //    @State var ageMenuList: [Int] = []
@@ -50,7 +51,6 @@ struct ManualWithdraw: View {
 //let _ = print(selectedAge, restrictAge)
                             NavigationLink(destination: LazyView {
                                 ManualWithdrawDone(exchange: exchange,
-                                                      model: model,
                                             centsToTransfer: centsToTransfer)
 //                                                restrictAge: restrictAge)
                             }) {
@@ -59,7 +59,6 @@ struct ManualWithdraw: View {
                         } else {
                             NavigationLink(destination: LazyView {
                                 WithdrawTOSView(exchangeBaseUrl: 
exchange.exchangeBaseUrl,
-                                                          model: model,
                                                          viewID: 
VIEW_WITHDRAW_TOS,
                                                    acceptAction: nil)         
// pop back to here
                             }) {
@@ -69,7 +68,6 @@ struct ManualWithdraw: View {
                     }
                 } // tooMany
             } // invalid
-            Spacer()
         }
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(.horizontal)
@@ -82,10 +80,8 @@ struct ManualWithdraw: View {
         .task(id: centsToTransfer) {
             let amount = Amount.amountFromCents(currency, centsToTransfer)
             do {
-                if let model {
-                    manualWithdrawalDetails = try await 
model.loadWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl, amount: amount)
-//                  agePicker.setAges(ages: 
manualWithdrawalDetails?.ageRestrictionOptions)
-                }
+                manualWithdrawalDetails = try await 
model.loadWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl, amount: amount)
+//                agePicker.setAges(ages: 
manualWithdrawalDetails?.ageRestrictionOptions)
             } catch {    // TODO: error
                 symLog.log(error.localizedDescription)
                 manualWithdrawalDetails = nil
@@ -112,7 +108,6 @@ struct ManualWithdraw_Container : View {
                           ageRestrictionOptions: [],
                                       permanent: false)
         ManualWithdraw(exchange: exchange,
-                          model: nil,
                 centsToTransfer: $centsToTransfer,
         manualWithdrawalDetails: details)
     }
diff --git a/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift 
b/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
index 27c4213..0afd531 100644
--- a/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
+++ b/TalerWallet1/Views/Exchange/ManualWithdrawDone.swift
@@ -11,19 +11,16 @@ struct ManualWithdrawDone: View {
     let navTitle = String(localized: "Wire Transfer")
 
     let exchange: Exchange
-    let model: WithdrawModel?
     let centsToTransfer: UInt64
 //    let restrictAge: Int?
 
+    @EnvironmentObject private var model: WalletModel
+
     @State var acceptManualWithdrawalResult: AcceptManualWithdrawalResult?
     @State var withdrawalTransaction: Transaction?
 
     func reloadOneAction(_ transactionId: String) async throws -> Transaction {
-        if let model {
-            return try await model.getTransactionByIdT(transactionId)
-        } else {
-            throw WalletBackendError.walletCoreError
-        }
+        return try await model.getTransactionByIdT(transactionId)
     }
 
     var body: some View {
@@ -47,14 +44,12 @@ struct ManualWithdrawDone: View {
             DebugViewC.shared.setViewID(VIEW_WITHDRAW_ACCEPT)
         }.task {
             do {
-                if let model {
-                    let amount = Amount.amountFromCents(exchange.currency!, 
centsToTransfer)
-                    let result = try await 
model.sendAcceptManualWithdrawalM(exchange.exchangeBaseUrl,
-                                                                             
amount: amount, restrictAge: 0)
+                let amount = Amount.amountFromCents(exchange.currency!, 
centsToTransfer)
+                let result = try await 
model.sendAcceptManualWithdrawalM(exchange.exchangeBaseUrl,
+                                                                         
amount: amount, restrictAge: 0)
 print(result as Any)
-                    let transaction = try await 
model.getTransactionByIdT(result!.transactionId)
-                    withdrawalTransaction = transaction
-                }
+                let transaction = try await 
model.getTransactionByIdT(result!.transactionId)
+                withdrawalTransaction = transaction
             } catch {    // TODO: error
                 symLog.log(error.localizedDescription)
             }
@@ -76,7 +71,6 @@ struct ManualWithdrawDone_Container : View {
                           ageRestrictionOptions: [],
                                       permanent: false)
         ManualWithdrawDone(exchange: exchange,
-                              model: nil,
                     centsToTransfer: centsToTransfer)
     }
 }
diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift 
b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
index 0d5366b..eaa5dea 100644
--- a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
+++ b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
@@ -8,12 +8,14 @@ import AVFoundation
 
 
 struct QRCodeDetailView: View {
-    var talerURI: String
+    @Binding var talerURI: String
+    let incoming: Bool
 
     var body: some View {
         if talerURI.count > 10 {
             VStack {
-                Text("Let the payee scan this QR code to receive:")
+                Text(incoming ? "Let the payer scan this QR code to pay:"
+                              : "Let the payee scan this QR code to receive:")
                     .fixedSize(horizontal: false, vertical: true)
                     .padding(.top, 30)
                     .font(.title3)
@@ -35,25 +37,21 @@ struct QRCodeDetailView: View {
         }
     }
 }
-
-
+// MARK: -
 #if DEBUG
 fileprivate struct ContentView: View {
-    @State var isOn = false
+    @State var talerURI: String = 
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520"
 
     var body: some View {
-        VStack {
-
+        List {
+            QRCodeDetailView(talerURI: $talerURI, incoming: false)
         }
     }
 }
 struct QRCodeDetailView_Previews: PreviewProvider {
 
     static var previews: some View {
-//        ContentView()
-        List {
-            QRCodeDetailView(talerURI: 
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520")
-        }
+        ContentView()
     }
 }
 #endif
diff --git a/TalerWallet1/Views/Main/MainView.swift 
b/TalerWallet1/Views/Main/MainView.swift
index b2745b6..20eea52 100644
--- a/TalerWallet1/Views/Main/MainView.swift
+++ b/TalerWallet1/Views/Main/MainView.swift
@@ -75,13 +75,11 @@ extension MainView {
             SidebarItem(name: balances,
                     sysImage: "creditcard.fill",        // TODO: Wallet Icon
                         view: AnyView(BalancesListView(navTitle: balances,
-                                                          model: 
BalancesModel.model(currency: "*"),
                                                 hamburgerAction: 
hamburgerAction)
                                      )),
             SidebarItem(name: exchanges,
                     sysImage: "building.columns",
                         view: AnyView(ExchangeListView(navTitle: exchanges,
-                                                          model: 
ExchangeModel.model(),
                                                 hamburgerAction: 
hamburgerAction)
                                      )),
             SidebarItem(name: settings,    // TODO: "About"?
diff --git a/TalerWallet1/Views/Payment/PaymentURIView.swift 
b/TalerWallet1/Views/Payment/PaymentURIView.swift
index 22048ca..c6e9ea6 100644
--- a/TalerWallet1/Views/Payment/PaymentURIView.swift
+++ b/TalerWallet1/Views/Payment/PaymentURIView.swift
@@ -6,10 +6,13 @@ import SwiftUI
 import AVFoundation
 import SymLog
 
+// Will be called either by the user scanning a QR code or tapping the 
provided link, both from the shop's website
+// we show the user the payment details
 struct PaymentURIView: View {
     private let symLog = SymLogV()
-    var url: URL
-    var model: PaymentURIModel?
+    let url: URL
+
+    @EnvironmentObject private var model: WalletModel
 
     @State var detailsForUri: PaymentDetailsForUri? = nil
 
@@ -27,16 +30,14 @@ struct PaymentURIView: View {
         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)
-                        }
+                    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
@@ -59,9 +60,8 @@ struct PaymentURIView: View {
         }.task {
             do {
                 symLog.log(".task")
-                if let model {
-                    detailsForUri = try await 
model.preparePayForUriM(url.absoluteString)
-                }
+                let details = try await 
model.preparePayForUriM(url.absoluteString)
+                detailsForUri = details
             } catch {    // TODO: error
                 symLog.log(error.localizedDescription)
             }
diff --git a/TalerWallet1/Views/Peer2peer/ReceivePurpose.swift 
b/TalerWallet1/Views/Peer2peer/PaymentPurpose.swift
similarity index 60%
rename from TalerWallet1/Views/Peer2peer/ReceivePurpose.swift
rename to TalerWallet1/Views/Peer2peer/PaymentPurpose.swift
index 16add0d..e7230ea 100644
--- a/TalerWallet1/Views/Peer2peer/ReceivePurpose.swift
+++ b/TalerWallet1/Views/Peer2peer/PaymentPurpose.swift
@@ -6,40 +6,29 @@ import SwiftUI
 import taler_swift
 import SymLog
 
-struct ReceivePurpose: View {
+struct PaymentPurpose: View {
     private let symLog = SymLogV()
-    @FocusState private var isFocused: Bool
-    @State var peerPullCheck: CheckPeerPullCreditResponse?
 
-    var scopeInfo: ScopeInfo
-    var centsToTransfer: UInt64
-    @Binding var purpose: String
+    let scopeInfo: ScopeInfo
+    let centsToTransfer: UInt64
+    let fee: String
+    @Binding var summary: String
     @Binding var expireDays: UInt
-    var deactivateAction: () -> Void
+//    var deactivateAction: () -> Void
 
-    let formatter = CurrencyFormatter.shared    // TODO: based on currency
+    @FocusState private var isFocused: Bool
 
+    let formatter = CurrencyFormatter.shared    // TODO: based on currency
     let buttonFont: Font = .title2
+
     private var label: String {
         let mag = pow(10, formatter.maximumFractionDigits)
         return formatter.string(for: Decimal(centsToTransfer) / mag) ?? ""
     }
 
-    func pullFee(ppCheck: CheckPeerPullCreditResponse?) -> String {
-        do {
-            if let p2pcheck = ppCheck {
-                let fee = try p2pcheck.amountRaw - p2pcheck.amountEffective
-                return fee.readableDescription
-            }
-        } catch {}
-        return ""
-    }
-
     var body: some View {
         let amount = Amount.amountFromCents(scopeInfo.currency, 
centsToTransfer)
-        let model = Peer2peerModel.model(baseURL: scopeInfo.currency)
 
-        let fee = pullFee(ppCheck: peerPullCheck)
         VStack (spacing: 6) {
             Text(amount.readableDescription)
             Text("+ \(fee) payment fee")
@@ -49,7 +38,7 @@ struct ReceivePurpose: View {
                     .padding(.top)
                     .font(.title3)
 
-                TextField("Purpose", text: $purpose)
+                TextField("Purpose", text: $summary)
                     .font(.title)
                     .foregroundColor(WalletColors().fieldForeground)     // 
text color
                     .background(WalletColors().fieldBackground)
@@ -63,7 +52,7 @@ struct ReceivePurpose: View {
 
                 HStack{
                     Spacer()
-                    Text("\(purpose.count)/100")
+                    Text("\(summary.count)/100")
                 } // maximum 100 characters
 
                 Text("Expires in:")
@@ -73,13 +62,14 @@ struct ReceivePurpose: View {
                     .disabled(false)
                     .padding(.bottom)
 
-                let buttonTitle = "Invoice \(label) \(scopeInfo.currency)"
-                let disabled = (expireDays == 0) || (purpose.count < 1)
+                let disabled = (expireDays == 0) || (summary.count < 1)
 
                 NavigationLink(destination: LazyView {
-                    SendNow(amountToSend: amount, purpose: purpose, 
expireDays: expireDays, model: model)
+                    SendNow(amountToSend: nil,
+                            amountToReceive: amount,
+                            summary: summary, expireDays: expireDays)
                 }) {
-                    Text(buttonTitle)
+                    Text("Invoice \(label) \(scopeInfo.currency)")
                         .font(buttonFont)
                 }
                 .buttonStyle(TalerButtonStyle(type: .prominent))
@@ -94,36 +84,28 @@ struct ReceivePurpose: View {
         .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
         .onAppear {
             DebugViewC.shared.setSheetID(VIEW_INVOICE_PURPOSE)
-            print("❗️ ReceivePurpose onAppear")
+            print("❗️ PaymentPurpose onAppear")
         }
         .onDisappear {
-            print("❗️ ReceivePurpose onDisappear")
-            deactivateAction()
-        }
-        .task {
-            symLog.log(".task")
-            do {
-                peerPullCheck = try await model.checkPeerPullCreditM(amount, 
exchangeBaseUrl: scopeInfo.exchangeBaseUrl ?? nil)   // TODO: exchangeBaseUrl!
-            } catch {    // TODO: error
-                symLog.log(error.localizedDescription)
-            }
+            print("❗️ PaymentPurpose onDisappear")
+//            deactivateAction()
         }
     }
 
 }
 // MARK: -
 #if DEBUG
-struct ReceivePurpose_Previews: PreviewProvider {
+struct PaymentPurpose_Previews: PreviewProvider {
     static var previews: some View {
         let scopeInfo = ScopeInfo(type: ScopeInfo.ScopeInfoType.exchange, 
exchangeBaseUrl: DEMOEXCHANGE, currency: LONGCURRENCY)
-        @State var purpose: String = "pUrPoSe"
+        @State var summary: String = "pUrPoSe"
         @State var expireDays: UInt = 0
-        ReceivePurpose(scopeInfo: scopeInfo,
+        PaymentPurpose(scopeInfo: scopeInfo,
                  centsToTransfer: 5,
-                         purpose: $purpose,
-                      expireDays: $expireDays) {
-            print("deactivateAction")
-        }
+                             fee: "fee",
+                         summary: $summary,
+                      expireDays: $expireDays)
+//        { print("deactivateAction") }
     }
 }
 #endif
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift 
b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
index d8d3be3..27e4aa6 100644
--- a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -6,13 +6,15 @@ import SwiftUI
 import taler_swift
 import SymLog
 
+// Will be called by the user tapping "Request Payment" in the balances list
 struct RequestPayment: View {
     private let symLog = SymLogV()
 
-    let model: Peer2peerModel?
     var scopeInfo: ScopeInfo
     @Binding var centsToTransfer: UInt64
-    @Binding var purpose: String
+    @Binding var summary: String
+
+    @EnvironmentObject private var model: WalletModel
 
     @State private var peerPullCheck: CheckPeerPullCreditResponse? = nil
     @State private var expireDays: UInt = 0
@@ -26,7 +28,7 @@ struct RequestPayment: View {
         let navTitle = String(localized: "Request \(currency)")
         let currencyField = CurrencyField(value: $centsToTransfer, currency: 
currency)
 
-        VStack(alignment: .leading, spacing: 6) {
+        ScrollView {
             CurrencyInputView(currencyField: currencyField,
                               title: String(localized: "Amount to receive:"))
 
@@ -37,26 +39,19 @@ struct RequestPayment: View {
             HStack {
                 let disabled = centsToTransfer == 0
 
-                let deactivateAction = {
-                    print("❗️ deactivateAction")
-                }
-
                 NavigationLink(destination: LazyView {
-                    ReceivePurpose(scopeInfo: scopeInfo,
+                    PaymentPurpose(scopeInfo: scopeInfo,
                              centsToTransfer: centsToTransfer,
-                                     purpose: $purpose,
-                                  expireDays: $expireDays
-                    ) {
-                        deactivateAction()
-                    }
+                                         fee: someCoins.fee,
+                                     summary: $summary,
+                                  expireDays: $expireDays)
+//                        { deactivateAction() }
                 }) {
                     Text("Create invoice")
                 }
                 .buttonStyle(TalerButtonStyle(type: .prominent))
                 .disabled(disabled)
             }
-            
-            Spacer()
         }
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(.horizontal)
@@ -72,12 +67,10 @@ struct RequestPayment: View {
         .task(id: centsToTransfer) {
             let amount = Amount.amountFromCents(currency, centsToTransfer)
             do {
-                if let model {
-                    let ppCheck = try await model.checkPeerPullCreditM(amount, 
exchangeBaseUrl: nil)
-                    peerPullCheck = ppCheck
-                    // TODO: set from exchange
+                let ppCheck = try await model.checkPeerPullCreditM(amount, 
exchangeBaseUrl: nil)
+                peerPullCheck = ppCheck
+                // TODO: set from exchange
 //                agePicker.setAges(ages: peerPushCheck?.ageRestrictionOptions)
-                }
             } catch {    // TODO: error
                 symLog.log(error.localizedDescription)
                 peerPullCheck = nil
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift 
b/TalerWallet1/Views/Peer2peer/SendAmount.swift
index 17e7026..a845d6d 100644
--- a/TalerWallet1/Views/Peer2peer/SendAmount.swift
+++ b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -10,12 +10,13 @@ import SymLog
 struct SendAmount: View {
     private let symLog = SymLogV()
 
-    let model: Peer2peerModel?
     let amountAvailable: Amount
     @Binding var centsToTransfer: UInt64
-    @Binding var purpose: String
+    @Binding var summary: String
 
-    @State var peerPushCheck: CheckPeerPushDebitResponse?
+    @EnvironmentObject private var model: WalletModel
+
+    @State var peerPushCheck: CheckPeerPushDebitResponse? = nil
     @State private var expireDays: UInt = 0
 
     private func fee(ppCheck: CheckPeerPushDebitResponse?) -> String {
@@ -54,21 +55,18 @@ struct SendAmount: View {
                 let disabled = centsToTransfer == 0    // TODO: check 
amountAvailable
 
                 NavigationLink(destination: LazyView {
-                    SendPurpose(model: model,
-                      amountAvailable: amountAvailable,
-                          centsToSend: centsToTransfer,
-                                  fee: fee,
-                              purpose: $purpose,
-                           expireDays: $expireDays,
-                     deactivateAction: {})
+                    SendPurpose(amountAvailable: amountAvailable,
+                                centsToTransfer: centsToTransfer,
+                                            fee: fee,
+                                        summary: $summary,
+                                     expireDays: $expireDays)
+//                        { deactivateAction() }
                 }) {
                     Text("To another wallet")
                 }
                 .buttonStyle(TalerButtonStyle(type: .prominent))
                 .disabled(disabled)
             }
-            
-            Spacer()
         }
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(.horizontal)
@@ -84,12 +82,10 @@ struct SendAmount: View {
         .task(id: centsToTransfer) {
             let amount = Amount.amountFromCents(currency, centsToTransfer)
             do {
-                if let model {
-                    let ppCheck = try await model.checkPeerPushDebitM(amount)
-                    peerPushCheck = ppCheck
-                    // TODO: set from exchange
-                    //                agePicker.setAges(ages: 
peerPushCheck?.ageRestrictionOptions)
-                }
+                let ppCheck = try await model.checkPeerPushDebitM(amount)
+                peerPushCheck = ppCheck
+                // TODO: set from exchange
+//                agePicker.setAges(ages: peerPushCheck?.ageRestrictionOptions)
             } catch {    // TODO: error
                 symLog.log(error.localizedDescription)
                 peerPushCheck = nil
@@ -101,14 +97,13 @@ struct SendAmount: View {
 #if DEBUG
 struct SendAmount_Container : View {
     @State private var centsToTransfer: UInt64 = 510
-    @State private var purpose: String = ""
+    @State private var summary: String = ""
 
     var body: some View {
         let amount = Amount(currency: LONGCURRENCY, integer: 10, fraction: 0)
-        SendAmount(model: nil,
-         amountAvailable: amount,
-         centsToTransfer: $centsToTransfer,
-                 purpose: $purpose)
+        SendAmount(amountAvailable: amount,
+                   centsToTransfer: $centsToTransfer,
+                           summary: $summary)
     }
 }
 
diff --git a/TalerWallet1/Views/Peer2peer/SendNow.swift 
b/TalerWallet1/Views/Peer2peer/SendNow.swift
index 8615341..811c22b 100644
--- a/TalerWallet1/Views/Peer2peer/SendNow.swift
+++ b/TalerWallet1/Views/Peer2peer/SendNow.swift
@@ -10,22 +10,22 @@ import SymLog
 struct SendNow: View {
     private let symLog = SymLogV()
 
-    var amountToSend: Amount
-    var purpose: String
-    var expireDays: UInt
+    let amountToSend: Amount?
+    let amountToReceive: Amount?
+    let summary: String
+    let expireDays: UInt
 
-    var model: Peer2peerModel?
-    @State var peerPushResponse: PeerPushResponse?
+    @EnvironmentObject private var model: WalletModel
 
-    @State var talerURI: String? = nil
+    @State var talerURI: String = ""
 
     var body: some View {
         ScrollView {
-            if talerURI == nil {
+            if talerURI.isEmpty {
                 LoadingView(backButtonHidden: true)
             } else {
                 VStack() {
-                    QRCodeDetailView(talerURI: talerURI!)
+                    QRCodeDetailView(talerURI: $talerURI, incoming: 
amountToSend == nil)
 
                     Text("The QR code can also be copied and shared from 
Transactions later")
                         .fixedSize(horizontal: false, vertical: true)
@@ -50,29 +50,38 @@ struct SendNow: View {
             symLog.log(".task")
             do {
                 // generate talerURI
-                if let model {
-                    let timestamp = Timestamp.inSomeDays(expireDays)
-                    let terms = PeerContractTerms(amount: amountToSend, 
summary: purpose, purse_expiration: timestamp)
+                let timestamp = Timestamp.inSomeDays(expireDays)
+                if let amountToSend {
+                    let terms = PeerContractTerms(amount: amountToSend,
+                                                 summary: summary,
+                                        purse_expiration: timestamp)
                     // TODO: user might choose baseURL
-                    peerPushResponse = try await 
model.initiatePeerPushDebitM(nil, terms: terms)
-                    talerURI = peerPushResponse?.talerUri
-                }
+                    let response = try await model.initiatePeerPushDebitM(nil, 
terms: terms)
+                    talerURI = response.talerUri
+                } else if let amountToReceive {
+                    let terms = PeerContractTerms(amount: amountToReceive,
+                                                 summary: summary,
+                                        purse_expiration: timestamp)
+                    // TODO: user might choose baseURL
+                    let response = try await 
model.initiatePeerPullCreditM(nil, terms: terms)
+                    talerURI = response.talerUri
+                } else { talerURI = "" }
             } catch {    // TODO: error
                 symLog.log(error.localizedDescription)
+                talerURI = ""
             }
         } // task
     }
 }
 // MARK: -
-//struct SendNow_Previews: PreviewProvider {
-//    static var previews: some View {
-//        Group {
-//            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")
-//        }
-//    }
-//}
+struct SendNow_Previews: PreviewProvider {
+    static var previews: some View {
+        Group {
+            SendNow(amountToSend: try! Amount(fromString: LONGCURRENCY + 
":4.8"),
+                    amountToReceive: nil,
+                    summary: "some purpose",
+                    expireDays: 0,
+                    talerURI: 
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520")
+        }
+    }
+}
diff --git a/TalerWallet1/Views/Peer2peer/SendPurpose.swift 
b/TalerWallet1/Views/Peer2peer/SendPurpose.swift
index 298115e..a17d7f4 100644
--- a/TalerWallet1/Views/Peer2peer/SendPurpose.swift
+++ b/TalerWallet1/Views/Peer2peer/SendPurpose.swift
@@ -9,25 +9,24 @@ import SymLog
 struct SendPurpose: View {
     private let symLog = SymLogV()
     @FocusState private var isFocused: Bool
-    var model: Peer2peerModel?
 
-    var amountAvailable: Amount
-    var centsToSend: UInt64
-    var fee: String
-    @Binding var purpose: String
+    let amountAvailable: Amount
+    let centsToTransfer: UInt64
+    let fee: String
+    @Binding var summary: String
     @Binding var expireDays: UInt
-    var deactivateAction: () -> Void
+//    var deactivateAction: () -> Void
 
     let formatter = CurrencyFormatter.shared    // TODO: based on currency
 
     let buttonFont: Font = .title2
     private var label: String {
         let mag = pow(10, formatter.maximumFractionDigits)
-        return formatter.string(for: Decimal(centsToSend) / mag) ?? ""
+        return formatter.string(for: Decimal(centsToTransfer) / mag) ?? ""
     }
 
     var body: some View {
-        let amount = Amount.amountFromCents(amountAvailable.currencyStr, 
centsToSend)
+        let amount = Amount.amountFromCents(amountAvailable.currencyStr, 
centsToTransfer)
 
         VStack (spacing: 6) {
             Text(amount.readableDescription)
@@ -38,7 +37,7 @@ struct SendPurpose: View {
                     .padding(.top)
                     .font(.title3)
 
-                TextField("Purpose", text: $purpose)
+                TextField("Purpose", text: $summary)
                     .font(.title)
                     .foregroundColor(WalletColors().fieldForeground)     // 
text color
                     .background(WalletColors().fieldBackground)
@@ -52,7 +51,7 @@ struct SendPurpose: View {
 
                 HStack{
                     Spacer()
-                    Text("\(purpose.count)/100")
+                    Text("\(summary.count)/100")
                 } // maximum 100 characters
 
                 Text("Expires in:")
@@ -63,13 +62,14 @@ struct SendPurpose: View {
                     .disabled(false)
                     .padding(.bottom)
 
-                let buttonTitle = "Send \(label) 
\(amountAvailable.currencyStr) now"
-                let disabled = (expireDays == 0) || (purpose.count < 1)    // 
TODO: check amountAvailable
+                let disabled = (expireDays == 0) || (summary.count < 1)    // 
TODO: check amountAvailable
 
                 NavigationLink(destination: LazyView {
-                    SendNow(amountToSend: amount, purpose: purpose, 
expireDays: expireDays, model: model)
+                    SendNow(amountToSend: amount,
+                            amountToReceive: nil,
+                            summary: summary, expireDays: expireDays)
                 }) {
-                    Text(buttonTitle)
+                    Text("Send \(label) \(amountAvailable.currencyStr) now")
                         .font(buttonFont)
                 }
                 .buttonStyle(TalerButtonStyle(type: .prominent))
@@ -88,7 +88,7 @@ struct SendPurpose: View {
         }
         .onDisappear {
             print("❗️ SendPurpose onDisappear")
-            deactivateAction()
+//            deactivateAction()
         }
         .task {
             symLog.log(".task")
@@ -105,18 +105,15 @@ struct SendPurpose: View {
 #if DEBUG
 struct SendPurpose_Previews: PreviewProvider {
     static var previews: some View {
-        @State var purpose: String = ""
+        @State var summary: String = ""
         @State var expireDays: UInt = 0
         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")
-        }
+        SendPurpose(amountAvailable: amount,
+                    centsToTransfer: 543,
+                                fee: "0,43",
+                            summary: $summary,
+                         expireDays: $expireDays)
+//        { print("deactivateAction") }
     }
 }
 #endif
diff --git a/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift 
b/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
index 8f29111..66691b6 100644
--- a/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
+++ b/TalerWallet1/Views/Settings/Pending/PendingOpsListView.swift
@@ -9,8 +9,9 @@ struct PendingOpsListView: View {
     private let symLog = SymLogV(0)
     let navTitle = String(localized: "Pending")
 
+    @EnvironmentObject private var model: WalletModel
+
     @State var pendingOperations: [PendingOperation] = []
-    var model: PendingModel
 
     var body: some View {
 #if DEBUG
@@ -32,6 +33,7 @@ extension PendingOpsListView {
         let symLog: SymLogV?
         @Binding var pendingOperations: [PendingOperation]
         var reloadAction: () async -> [PendingOperation]
+        @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
         var body: some View {
 #if DEBUG
             let _ = Self._printChanges()
@@ -41,7 +43,7 @@ extension PendingOpsListView {
                 List(pendingOperations, id: \.self) { pendingOp in
                     PendingOpView(pendingOp: pendingOp)
                 }
-                .listStyle(SidebarListStyle())
+                .listStyle(myListStyle.style).anyView
                 .navigationBarTitleDisplayMode(.large)
                 .onAppear() {
                     DebugViewC.shared.setViewID(VIEW_PENDING)
diff --git a/TalerWallet1/Views/Settings/SettingsView.swift 
b/TalerWallet1/Views/Settings/SettingsView.swift
index 247a1e8..e299e65 100644
--- a/TalerWallet1/Views/Settings/SettingsView.swift
+++ b/TalerWallet1/Views/Settings/SettingsView.swift
@@ -27,6 +27,8 @@ struct SettingsView: View {
 
     var hamburgerAction: () -> Void
 
+    @EnvironmentObject private var model: WalletModel
+
     @State private var checkDisabled = false
     @State private var withDrawDisabled = false
 #if DEBUG
@@ -66,7 +68,7 @@ struct SettingsView: View {
                     }
                     if showDevelopItems {  // show or hide the following items
                         NavigationLink {        // whole row like in a 
tableView
-                            LazyView { PendingOpsListView(model: 
PendingModel.model()) }
+                            LazyView { PendingOpsListView() }
                         } label: {
                             SettingsItem(name: String(localized: "Pending 
Operations"), description: String(localized: "Exchange not yet ready...")) {}
                         }
@@ -80,7 +82,6 @@ struct SettingsView: View {
                             Button("Withdraw") {
                                 withDrawDisabled = true    // don't run twice
                                 Task {
-                                    let model: SettingsModel = SettingsModel()
                                     symLog.log("Withdraw TestKUDOS")
                                     do {
                                         try await model.loadTestKudosM()
@@ -97,7 +98,6 @@ struct SettingsView: View {
                             Button("Test 1") {
                                 checkDisabled = true    // don't run twice
                                 Task {
-                                    let model: SettingsModel = SettingsModel()
                                     symLog.log("running integration test")
                                     do {
                                         try await 
model.runIntegrationTestM(newVersion: false)
@@ -114,7 +114,6 @@ struct SettingsView: View {
                             Button("Test 2") {
                                 checkDisabled = true    // don't run twice
                                 Task {
-                                    let model: SettingsModel = SettingsModel()
                                     symLog.log("running integration test V2")
                                     do {
                                         try await 
model.runIntegrationTestM(newVersion: true)
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift 
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pAcceptDone.swift
similarity index 75%
copy from TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
copy to TalerWallet1/Views/Sheets/P2P_Sheets/P2pAcceptDone.swift
index 766ee8d..34380e6 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pAcceptDone.swift
@@ -6,23 +6,20 @@ import SwiftUI
 import taler_swift
 import SymLog
 
-struct WithdrawAcceptDone: View {
+struct P2pAcceptDone: View {
     private let symLog = SymLogV()
-    let navTitle = String(localized: "Confirm with Bank")
+    let navTitle = String(localized: "Received P2P")
 
-    let exchangeBaseUrl: String
-    let model: WithdrawModel?
+    let exchangeBaseUrl: String?
     let url: URL
 
+    @EnvironmentObject private var model: WalletModel
+
     @State private var confirmTransferUrl: String? = nil
     @State private var transaction: Transaction? = nil
 
     func reloadOneAction(_ transactionId: String) async throws -> Transaction {
-        if let model {
-            return try await model.getTransactionByIdT(transactionId)
-        } else {
-            throw WalletBackendError.walletCoreError
-        }
+        return try await model.getTransactionByIdT(transactionId)
     }
 
     var body: some View {
@@ -44,10 +41,10 @@ struct WithdrawAcceptDone: View {
             }
         }.onAppear() {
             symLog.log("onAppear")
-            DebugViewC.shared.setSheetID(SHEET_WITHDRAW_CONFIRM)
+            DebugViewC.shared.setSheetID(SHEET_RCV_P2P_ACCEPT)
         }.task {
             do {
-                if let model {
+                if let exchangeBaseUrl {
                     let result = try await 
model.sendAcceptIntWithdrawalM(exchangeBaseUrl, withdrawURL: url.absoluteString)
                     confirmTransferUrl = result!.confirmTransferUrl
                     transaction = try await 
model.getTransactionByIdT(result!.transactionId)
@@ -59,10 +56,9 @@ struct WithdrawAcceptDone: View {
     }
 }
 // MARK: -
-struct WithdrawAcceptDone_Previews: PreviewProvider {
+struct P2pAcceptDone_Previews: PreviewProvider {
     static var previews: some View {
-        WithdrawAcceptDone(exchangeBaseUrl: DEMOEXCHANGE,
-                           model: nil,
+        P2pAcceptDone(exchangeBaseUrl: DEMOEXCHANGE,
                            url: URL(string: DEMOSHOP)!)
     }
 }
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift 
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
new file mode 100644
index 0000000..1b0478a
--- /dev/null
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
@@ -0,0 +1,80 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+import SwiftUI
+import taler_swift
+import SymLog
+
+// Will be called either by the user scanning a QR code or tapping the 
provided link, from another user's SendCoins
+// we show the user the P2P details - but first the ToS must be accepted
+struct P2pReceiveURIView: View {
+    private let symLog = SymLogV()
+    let navTitle = String(localized: "Accept P2P Receive")
+
+    // the URL from the bank website
+    let url: URL
+    @EnvironmentObject private var model: WalletModel
+
+    @State private var peerPushCreditResponse: PreparePeerPushCreditResponse?
+
+    var body: some View {
+        let badURL = "Error in URL: \(url)"
+        VStack {
+            if let peerPushCreditResponse {
+                List {
+                    let raw = peerPushCreditResponse.amountRaw
+                    let effective = peerPushCreditResponse.amountEffective
+                    let currency = raw.currencyStr
+                    let fee = try! Amount.diff(raw, effective)
+                    let outColor = WalletColors().transactionColor(false)
+                    let inColor = WalletColors().transactionColor(true)
+
+                    ThreeAmountsView(topTitle: String(localized: "Amount to 
receive:"),
+                                    topAmount: raw, fee: fee,
+                                  bottomTitle: String(localized: "\(currency) 
to be obtained:"),
+                                 bottomAmount: effective,
+                                        large: false, pending: false, 
incoming: true,
+                                      baseURL: nil)
+                }
+                .navigationTitle(navTitle)
+                let tosAccepted = true  // TODO: 
https://bugs.gnunet.org/view.php?id=7869
+                if tosAccepted {
+                    NavigationLink(destination: LazyView {
+                        P2pAcceptDone(exchangeBaseUrl: nil, url: url)
+                    }) {
+                        Text("Confirm Withdrawal")      // 
SHEET_WITHDRAW_ACCEPT
+                    }.buttonStyle(TalerButtonStyle(type: .prominent))
+                        .padding()
+                } else {
+                    NavigationLink(destination: LazyView {
+                        WithdrawTOSView(exchangeBaseUrl: nil,
+                                                 viewID: SHEET_RCV_P2P_TOS,
+                                           acceptAction: nil)         // pop 
back to here
+                    }) {
+                        Text("Check Terms of Service")
+                    }.buttonStyle(TalerButtonStyle(type: .prominent))
+                        .padding()
+                }
+            } else {
+                // Yikes no details or no baseURL
+//                WithdrawProgressView(message: url.host ?? badURL)
+//                    .navigationTitle("Contacting Exchange")
+            }
+        }
+        .onAppear() {
+            symLog.log("onAppear")
+            DebugViewC.shared.setSheetID(SHEET_RCV_P2P)
+        }
+        .task {
+            do { // TODO: cancelled
+                symLog.log(".task")
+                let ppCreditResponse = try await 
model.preparePeerPushCreditM(url.absoluteString)
+                peerPushCreditResponse = ppCreditResponse
+            } catch {    // TODO: error
+                symLog.log(error.localizedDescription)
+                peerPushCreditResponse = nil
+            }
+        }
+    }
+}
diff --git a/TalerWallet1/Views/Sheets/URLSheet.swift 
b/TalerWallet1/Views/Sheets/URLSheet.swift
index 249c138..d58eb4c 100644
--- a/TalerWallet1/Views/Sheets/URLSheet.swift
+++ b/TalerWallet1/Views/Sheets/URLSheet.swift
@@ -15,11 +15,19 @@ struct URLSheet: View {
 
     var body: some View {
         Group {
-            if urlCommand == .withdraw {
-                WithdrawURIView(url: urlToOpen)
-            } else if urlCommand == UrlCommand.pay {
-                let model = PaymentURIModel.model()
-                PaymentURIView(url: urlToOpen, model: model)
+            if let urlCommand {
+                switch urlCommand {
+                    case .withdraw:
+                        WithdrawURIView(url: urlToOpen)
+                    case .pay:
+                        PaymentURIView(url: urlToOpen)
+                    case .payPull:
+                        Text("payPull not implemented yet")
+                    case .payPush:
+                        P2pReceiveURIView(url: urlToOpen)
+                    case .unknown:
+                        Text("unknown command")
+                }
             } else {
                 VStack {        // Error view
                     Spacer()
diff --git a/TalerWallet1/Views/Transactions/ThreeAmounts.swift 
b/TalerWallet1/Views/Transactions/ThreeAmounts.swift
index 661fcfe..26a4cb3 100644
--- a/TalerWallet1/Views/Transactions/ThreeAmounts.swift
+++ b/TalerWallet1/Views/Transactions/ThreeAmounts.swift
@@ -79,7 +79,7 @@ struct ThreeAmountsView: View {
             if let status {
                 HStack {
                     Spacer()
-                    Text("Status: \(status)")       // TODO: localize
+                    Text("Status: \(status)")
                         .font(.title2)
                 }.padding()
             }
@@ -103,6 +103,7 @@ struct ThreeAmounts_Previews: PreviewProvider {
                         Button(String(localized: "Accept"), action: {})
                             .buttonStyle(TalerButtonStyle(type: .prominent))
                             .padding(.horizontal)
+                            .disabled(true)
                     }
             }
         }
diff --git a/TalerWallet1/Views/Transactions/TransactionDetailView.swift 
b/TalerWallet1/Views/Transactions/TransactionDetailView.swift
index d9e16c1..f1ea9d8 100644
--- a/TalerWallet1/Views/Transactions/TransactionDetailView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionDetailView.swift
@@ -27,8 +27,9 @@ struct TransactionDetailView: View {
         let common = transaction.common
         let pending = transaction.isPending
         let dateString = TalerDater.dateString(from: common.timestamp)
-        let navTitle = (pending ? String(localized: "Pending ") : "") + 
"\(common.type)"   // TODO: localize type
-
+        let localizedType = transaction.localizedType
+        let navTitle = pending ? String(localized: "Pending \(localizedType)")
+                               : localizedType
         Group {
             List {
                 Text("\(dateString)")
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift 
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
index 766ee8d..e7cf2a1 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawAcceptDone.swift
@@ -10,19 +10,16 @@ struct WithdrawAcceptDone: View {
     private let symLog = SymLogV()
     let navTitle = String(localized: "Confirm with Bank")
 
-    let exchangeBaseUrl: String
-    let model: WithdrawModel?
+    let exchangeBaseUrl: String?
     let url: URL
 
+    @EnvironmentObject private var model: WalletModel
+
     @State private var confirmTransferUrl: String? = nil
     @State private var transaction: Transaction? = nil
 
     func reloadOneAction(_ transactionId: String) async throws -> Transaction {
-        if let model {
             return try await model.getTransactionByIdT(transactionId)
-        } else {
-            throw WalletBackendError.walletCoreError
-        }
     }
 
     var body: some View {
@@ -47,7 +44,7 @@ struct WithdrawAcceptDone: View {
             DebugViewC.shared.setSheetID(SHEET_WITHDRAW_CONFIRM)
         }.task {
             do {
-                if let model {
+                if let exchangeBaseUrl {
                     let result = try await 
model.sendAcceptIntWithdrawalM(exchangeBaseUrl, withdrawURL: url.absoluteString)
                     confirmTransferUrl = result!.confirmTransferUrl
                     transaction = try await 
model.getTransactionByIdT(result!.transactionId)
@@ -62,7 +59,6 @@ struct WithdrawAcceptDone: View {
 struct WithdrawAcceptDone_Previews: PreviewProvider {
     static var previews: some View {
         WithdrawAcceptDone(exchangeBaseUrl: DEMOEXCHANGE,
-                           model: nil,
                            url: URL(string: DEMOSHOP)!)
     }
 }
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift 
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
index 4df29c3..f0efbd2 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift
@@ -11,8 +11,9 @@ struct WithdrawTOSView: View {
 
     let navTitle = String(localized: "Terms of Service")
 
-    var exchangeBaseUrl: String
-    var model: WithdrawModel?
+    var exchangeBaseUrl: String?
+
+    @EnvironmentObject private var model: WalletModel
 
     @State var exchangeTOS: ExchangeTermsOfService?
     let viewID: Int         // either VIEW_WITHDRAW_TOS or SHEET_WITHDRAW_TOS
@@ -25,7 +26,7 @@ struct WithdrawTOSView: View {
             Content(symLog: symLog, exchangeTOS: exchangeTOS, myListStyle: 
$myListStyle) {
                 Task {
                     do {
-                        if let model {
+                        if let exchangeBaseUrl {
                             _ = try await 
model.setExchangeTOSAcceptedM(exchangeBaseUrl, etag: exchangeTOS!.currentEtag)
                             if acceptAction != nil {
                                 acceptAction!()
@@ -42,8 +43,14 @@ struct WithdrawTOSView: View {
             .navigationTitle(navTitle)
             .overlay {
                 if exchangeTOS == nil {
-                    WithdrawProgressView(message: exchangeBaseUrl.trimURL())
-                        .navigationTitle("Loading " + navTitle)
+                    if let exchangeBaseUrl {
+                        WithdrawProgressView(message: 
exchangeBaseUrl.trimURL())
+                            .navigationTitle("Loading " + navTitle)
+                    } else {
+                        // Yikes!
+                        WithdrawProgressView(message: "No exchangeBaseUrl!")
+                            .navigationTitle("Loading " + navTitle)
+                    }
                 }
             }
         }.onAppear() {
@@ -54,7 +61,7 @@ struct WithdrawTOSView: View {
             }
         }.task {
             do {
-                if let model {
+                if let exchangeBaseUrl {
                     let someTOS = try await 
model.loadExchangeTermsOfServiceM(exchangeBaseUrl)
                     exchangeTOS = someTOS
                 }
diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift 
b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
index 6f851ce..85779a7 100644
--- a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -16,7 +16,7 @@ struct WithdrawURIView: View {
     // the URL from the bank website
     let url: URL
 
-    let model = WithdrawModel.model(baseURL: "global")      // TODO: get 
baseURL from URL
+    @EnvironmentObject private var model: WalletModel
 
     // the exchange used for this withdrawal.
     @State private var exchangeBaseUrl: String? = nil
@@ -48,7 +48,7 @@ struct WithdrawURIView: View {
                 let tosAccepted = manualWithdrawalDetails.tosAccepted
                 if tosAccepted {
                     NavigationLink(destination: LazyView {
-                        WithdrawAcceptDone(exchangeBaseUrl: exchangeBaseUrl, 
model: model, url: url)
+                        WithdrawAcceptDone(exchangeBaseUrl: exchangeBaseUrl, 
url: url)
                     }) {
                         Text("Confirm Withdrawal")      // 
SHEET_WITHDRAW_ACCEPT
                     }.buttonStyle(TalerButtonStyle(type: .prominent))
@@ -56,7 +56,6 @@ struct WithdrawURIView: View {
                 } else {
                     NavigationLink(destination: LazyView {
                         WithdrawTOSView(exchangeBaseUrl: exchangeBaseUrl,
-                                                  model: model,
                                                  viewID: SHEET_WITHDRAW_TOS,
                                            acceptAction: nil)         // pop 
back to here
                     }) {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]