gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-ios] branch master updated (8804815 -> 022a1b3)


From: gnunet
Subject: [taler-taler-ios] branch master updated (8804815 -> 022a1b3)
Date: Fri, 02 Aug 2024 18:03:54 +0200

This is an automated email from the git hooks/post-receive script.

marc-stibane pushed a change to branch master
in repository taler-ios.

    from 8804815  cleanup, a11y
     new 487859d  Amounts can be with "-" or "+" sign, or without sign
     new 42d9e8e  Preview
     new e8bdb24  wording
     new c23dc30  German Localization
     new eba3a81  rename
     new 9b397c7  Add CURRENCY below Pay button
     new 5efb9f6  currencyInfo
     new d4666ce  cleanup
     new e8db80f  comments, cleanup
     new 3ff8de2  insufficient, disabled
     new 339e721  Fee
     new f4ea124  cancellationId
     new 0cddeb6  CopyShare for QR, with separate content
     new 01a50bc  sign of fee amount
     new 06242af  fix cancel
     new dff2354  rename
     new dac14b7  Compute fees
     new e765ec5  Convenience, cleanup
     new 0eb8c1d  WithdrawalDetails
     new 022a1b3  abortedHint

The 20 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 TalerWallet.xcodeproj/project.pbxproj              |  12 +-
 TalerWallet1/Controllers/Controller.swift          |   2 +-
 TalerWallet1/Localizable.xcstrings                 | 303 ++++++++++++++++-----
 TalerWallet1/Model/Model+Deposit.swift             |   8 +-
 TalerWallet1/Model/Model+P2P.swift                 |  15 +-
 TalerWallet1/Model/Model+Withdraw.swift            |   9 +-
 TalerWallet1/Model/Transaction.swift               |  28 +-
 TalerWallet1/Views/Balances/BalanceCellV.swift     |   2 +-
 TalerWallet1/Views/Banking/ManualWithdraw.swift    |   1 -
 TalerWallet1/Views/HelperViews/AmountInputV.swift  |  36 ++-
 TalerWallet1/Views/HelperViews/AmountRowV.swift    |   2 +-
 TalerWallet1/Views/HelperViews/AmountV.swift       |  12 +-
 .../Views/HelperViews/GradientBorder.swift         |   2 +-
 .../Views/HelperViews/QRCodeDetailView.swift       |   7 +-
 TalerWallet1/Views/Peer2peer/RequestPayment.swift  |  45 ++-
 TalerWallet1/Views/Peer2peer/SendAmount.swift      |  62 ++---
 .../Views/Sheets/P2P_Sheets/P2pPayURIView.swift    |   5 +-
 .../Sheets/P2P_Sheets/P2pReceiveURIView.swift      |   5 +-
 .../Views/Sheets/Payment/PayTemplateV.swift        |  26 +-
 .../Views/Sheets/Payment/PaymentView.swift         |  51 +++-
 .../WithdrawAcceptDone.swift                       |   2 +-
 .../WithdrawAcceptView.swift                       |   3 +-
 .../WithdrawBankIntegrated/WithdrawURIView.swift   |  10 +-
 .../Views/Transactions/ManualDetailsV.swift        |   3 +
 .../Views/Transactions/ThreeAmountsSection.swift   |  15 +-
 ...onDetailV.swift => TransactionPayDetailV.swift} |   4 +-
 .../Views/Transactions/TransactionRowView.swift    |   5 +-
 .../Views/Transactions/TransactionSummaryV.swift   |  38 ++-
 taler-swift/Sources/taler-swift/Time.swift         |  18 +-
 29 files changed, 509 insertions(+), 222 deletions(-)
 rename TalerWallet1/Views/Transactions/{TransactionDetailV.swift => 
TransactionPayDetailV.swift} (93%)

diff --git a/TalerWallet.xcodeproj/project.pbxproj 
b/TalerWallet.xcodeproj/project.pbxproj
index 1a01e3f..4555e17 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -165,8 +165,8 @@
                4E6EDD872A363D8D0031D520 /* ListStyle.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E6EDD862A363D8D0031D520 /* ListStyle.swift */; 
};
                4E6EF56B2B65A33300AF252A /* PaymentDone.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E6EF56A2B65A33300AF252A /* PaymentDone.swift 
*/; };
                4E6EF56C2B65A33300AF252A /* PaymentDone.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E6EF56A2B65A33300AF252A /* PaymentDone.swift 
*/; };
-               4E6EF56E2B669C7000AF252A /* TransactionDetailV.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4E6EF56D2B669C7000AF252A /* 
TransactionDetailV.swift */; };
-               4E6EF56F2B669C7000AF252A /* TransactionDetailV.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = 4E6EF56D2B669C7000AF252A /* 
TransactionDetailV.swift */; };
+               4E6EF56E2B669C7000AF252A /* TransactionPayDetailV.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4E6EF56D2B669C7000AF252A /* 
TransactionPayDetailV.swift */; };
+               4E6EF56F2B669C7000AF252A /* TransactionPayDetailV.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4E6EF56D2B669C7000AF252A /* 
TransactionPayDetailV.swift */; };
                4E753A062A0952F8002D9328 /* DebugViewC.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E753A052A0952F7002D9328 /* DebugViewC.swift */; 
};
                4E753A082A0B6A5F002D9328 /* ShareSheet.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E753A072A0B6A5F002D9328 /* ShareSheet.swift */; 
};
                4E77976F2C4BEA4E005D6ECB /* BalanceCellV.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4E77976E2C4BEA4E005D6ECB /* BalanceCellV.swift 
*/; };
@@ -388,7 +388,7 @@
                4E6EDD842A3615BE0031D520 /* ManualDetailsV.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ManualDetailsV.swift; sourceTree = "<group>"; };
                4E6EDD862A363D8D0031D520 /* ListStyle.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ListStyle.swift; sourceTree = "<group>"; };
                4E6EF56A2B65A33300AF252A /* PaymentDone.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
PaymentDone.swift; sourceTree = "<group>"; };
-               4E6EF56D2B669C7000AF252A /* TransactionDetailV.swift */ = {isa 
= PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
TransactionDetailV.swift; sourceTree = "<group>"; };
+               4E6EF56D2B669C7000AF252A /* TransactionPayDetailV.swift */ = 
{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
TransactionPayDetailV.swift; sourceTree = "<group>"; };
                4E753A042A08E720002D9328 /* transactions.json */ = {isa = 
PBXFileReference; lastKnownFileType = text.json; path = transactions.json; 
sourceTree = "<group>"; };
                4E753A052A0952F7002D9328 /* DebugViewC.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= DebugViewC.swift; sourceTree = "<group>"; };
                4E753A072A0B6A5F002D9328 /* ShareSheet.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ShareSheet.swift; sourceTree = "<group>"; };
@@ -788,7 +788,7 @@
                                4EB0952F2989CBFE0043A8A1 /* 
TransactionsListView.swift */,
                                4EB095302989CBFE0043A8A1 /* 
TransactionRowView.swift */,
                                4EB095312989CBFE0043A8A1 /* 
TransactionSummaryV.swift */,
-                               4E6EF56D2B669C7000AF252A /* 
TransactionDetailV.swift */,
+                               4E6EF56D2B669C7000AF252A /* 
TransactionPayDetailV.swift */,
                                4E87C8722A31CB7F001C6406 /* 
TransactionsEmptyView.swift */,
                                4E6EDD842A3615BE0031D520 /* 
ManualDetailsV.swift */,
                                4ED2F94A2A278F5100453B40 /* 
ThreeAmountsSection.swift */,
@@ -1242,7 +1242,7 @@
                                4EFA39602AA7946B00742548 /* ToSButtonView.swift 
in Sources */,
                                4E3EAE4F2A990778009F1BE8 /* TwoRowButtons.swift 
in Sources */,
                                4E3EAE502A990778009F1BE8 /* 
Model+Transactions.swift in Sources */,
-                               4E6EF56E2B669C7000AF252A /* 
TransactionDetailV.swift in Sources */,
+                               4E6EF56E2B669C7000AF252A /* 
TransactionPayDetailV.swift in Sources */,
                                4E3EAE512A990778009F1BE8 /* 
Controller+playSound.swift in Sources */,
                                4EE77E882C101F5B007C9064 /* 
OverviewSectionV.swift in Sources */,
                                4E3EAE522A990778009F1BE8 /* 
WalletEmptyView.swift in Sources */,
@@ -1371,7 +1371,7 @@
                                4EFA39612AA7946B00742548 /* ToSButtonView.swift 
in Sources */,
                                4EB065442A4CD1A80039B91D /* TwoRowButtons.swift 
in Sources */,
                                4EB095592989CBFE0043A8A1 /* 
Model+Transactions.swift in Sources */,
-                               4E6EF56F2B669C7000AF252A /* 
TransactionDetailV.swift in Sources */,
+                               4E6EF56F2B669C7000AF252A /* 
TransactionPayDetailV.swift in Sources */,
                                4E578E922A481D8600F21F1C /* 
Controller+playSound.swift in Sources */,
                                4EE77E892C101F5B007C9064 /* 
OverviewSectionV.swift in Sources */,
                                4EB0955F2989CBFE0043A8A1 /* 
WalletEmptyView.swift in Sources */,
diff --git a/TalerWallet1/Controllers/Controller.swift 
b/TalerWallet1/Controllers/Controller.swift
index a252e65..3ecdba3 100755
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -173,7 +173,7 @@ class Controller: ObservableObject {
         }
     }
 
-    func checkInfo(for baseUrl: String, model: WalletModel) async {
+    func checkCurrencyInfo(for baseUrl: String, model: WalletModel) async {
         if let exchange = await exchange(for: baseUrl, model: model) {
             let scope = exchange.scopeInfo
             for info in currencyInfos {
diff --git a/TalerWallet1/Localizable.xcstrings 
b/TalerWallet1/Localizable.xcstrings
index f412b9a..0e61c5e 100644
--- a/TalerWallet1/Localizable.xcstrings
+++ b/TalerWallet1/Localizable.xcstrings
@@ -1,6 +1,16 @@
 {
   "sourceLanguage" : "en",
   "strings" : {
+    "\nWarnings can be switched off in Settings" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "\\nWarnungen können in den Einstellungen ausgeschaltet 
werden"
+          }
+        }
+      }
+    },
     "- %@ fee" : {
       "localizations" : {
         "de" : {
@@ -34,6 +44,17 @@
         }
       }
     },
+    ". Needs bank authorization" : {
+      "comment" : "VoiceOver",
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : ". Benötigt die Autorisierung der Bank"
+          }
+        }
+      }
+    },
     ". Needs bank confirmation" : {
       "comment" : "VoiceOver",
       "localizations" : {
@@ -250,6 +271,16 @@
         }
       }
     },
+    "%@ fee" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "%@ Gebühr"
+          }
+        }
+      }
+    },
     "%lld characters of 100" : {
       "localizations" : {
         "de" : {
@@ -708,6 +739,7 @@
       }
     },
     "Amount to be withdrawn:" : {
+      "extractionState" : "stale",
       "localizations" : {
         "de" : {
           "stringUnit" : {
@@ -739,6 +771,16 @@
         }
       }
     },
+    "Amount to obtain:" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Zu erhaltender Betrag:"
+          }
+        }
+      }
+    },
     "Amount to pay:" : {
       "localizations" : {
         "de" : {
@@ -931,6 +973,17 @@
         }
       }
     },
+    "Authorize at Bank" : {
+      "comment" : "Nav title",
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Bei der Bank autorisieren"
+          }
+        }
+      }
+    },
     "Authorize later" : {
       "localizations" : {
         "de" : {
@@ -1185,40 +1238,6 @@
         }
       }
     },
-    "Confirm later" : {
-      "extractionState" : "stale",
-      "localizations" : {
-        "de" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "Später bestätigen"
-          }
-        },
-        "es" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "Confirmar después"
-          }
-        }
-      }
-    },
-    "Confirm now" : {
-      "extractionState" : "stale",
-      "localizations" : {
-        "de" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "Jetzt bestätigen"
-          }
-        },
-        "es" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "Confirmar ahora"
-          }
-        }
-      }
-    },
     "Confirm Payment" : {
       "comment" : "pay P2P request/invoice\npay merchant",
       "localizations" : {
@@ -1236,35 +1255,29 @@
         }
       }
     },
-    "Confirm with Bank" : {
-      "comment" : "Nav title",
+    "Confirm Withdrawal" : {
       "localizations" : {
         "de" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Mit der Bank bestätigen"
+            "value" : "Abhebung bestätigen"
           }
         },
         "es" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Confirmar con Banco"
+            "value" : "Confirmar Extracción"
           }
         }
       }
     },
-    "Confirm Withdrawal" : {
+    "Confirmation:" : {
+      "comment" : "purchase may have a pos validation / confirmation",
       "localizations" : {
         "de" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Abhebung bestätigen"
-          }
-        },
-        "es" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "Confirmar Extracción"
+            "value" : "Bestätigung:"
           }
         }
       }
@@ -1570,7 +1583,7 @@
       }
     },
     "DepositButton_Short" : {
-      "comment" : "Abbreviation of `Deposit (currency)´",
+      "comment" : "Abbreviation of button `Deposit (currency)´",
       "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
@@ -2004,18 +2017,38 @@
         }
       }
     },
-    "Exchange" : {
+    "Exchange fee (long):" : {
+      "comment" : "long version",
+      "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Service Provider"
+            "value" : "Gebühr:"
           }
         },
-        "es" : {
+        "en" : {
+          "stringUnit" : {
+            "state" : "new",
+            "value" : "Fee:"
+          }
+        }
+      }
+    },
+    "Exchange fee (short):" : {
+      "comment" : "short version",
+      "extractionState" : "extracted_with_value",
+      "localizations" : {
+        "de" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Proveedor de Pagos"
+            "value" : "Gebühr:"
+          }
+        },
+        "en" : {
+          "stringUnit" : {
+            "state" : "new",
+            "value" : "Fee:"
           }
         }
       }
@@ -2055,7 +2088,7 @@
     },
     "Fee (long):" : {
       "comment" : "long version",
-      "extractionState" : "extracted_with_value",
+      "extractionState" : "stale",
       "localizations" : {
         "de" : {
           "stringUnit" : {
@@ -2079,7 +2112,7 @@
     },
     "Fee (short):" : {
       "comment" : "short version",
-      "extractionState" : "extracted_with_value",
+      "extractionState" : "stale",
       "localizations" : {
         "de" : {
           "stringUnit" : {
@@ -2263,6 +2296,16 @@
         }
       }
     },
+    "It seems you wanted to request money - but this transaction will let you 
pay..." : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Es scheint als wollten Sie Geld anfordern - aber diese 
Transaktion lässt Sie bezahlen..."
+          }
+        }
+      }
+    },
     "KYC" : {
       "localizations" : {
         "de" : {
@@ -3084,6 +3127,16 @@
         }
       }
     },
+    "No payment fee" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Kein Zahlungsgebühr"
+          }
+        }
+      }
+    },
     "No withdrawal fee" : {
       "localizations" : {
         "de" : {
@@ -3100,7 +3153,18 @@
         }
       }
     },
+    "Note: It will take quite some time to prepare this amount! Be more 
patient..." : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Hinweis: Es braucht eine ganze Weile um diesen Betrag 
vorzubereiten. Seien Sie noch geduldiger..."
+          }
+        }
+      }
+    },
     "Note: It will take quite some time to withdraw this amount! Be more 
patient..." : {
+      "extractionState" : "stale",
       "localizations" : {
         "de" : {
           "stringUnit" : {
@@ -3116,7 +3180,18 @@
         }
       }
     },
+    "Note: It will take some time to prepare this amount. Be patient..." : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Hinweis: Es braucht eine Weile um diesen Betrag 
vorzubereiten. Seien Sie geduldig..."
+          }
+        }
+      }
+    },
     "Note: It will take some time to withdraw this amount. Be patient..." : {
+      "extractionState" : "stale",
       "localizations" : {
         "de" : {
           "stringUnit" : {
@@ -3148,6 +3223,17 @@
         }
       }
     },
+    "Obtain:" : {
+      "comment" : "Amount to obtain:",
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Erhalten:"
+          }
+        }
+      }
+    },
     "Obtained amount:" : {
       "localizations" : {
         "de" : {
@@ -3293,6 +3379,16 @@
         }
       }
     },
+    "Order-ID:" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Bestellnummer:"
+          }
+        }
+      }
+    },
     "P2P Ready" : {
       "localizations" : {
         "de" : {
@@ -3408,6 +3504,9 @@
           }
         }
       }
+    },
+    "Pay %@ now" : {
+
     },
     "Pay P2P" : {
       "comment" : "Nav Title",
@@ -3543,6 +3642,9 @@
           }
         }
       }
+    },
+    "Payment is made in %@" : {
+
     },
     "Payment provider:" : {
       "localizations" : {
@@ -3691,6 +3793,16 @@
         }
       }
     },
+    "Progress indicator" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Fortschrittsanzeige"
+          }
+        }
+      }
+    },
     "QR Code" : {
       "localizations" : {
         "de" : {
@@ -3992,31 +4104,31 @@
       }
     },
     "RequestButton_Full" : {
-      "comment" : "`Request Payment´ in Balances - set exactly 1 \\t for line 
break",
+      "comment" : "`Request (currency)´ in Balances - must have ONE \\t and 
ONE %@",
       "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Zahlung\tanfordern"
+            "value" : "%@\tanfordern"
           }
         },
         "en" : {
           "stringUnit" : {
             "state" : "new",
-            "value" : "Request\tPayment"
+            "value" : "Request\t%@"
           }
         },
         "es" : {
           "stringUnit" : {
-            "state" : "translated",
+            "state" : "needs_review",
             "value" : "Pedir\tPago"
           }
         }
       }
     },
     "RequestButton_Short" : {
-      "comment" : "Abbreviation of button `Request Payment´",
+      "comment" : "Abbreviation of button `Request (currency)´",
       "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
@@ -4284,31 +4396,31 @@
       }
     },
     "SendButton_Full" : {
-      "comment" : "`Send Money´ in Balances - set exactly 1 \\t for line 
break",
+      "comment" : "`Send (currency)´ in Balances - must have ONE \\t and ONE 
%@",
       "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
           "stringUnit" : {
             "state" : "translated",
-            "value" : "Geld\tsenden"
+            "value" : "%@\tsenden"
           }
         },
         "en" : {
           "stringUnit" : {
             "state" : "new",
-            "value" : "Send\tMoney"
+            "value" : "Send\t%@"
           }
         },
         "es" : {
           "stringUnit" : {
-            "state" : "translated",
+            "state" : "needs_review",
             "value" : "Enviar\tDinero"
           }
         }
       }
     },
     "SendButton_Short" : {
-      "comment" : "Abbreviation of button `Send Money´",
+      "comment" : "Abbreviation of button `Send (currency)´",
       "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
@@ -4527,7 +4639,18 @@
         }
       }
     },
+    "Status:" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Status:"
+          }
+        }
+      }
+    },
     "Status: %@" : {
+      "extractionState" : "stale",
       "localizations" : {
         "de" : {
           "stringUnit" : {
@@ -4657,6 +4780,16 @@
         }
       }
     },
+    "The exchange will send your money back if it won't get collected in time, 
or when you abort the operation." : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Die Exchange wird Ihr Geld zurücksenden wenn es nicht 
bis zum Ablaufdatum abgeholt wird, oder wenn Sie die Operation abbrechen."
+          }
+        }
+      }
+    },
     "The Payment Service Provider is waiting for your wire-transfer." : {
       "localizations" : {
         "de" : {
@@ -4753,6 +4886,16 @@
         }
       }
     },
+    "This request will be cancelled if it doesn't get paid in time, or when 
you abort the operation." : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Diese Anforderung wird abgebrochen wenn sie nicht bis 
zum Ablaufdatum bezahlt wird, oder wenn Sie die Operation abbrechen."
+          }
+        }
+      }
+    },
     "This transaction is not yet ready..." : {
       "localizations" : {
         "de" : {
@@ -5354,6 +5497,17 @@
         }
       }
     },
+    "using:" : {
+      "comment" : "using: exchange.taler.net",
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "mit:"
+          }
+        }
+      }
+    },
     "via %@" : {
       "localizations" : {
         "de" : {
@@ -5613,6 +5767,17 @@
         }
       }
     },
+    "Withdraw:" : {
+      "comment" : "Chosen amount to withdraw:",
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Abheben:"
+          }
+        }
+      }
+    },
     "Withdrawal" : {
       "comment" : "TransactionType",
       "localizations" : {
@@ -5631,7 +5796,7 @@
       }
     },
     "WithdrawButton_Short" : {
-      "comment" : "Abbreviation of `Withdraw (currency)´",
+      "comment" : "Abbreviation of button `Withdraw (currency)´",
       "extractionState" : "extracted_with_value",
       "localizations" : {
         "de" : {
@@ -5820,6 +5985,16 @@
           }
         }
       }
+    },
+    "Your bank's wire fee: %@" : {
+      "localizations" : {
+        "de" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Überweisungsgebühren ihrer Bank: %@"
+          }
+        }
+      }
     }
   },
   "version" : "1.0"
diff --git a/TalerWallet1/Model/Model+Deposit.swift 
b/TalerWallet1/Model/Model+Deposit.swift
index 417e828..0dcd0ff 100644
--- a/TalerWallet1/Model/Model+Deposit.swift
+++ b/TalerWallet1/Model/Model+Deposit.swift
@@ -42,11 +42,11 @@ struct CheckDepositResult: Codable {
 fileprivate struct CheckDeposit: WalletBackendFormattedRequest {
     typealias Response = CheckDepositResult
     func operation() -> String { "checkDeposit" }
-    func args() -> Args { Args(depositPaytoUri: depositPaytoUri, amount: 
amount, clientCancellationId: cancellationId) }
+    func args() -> Args { Args(depositPaytoUri: depositPaytoUri, amount: 
amount,
+                          clientCancellationId: "cancel") }
 
     var depositPaytoUri: String
     var amount: Amount
-    var cancellationId: String?
     struct Args: Encodable {
         var depositPaytoUri: String
         var amount: Amount
@@ -84,9 +84,9 @@ extension WalletModel {
 
     /// check fees for deposit. No Networking
     @MainActor    // M for MainActor
-    func checkDepositM(_ depositPaytoUri: String, amount: Amount, 
cancellationId: String? = nil, viewHandles: Bool = false)
+    func checkDepositM(_ depositPaytoUri: String, amount: Amount, viewHandles: 
Bool = false)
       async throws -> CheckDepositResult {
-          let request = CheckDeposit(depositPaytoUri: depositPaytoUri, amount: 
amount, cancellationId: cancellationId)
+          let request = CheckDeposit(depositPaytoUri: depositPaytoUri, amount: 
amount)
           let response = try await sendRequest(request, ASYNCDELAY, 
viewHandles: viewHandles)
           return response
     }
diff --git a/TalerWallet1/Model/Model+P2P.swift 
b/TalerWallet1/Model/Model+P2P.swift
index bacbf3e..22743a8 100644
--- a/TalerWallet1/Model/Model+P2P.swift
+++ b/TalerWallet1/Model/Model+P2P.swift
@@ -52,10 +52,9 @@ struct CheckPeerPushDebitResponse: Codable {
 fileprivate struct CheckPeerPushDebit: WalletBackendFormattedRequest {
     typealias Response = CheckPeerPushDebitResponse
     func operation() -> String { "checkPeerPushDebit" }
-    func args() -> Args { Args(amount: amount, clientCancellationId: 
cancellationId) }
+    func args() -> Args { Args(amount: amount, clientCancellationId: "cancel") 
}
 
     var amount: Amount
-    var cancellationId: String?
     struct Args: Encodable {
         var amount: Amount
         var clientCancellationId: String?
@@ -63,9 +62,9 @@ fileprivate struct CheckPeerPushDebit: 
WalletBackendFormattedRequest {
 }
 extension WalletModel {
     @MainActor          // M for MainActor
-    func checkPeerPushDebitM(_ amount: Amount, cancellationId: String? = nil, 
viewHandles: Bool = false)
+    func checkPeerPushDebitM(_ amount: Amount, viewHandles: Bool = false)
       async throws -> CheckPeerPushDebitResponse {
-        let request = CheckPeerPushDebit(amount: amount, cancellationId: 
cancellationId)
+        let request = CheckPeerPushDebit(amount: amount)
         let response = try await sendRequest(request, ASYNCDELAY, viewHandles: 
viewHandles)
         return response
     }
@@ -116,12 +115,11 @@ fileprivate struct CheckPeerPullCredit: 
WalletBackendFormattedRequest {
     typealias Response = CheckPeerPullCreditResponse
     func operation() -> String { "checkPeerPullCredit" }
     func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl, scopeInfo: 
scopeInfo,
-                                        amount: amount, clientCancellationId: 
cancellationId) }
+                                        amount: amount, clientCancellationId: 
"cancel") }
 
     var exchangeBaseUrl: String?
     var scopeInfo: ScopeInfo?
     var amount: Amount
-    var cancellationId: String?
     struct Args: Encodable {
         var exchangeBaseUrl: String?
         var scopeInfo: ScopeInfo?
@@ -132,11 +130,10 @@ fileprivate struct CheckPeerPullCredit: 
WalletBackendFormattedRequest {
 extension WalletModel {
     @MainActor           // M for MainActor
     func checkPeerPullCreditM(_ exchangeBaseUrl: String?, amount: Amount,
-                              cancellationId: String? = nil, viewHandles: Bool 
= false)
+                                    viewHandles: Bool = false)
       async throws -> CheckPeerPullCreditResponse {
         let request = CheckPeerPullCredit(exchangeBaseUrl: exchangeBaseUrl,
-                                                   amount: amount,
-                                           cancellationId: cancellationId)
+                                                   amount: amount)
         let response = try await sendRequest(request, ASYNCDELAY, viewHandles: 
viewHandles)
         return response
     }
diff --git a/TalerWallet1/Model/Model+Withdraw.swift 
b/TalerWallet1/Model/Model+Withdraw.swift
index 0bbc9ef..69f83bc 100644
--- a/TalerWallet1/Model/Model+Withdraw.swift
+++ b/TalerWallet1/Model/Model+Withdraw.swift
@@ -105,11 +105,11 @@ struct WithdrawalAmountDetails: Decodable {
 fileprivate struct GetWithdrawalDetailsForAmount: 
WalletBackendFormattedRequest {
     typealias Response = WithdrawalAmountDetails
     func operation() -> String { "getWithdrawalDetailsForAmount" }
-    func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl, amount: 
amount, clientCancellationId: cancellationId) }
+    func args() -> Args { Args(exchangeBaseUrl: exchangeBaseUrl, amount: 
amount,
+                          clientCancellationId: "cancel") }
 
     var exchangeBaseUrl: String
     var amount: Amount
-    var cancellationId: String?
     struct Args: Encodable {
         var exchangeBaseUrl: String
         var amount: Amount
@@ -248,11 +248,10 @@ extension WalletModel {
     }
     @MainActor                     // M for MainActor
     func getWithdrawalDetailsForAmountM(_ exchangeBaseUrl: String, amount: 
Amount,
-                                           cancellationId: String? = nil, 
viewHandles: Bool = false)
+                                              viewHandles: Bool = false)
       async throws -> WithdrawalAmountDetails {
         let request = GetWithdrawalDetailsForAmount(exchangeBaseUrl: 
exchangeBaseUrl,
-                                                             amount: amount,
-                                                     cancellationId: 
cancellationId)
+                                                             amount: amount)
         let response = try await sendRequest(request, ASYNCDELAY, viewHandles: 
viewHandles)
         return response
     }
diff --git a/TalerWallet1/Model/Transaction.swift 
b/TalerWallet1/Model/Transaction.swift
index 18d8866..259c468 100644
--- a/TalerWallet1/Model/Transaction.swift
+++ b/TalerWallet1/Model/Transaction.swift
@@ -333,7 +333,7 @@ struct TransactionCommon: Decodable, Sendable {
             || type == .scanPushCredit
     }
 }
-
+// MARK: - Withdrawal
 struct WithdrawalDetails: Decodable {
     enum WithdrawalType: String, Decodable {
         case manual = "manual-transfer"
@@ -343,9 +343,11 @@ struct WithdrawalDetails: Decodable {
     /// The public key of the reserve.
     var reservePub: String
     var reserveIsReady: Bool
+    var exchangeCreditAccountDetails: [WithdrawalExchangeAccountDetails]?
 
   /// Details for manual withdrawals:
-    var exchangeCreditAccountDetails: [WithdrawalExchangeAccountDetails]?
+    var reserveClosingDelay: RelativeTime?
+    var exchangePaytoUris: [String]?
 
   /// Details for bank-integrated withdrawals:
     /// Whether the bank has confirmed the withdrawal.
@@ -361,7 +363,7 @@ struct WithdrawalTransaction : Sendable {
     var common: TransactionCommon
     var details: WithdrawalTransactionDetails
 }
-
+// MARK: - Deposit
 struct TrackingState : Decodable {
     var wireTransferId: String
     var timestampExecuted: Timestamp
@@ -380,7 +382,7 @@ struct DepositTransaction : Sendable {
     var common: TransactionCommon
     var details: DepositTransactionDetails
 }
-
+// MARK: - Payment
 struct RefundInfo: Decodable {
     var amountEffective: Amount
     var amountRaw: Amount
@@ -401,7 +403,7 @@ struct PaymentTransaction : Sendable {
     var common: TransactionCommon
     var details: PaymentTransactionDetails
 }
-
+// MARK: - Refund
 struct RefundTransactionDetails: Decodable {
     var refundedTransactionId: String
     var refundPending: Amount?
@@ -409,11 +411,11 @@ struct RefundTransactionDetails: Decodable {
     var amountInvalid: Amount?
     var info: OrderShortInfo?       // TODO: is this still here?
 }
-struct RefundTransaction : Sendable{
+struct RefundTransaction : Sendable {
     var common: TransactionCommon
     var details: RefundTransactionDetails
 }
-
+// MARK: - Refresh
 enum RefreshReason: String, Decodable {
     case manual
     case payMerchant = "pay-merchant"
@@ -476,7 +478,7 @@ struct RefreshTransaction : Sendable {
     var common: TransactionCommon
     var details: RefreshTransactionDetails
 }
-
+// MARK: - P2P
 struct P2pShortInfo: Codable, Sendable {
     var summary: String
     var expiration: Timestamp
@@ -490,7 +492,7 @@ struct P2PTransaction : Sendable {
     var common: TransactionCommon
     var details: P2PTransactionDetails
 }
-
+// MARK: - Recoup
 struct RecoupTransactionDetails: Decodable {
     var recoupReason: String?
 }
@@ -498,7 +500,7 @@ struct RecoupTransaction : Sendable {
     var common: TransactionCommon
     var details: RecoupTransactionDetails
 }
-
+// MARK: - DenomLoss
 enum DenomLossEventType: String, Decodable {
     case denomExpired = "denom-expired"
     case denomVanished = "denom-vanished"
@@ -512,11 +514,11 @@ struct DenomLossTransaction : Sendable {
     var common: TransactionCommon
     var details: DenomLossTransactionDetails
 }
-
-struct DummyTransaction : Sendable{
+// MARK: - Dummy
+struct DummyTransaction : Sendable {
     var common: TransactionCommon
 }
-
+// MARK: - Transaction
 enum Transaction: Decodable, Hashable, Identifiable, Sendable {
     case dummy (DummyTransaction)
     case withdrawal (WithdrawalTransaction)
diff --git a/TalerWallet1/Views/Balances/BalanceCellV.swift 
b/TalerWallet1/Views/Balances/BalanceCellV.swift
index da6869d..a668e72 100644
--- a/TalerWallet1/Views/Balances/BalanceCellV.swift
+++ b/TalerWallet1/Views/Balances/BalanceCellV.swift
@@ -27,7 +27,7 @@ struct BalanceCellV: View {
         let amountV = AmountV(stack: stack?.push("AmountV"),
                        currencyInfo: $currencyInfo,
                              amount: amount,
-                         isNegative: false,
+                         isNegative: nil,           // don't show the + sign
                               large: true)
             .foregroundColor(.primary)
         let hLayout = amountV
diff --git a/TalerWallet1/Views/Banking/ManualWithdraw.swift 
b/TalerWallet1/Views/Banking/ManualWithdraw.swift
index 99e6aae..704e1f1 100644
--- a/TalerWallet1/Views/Banking/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Banking/ManualWithdraw.swift
@@ -132,7 +132,6 @@ struct ManualWithdraw: View {
                     do {
                         let details = try await 
model.getWithdrawalDetailsForAmountM(exchangeBaseUrl,
                                                                               
amount: amountToTransfer,
-                                                                      
cancellationId: "cancel",
                                                                          
viewHandles: true)
                         withdrawalAmountDetails = details
 //                      agePicker.setAges(ages: 
withdrawalAmountDetails?.ageRestrictionOptions)
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift 
b/TalerWallet1/Views/HelperViews/AmountInputV.swift
index 2ef7e75..d1b4f05 100644
--- a/TalerWallet1/Views/HelperViews/AmountInputV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountInputV.swift
@@ -14,6 +14,19 @@ struct ComputeFeeResult {
     let feeAmount: Amount?
     let feeStr: String
     let numCoins: Int?
+
+    static func zero() -> ComputeFeeResult {
+        ComputeFeeResult(insufficient: false,
+                            feeAmount: nil,
+                               feeStr: EMPTYSTRING,
+                             numCoins: 0)
+    }
+    static func insufficient() -> ComputeFeeResult {
+        ComputeFeeResult(insufficient: true,
+                            feeAmount: nil,
+                               feeStr: EMPTYSTRING,
+                             numCoins: -1)
+    }
 }
 
 struct AmountInputV: View {
@@ -47,23 +60,32 @@ struct AmountInputV: View {
         let disabled: Bool
     }
 
-    func checkAvailable(_ amount: Amount, _ coinData: CoinData) -> Flags {
+    func checkAvailable(_ coinData: CoinData) -> Flags {
+        let isZero = amountToTransfer.isZero
         if let amountAvailable {
             do {
-                let insufficient = try amount > amountAvailable
-                let disabled = insufficient || amount.isZero || 
coinData.invalid || coinData.tooMany
+                let insufficient: Bool
+                if let feeAmount {
+                    if feeIsNegative {
+                        insufficient = try amountToTransfer > amountAvailable
+                    } else {
+                        insufficient = try (amountToTransfer + feeAmount) > 
amountAvailable
+                    }
+                } else {
+                    insufficient = try amountToTransfer > amountAvailable
+                }
+                let disabled = insufficient || isZero || coinData.invalid || 
coinData.tooMany
                 return Flags(insufficient: insufficient, disabled: disabled)
             } catch {
                 // TODO: error Amounts don't match
             }
         }
-        return Flags(insufficient: false, disabled: amount.isZero)
+        return Flags(insufficient: false, disabled: isZero)
     }
 
     var body: some View {
         let currency = amountToTransfer.currencyStr
-//        let currencyInfo = controller.info(for: currency, 
controller.currencyTicker)
-        let insufficientLabel = String(localized: "You don't have enough 
\(currency).")
+//        let insufficientLabel = String(localized: "You don't have enough 
\(currency).")
         let available = amountAvailable?.formatted(currencyInfo, isNegative: 
false) ?? nil
         VStack(alignment: .trailing) {
             if summary.count > 0 {
@@ -92,7 +114,7 @@ struct AmountInputV: View {
                                coinData: coinData,
                           shouldShowFee: true,       // TODO: set to false if 
we never charge withdrawal fees
                           feeIsNegative: feeIsNegative)
-            let flags = checkAvailable(amountToTransfer, coinData)
+            let flags = checkAvailable(coinData)
             Button("Next") { buttonAction() }
                 .buttonStyle(TalerButtonStyle(type: .prominent, disabled: 
flags.disabled))
                 .disabled(flags.disabled)
diff --git a/TalerWallet1/Views/HelperViews/AmountRowV.swift 
b/TalerWallet1/Views/HelperViews/AmountRowV.swift
index 5149f6a..de10ee1 100644
--- a/TalerWallet1/Views/HelperViews/AmountRowV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountRowV.swift
@@ -14,7 +14,7 @@ struct AmountRowV: View {
     @Binding var currencyInfo: CurrencyInfo
     let title: String
     let amount: Amount
-    let isNegative: Bool        // if true, show a "-" before the amount
+    let isNegative: Bool?        // show fee with minus (or plus) sign, or no 
sign if nil
     let color: Color
     let large: Bool      // set to false for QR or IBAN
 
diff --git a/TalerWallet1/Views/HelperViews/AmountV.swift 
b/TalerWallet1/Views/HelperViews/AmountV.swift
index 274074d..e5ecafc 100644
--- a/TalerWallet1/Views/HelperViews/AmountV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountV.swift
@@ -12,13 +12,19 @@ struct AmountV: View {
     let stack: CallStack?
     @Binding var currencyInfo: CurrencyInfo
     let amount: Amount
-    let isNegative: Bool        // if true, show a "-" before the amount
+    let isNegative: Bool?        // if true, show a "-" before the amount
     let large: Bool             // set to false for QR or IBAN
 
     @EnvironmentObject private var controller: Controller
 
     var body: some View {
-        Text(amount.formatted(currencyInfo, isNegative: isNegative))
+        let dontShow = (isNegative == nil)
+        let showSign: Bool = isNegative ?? false
+        let amountFormatted = amount.formatted(currencyInfo, isNegative: false)
+        let amountStr = dontShow ?      amountFormatted
+                      : showSign ? "- \(amountFormatted)"
+                                 : "+ \(amountFormatted)"
+        Text(amountStr)
             .multilineTextAlignment(.center)
             .talerFont(large ? .title : .title2)
 //            .fontWeight(large ? .medium : .regular)       // @available(iOS 
16.0, *)
@@ -27,7 +33,7 @@ struct AmountV: View {
     }
 }
 extension AmountV {
-    init(_ currencyInfo: Binding<CurrencyInfo>, _ amount: Amount, isNegative: 
Bool) {
+    init(_ currencyInfo: Binding<CurrencyInfo>, _ amount: Amount, isNegative: 
Bool?) {
         self.stack = nil
         self._currencyInfo = currencyInfo
         self.amount = amount
diff --git a/TalerWallet1/Views/HelperViews/GradientBorder.swift 
b/TalerWallet1/Views/HelperViews/GradientBorder.swift
index 0a23954..29cb0a1 100644
--- a/TalerWallet1/Views/HelperViews/GradientBorder.swift
+++ b/TalerWallet1/Views/HelperViews/GradientBorder.swift
@@ -100,7 +100,7 @@ struct GradientBorder_Previews: PreviewProvider {
 //                  lineWidth: 2,
                       color: .blue,
                  background: .yellow) {
-            Text("Preview")
+            Text(verbatim: "Preview")
         }
     }
 }
diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift 
b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
index 283fcee..771936c 100644
--- a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
+++ b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
@@ -12,6 +12,7 @@ import AVFoundation
 
 struct QRCodeDetailView: View {
     let talerURI: String
+    let talerCopyShare: String
     let incoming: Bool
     let amount: Amount
 
@@ -36,7 +37,7 @@ struct QRCodeDetailView: View {
                     .talerFont(.title3)
 //                    .padding(.vertical)
                     .listRowSeparator(.hidden)
-                CopyShare(textToCopy: talerURI)
+                CopyShare(textToCopy: talerCopyShare)
                     .disabled(false)
 //                    .padding(.bottom)
                     .listRowSeparator(.hidden)
@@ -87,12 +88,12 @@ struct QRCodeDetailView: View {
 // MARK: -
 #if DEBUG
 fileprivate struct ContentView: View {
-    @State var talerURI: String = 
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520"
+    @State var previewURI: String = 
"taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520"
 
     var body: some View {
         let amount = Amount(currency: LONGCURRENCY, cent: 123)
         List {
-            QRCodeDetailView(talerURI: talerURI, incoming: false, amount: 
amount)
+            QRCodeDetailView(talerURI: previewURI, talerCopyShare: previewURI, 
incoming: false, amount: amount)
         }
     }
 }
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift 
b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
index 72da38d..7a72167 100644
--- a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -24,6 +24,7 @@ struct RequestPayment: View {
     @State private var peerPullCheck: CheckPeerPullCreditResponse? = nil
     @State private var expireDays: UInt = 0
 //    @State private var feeAmount: Amount? = nil
+    @State private var feeStr: String = EMPTYSTRING
     @State private var buttonSelected = false
     @State private var shortcutSelected = false
     @State private var amountShortcut = Amount.zero(currency: EMPTYSTRING)     
 // Update currency when used
@@ -33,8 +34,19 @@ struct RequestPayment: View {
         amountShortcut = shortcut
         shortcutSelected = true
     }
-    private func buttonAction() {
-        buttonSelected = true
+    private func buttonAction() { buttonSelected = true }
+
+    private func feeLabel(_ feeString: String) -> String {
+        feeString.count > 0 ? String(localized: "- \(feeString) fee")
+        : EMPTYSTRING
+    }
+
+    private func fee(raw: Amount, effective: Amount) -> Amount? {
+        do {     // Incoming: fee = raw - effective
+            let fee = try raw - effective
+            return fee
+        } catch {}
+        return nil
     }
 
     private func feeIsNotZero() -> Bool? {
@@ -53,13 +65,28 @@ struct RequestPayment: View {
             }
         }
         if amount.isZero {
-//            fee = EMPTYSTRING
-        } else {
+            return ComputeFeeResult.zero()
+        }
+        do {
             let baseURL = exchange?.exchangeBaseUrl
-            peerPullCheck = try? await model.checkPeerPullCreditM(baseURL, 
amount: amount,
-                                                                  
cancellationId: "cancel")
+            let ppCheck = try await model.checkPeerPullCreditM(baseURL, 
amount: amount)
+            let raw = ppCheck.amountRaw
+            let effective = ppCheck.amountEffective
+            if let fee = fee(raw: raw, effective: effective) {
+                feeStr = fee.formatted(currencyInfo, isNegative: true)
+                symLog.log("Fee = \(feeStr)")
 
-//            return ComputeFeeResult(insufficient: false, feeStr: 
feeLabel(feeStr), numCoins: details.numCoins)
+                peerPullCheck = ppCheck
+                return ComputeFeeResult(insufficient: false,
+                                           feeAmount: fee,
+                                              feeStr: feeLabel(feeStr),
+                                            numCoins: ppCheck.numCoins)
+            } else {
+                peerPullCheck = nil
+            }
+        } catch {
+            // handle cancel, errors
+            symLog.log("❗️ \(error)")
         }
         return nil
     }
@@ -101,7 +128,6 @@ struct RequestPayment: View {
                       summary: $summary,
                    expireDays: $expireDays)
         }
-        let disabled = amountToTransfer.isZero || coinData.invalid || 
coinData.tooMany
 
         ScrollView {
             let amountLabel = minimalistic ? String(localized: "Amount:")
@@ -148,8 +174,7 @@ struct RequestPayment: View {
 //            } else {
 //                let baseURL = exchange?.exchangeBaseUrl
 // //               peerPullCheck = try? await 
model.checkPeerPullCreditM(amountToTransfer, exchangeBaseUrl: nil)
-//                peerPullCheck = try? await 
model.checkPeerPullCreditM(baseURL, amount: amountToTransfer,
-//                                                                       
cancellationId: "cancel")
+//                peerPullCheck = try? await 
model.checkPeerPullCreditM(baseURL, amount: amountToTransfer)
 //            }
 //        }
     }
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift 
b/TalerWallet1/Views/Peer2peer/SendAmount.swift
index 87fb8a5..f700695 100644
--- a/TalerWallet1/Views/Peer2peer/SendAmount.swift
+++ b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -41,22 +41,17 @@ struct SendAmount: View {
         amountShortcut = shortcut
         shortcutSelected = true
     }
-    private func buttonAction() {
-        buttonSelected = true
-    }
+    private func buttonAction() { buttonSelected = true }
 
     private func feeLabel(_ feeString: String) -> String {
         feeString.count > 0 ? String(localized: "+ \(feeString) fee")
                             : EMPTYSTRING
     }
 
-    private func fee(ppCheck: CheckPeerPushDebitResponse?) -> Amount? {
-        do {
-            if let ppCheck {
-                // Outgoing: fee = effective - raw
-                let fee = try ppCheck.amountEffective - ppCheck.amountRaw
-                return fee
-            }
+    private func fee(raw: Amount, effective: Amount) -> Amount? {
+        do {     // Outgoing: fee = effective - raw
+            let fee = try effective - raw
+            return fee
         } catch {}
         return nil
     }
@@ -72,38 +67,35 @@ struct SendAmount: View {
     }
 
     private func computeFeeSend(_ amount: Amount) async -> ComputeFeeResult? {
-        if exchange == nil {
-            if let url = currencyInfo.scope.url {
-                exchange = try? await model.getExchangeByUrl(url: url)
-            }
+        if amount.isZero {
+            return ComputeFeeResult.zero()
         }
-        do {
-            insufficient = try amount > amountAvailable
-        } catch {
-            print("Yikes❗️ insufficient failed❗️")
-            insufficient = true
+        let insufficient = (try? amount > amountAvailable) ?? true
+        if insufficient {
+            return ComputeFeeResult.insufficient()
         }
+        do {
+            let ppCheck = try await model.checkPeerPushDebitM(amount, 
viewHandles: true)
+            let raw = ppCheck.amountRaw
+            let effective = ppCheck.amountEffective
+            if let fee = fee(raw: raw, effective: effective) {
+                feeStr = fee.formatted(currencyInfo, isNegative: false)
+                symLog.log("Fee = \(feeStr)")
+                let insufficient = (try? effective > amountAvailable) ?? true
 
-        if insufficient {
-//            announce("\(amountVoiceOver), \(insufficientLabel2)")
-        } else if amount.isZero {
-            feeStr = EMPTYSTRING
-        } else {
-            if let ppCheck = try? await 
model.checkPeerPushDebitM(amountToTransfer) {
-                // TODO: set from exchange
-//                agePicker.setAges(ages: peerPushCheck?.ageRestrictionOptions)
-                if let feeAmount = fee(ppCheck: ppCheck) {
-                    feeStr = feeAmount.formatted(currencyInfo, isNegative: 
false)
-                    let feeLabel = feeLabel(feeStr)
-//                    announce("\(amountVoiceOver), \(feeLabel)")
-                } else {
-                    feeStr = EMPTYSTRING
-//                    announce(amountVoiceOver)
-                }
                 peerPushCheck = ppCheck
+                let feeLabel = feeLabel(feeStr)
+//                announce("\(amountVoiceOver), \(feeLabel)")
+                return ComputeFeeResult(insufficient: insufficient,
+                                           feeAmount: fee,
+                                              feeStr: feeLabel,
+                                            numCoins: nil)
             } else {
                 peerPushCheck = nil
             }
+        } catch {
+            // handle cancel, errors
+            symLog.log("❗️ \(error)")
         }
         return nil
     }
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift 
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
index 82e948f..4ba8dbf 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
@@ -38,13 +38,14 @@ struct P2pPayURIView: View {
                                  currencyInfo: $currencyInfo,
                                      topTitle: String(localized: "Amount to 
pay:"),
                                     topAbbrev: String(localized: "Pay:", 
comment: "mini"),
-                                    topAmount: raw, fee: fee,
+                                    topAmount: raw,
+                                       noFees: nil,        // TODO: check 
baseURL for fees
+                                          fee: fee,
                                   bottomTitle: String(localized: "Amount to be 
spent:"),
                                  bottomAbbrev: String(localized: "Effective:", 
comment: "mini"),
                                  bottomAmount: effective,
                                         large: false, pending: false, 
incoming: false,
                                       baseURL: nil,
-                                       noFees: nil,        // TODO: check 
baseURL for fees
                                    txStateLcl: nil,
                                       summary: 
peerPullDebitResponse.contractTerms.summary,
                                      merchant: nil)
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift 
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
index a9d221b..24f8dd2 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
@@ -47,13 +47,14 @@ struct P2pReceiveURIView: View {
                                  currencyInfo: $currencyInfo,
                                      topTitle: String(localized: "Gross Amount 
to receive:"),
                                     topAbbrev: String(localized: "Receive 
gross:", comment: "mini"),
-                                    topAmount: raw, fee: fee,
+                                    topAmount: raw,
+                                       noFees: nil,        // TODO: check 
baseURL for fees
+                                          fee: fee,
                                   bottomTitle: String(localized: "Net Amount 
to receive:"),
                                  bottomAbbrev: String(localized: "Receive 
net:", comment: "mini"),
                                  bottomAmount: effective,
                                         large: false, pending: false, 
incoming: true,
                                       baseURL: nil,
-                                       noFees: nil,        // TODO: check 
baseURL for fees
                                    txStateLcl: nil,
                                       summary: 
peerPushCreditResponse.contractTerms.summary,
                                      merchant: nil)
diff --git a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift 
b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
index 5e0d686..fc3218b 100644
--- a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
@@ -159,14 +159,14 @@ struct PayTemplateV: View {
                             .background(NavigationLink(destination: 
finalDestinationI, isActive: $buttonSelected1)
                                         { EmptyView() }.frame(width: 
0).opacity(0).hidden())
                     }
-                } // ScrollView
+                } // amountInput
             } else if summaryIsEditable {   // template contract summary is 
not fixed => let the user input a summary
                 ScrollView {
                     inputDestination
                         .background(NavigationLink(destination: 
finalDestinationI, isActive: $buttonSelected2)
                                     { EmptyView() }.frame(width: 
0).opacity(0).hidden()
                         )
-                }
+                } // inputDestination
             } else {    // both template contract amount and summary are fixed 
=> directly show the payment
                 // Attention: contains a List, thus mustn't be included in a 
ScrollView
                 PaymentView(stack: stack.push(),
@@ -177,18 +177,18 @@ struct PayTemplateV: View {
                  amountIsEditable: amountIsEditable,
                 summaryIsEditable: summaryIsEditable)
             }
-          }.navigationTitle(navTitle)
-          .frame(maxWidth: .infinity, alignment: .leading)
-          
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
-          .task(id: controller.currencyTicker) {
-              let currency = amountToTransfer.currencyStr
-              currencyInfo = controller.info(for: currency, 
controller.currencyTicker)
+          } .navigationTitle(navTitle)
+            .frame(maxWidth: .infinity, alignment: .leading)
+            
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+            .task(id: controller.currencyTicker) {
+                let currency = amountToTransfer.currencyStr
+                currencyInfo = controller.info(for: currency, 
controller.currencyTicker)
 //                currencyName = currencyInfo.scope.currency
-          }
-          .onAppear() {
-              symLog.log("onAppear")
-              DebugViewC.shared.setSheetID(SHEET_PAY_TEMPLATE)
-          }
+            }
+            .onAppear() {
+                symLog.log("onAppear")
+                DebugViewC.shared.setSheetID(SHEET_PAY_TEMPLATE)
+            }
         } else {
             LoadingView(scopeInfo: nil, message: url.host)
                 .task {
diff --git a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift 
b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
index 994354b..f1ce7d4 100644
--- a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
@@ -88,15 +88,29 @@ struct PaymentView: View {
 
     let navTitle = String(localized: "Confirm Payment", comment:"pay merchant")
 
+    func checkCurrencyInfo(for result: PreparePayResult) async {
+        let exchanges = result.contractTerms.exchanges
+        for exchange in exchanges {
+            let baseUrl = exchange.url
+            if let someExchange = try? await model.getExchangeByUrl(url: 
baseUrl) {
+                symLog.log("\(baseUrl.trimURL()) loaded")
+                await controller.checkCurrencyInfo(for: baseUrl, model: model)
+                symLog.log("Info(for: \(baseUrl.trimURL())) loaded")
+                return
+            }
+        }
+        symLog.log("Couldn't load Info(for: \(result.amountRaw.currencyStr))")
+    }
+
     var body: some View {
       Group {
         if let preparePayResult {
+            let raw = preparePayResult.amountRaw
             let effective = preparePayResult.amountEffective
             let terms = preparePayResult.contractTerms
             List {
                 // TODO: show balanceDetails.balanceAvailable
                 let baseURL = 
preparePayResult.contractTerms.exchanges.first?.url
-                let raw = preparePayResult.amountRaw
                 let status = preparePayResult.status
                 let currency = raw.currencyStr
                 let topTitle = String(localized: "Amount to pay:")
@@ -108,7 +122,9 @@ struct PaymentView: View {
                                  currencyInfo: $currencyInfo,
                                      topTitle: topTitle,
                                     topAbbrev: topAbbrev,
-                                    topAmount: raw, fee: fee,
+                                    topAmount: raw,
+                                       noFees: nil,        // TODO: check 
baseURL for fees
+                                          fee: fee,
                                   bottomTitle: String(localized: "Amount to 
spend:"),
                                  bottomAbbrev: String(localized: "Effective:", 
comment: "mini"),
                                  bottomAmount: effective,
@@ -116,7 +132,6 @@ struct PaymentView: View {
                                       pending: false,
                                      incoming: false,
                                       baseURL: baseURL,
-                                       noFees: nil,        // TODO: check 
baseURL for fees
                                    txStateLcl: nil,
                                       summary: terms.summary,
                                      merchant: terms.merchant.name)
@@ -128,7 +143,9 @@ struct PaymentView: View {
                                  currencyInfo: $currencyInfo,
                                      topTitle: topTitle,
                                     topAbbrev: topAbbrev,
-                                    topAmount: raw, fee: nil,
+                                    topAmount: raw,
+                                       noFees: nil,        // TODO: check 
baseURL for fees
+                                          fee: nil,
                                   bottomTitle: String(localized: "Amount 
available:"),
                                  bottomAbbrev: String(localized: "Available:", 
comment: "mini"),
                                  bottomAmount: balanceDetails.balanceAvailable,
@@ -136,7 +153,6 @@ struct PaymentView: View {
                                       pending: false,
                                      incoming: false,
                                       baseURL: baseURL,
-                                       noFees: nil,        // TODO: check 
baseURL for fees
                                    txStateLcl: nil,
                                       summary: terms.summary,
                                      merchant: terms.merchant.name)
@@ -149,15 +165,20 @@ struct PaymentView: View {
             .listStyle(myListStyle.style).anyView
             .safeAreaInset(edge: .bottom) {
                 if let effective {
-                    NavigationLink(destination: LazyView {
-                        PaymentDone(stack: stack.push(),
-                             currencyInfo: $currencyInfo,
-                            transactionId: preparePayResult.transactionId)
-                    }) {
-                        Text(navTitle)      // Confirm Payment
+                    VStack {
+                        NavigationLink(destination: LazyView {
+                            PaymentDone(stack: stack.push(),
+                                 currencyInfo: $currencyInfo,
+                                transactionId: preparePayResult.transactionId)
+                        }) {
+                            let formatted = raw.formatted(currencyInfo, 
isNegative: false)
+                            Text("Pay \(formatted) now")
+                        }
+                            .buttonStyle(TalerButtonStyle(type: .prominent))
+                            .padding(.horizontal)
+                        Text("Payment is made in 
\(currencyInfo.scope.currency)")
+                            .talerFont(.callout)
                     }
-                    .buttonStyle(TalerButtonStyle(type: .prominent))
-                    .padding(.horizontal)
                 } else {
                     Button("Cancel", action: {
                         dismissTop(stack.push())
@@ -170,6 +191,7 @@ struct PaymentView: View {
             .task(id: controller.currencyTicker) {
                 let currency = amountToTransfer.currencyStr
                 currencyInfo = controller.info(for: currency, 
controller.currencyTicker)
+                symLog.log("Info(for: \(currency)) loaded: 
\(currencyInfo.scope.currency)")
 //                currencyName = currencyInfo.scope.currency
             }
         } else {
@@ -180,10 +202,13 @@ struct PaymentView: View {
                     if let result = try? await 
model.preparePayForTemplateM(url.absoluteString,
                                                                      amount: 
amountIsEditable ? amountToTransfer : nil,
                                                                     summary: 
summaryIsEditable ? summary : nil) {
+                        await checkCurrencyInfo(for: result)
                         preparePayResult = result
                     }
                 } else {
                     if let result = try? await 
model.preparePayForUriM(url.absoluteString) {
+                        amountToTransfer = result.amountRaw
+                        await checkCurrencyInfo(for: result)
                         preparePayResult = result
                     }
                 }
diff --git 
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift 
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
index 04fc01d..459fa84 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptDone.swift
@@ -24,7 +24,7 @@ struct WithdrawAcceptDone: View {
     @State private var transactionId: String? = nil
     @State private var transaction: Transaction? = nil
 
-    let navTitle = String(localized: "Authorize with Bank", comment: "Nav 
title")
+    let navTitle = String(localized: "Authorize at Bank", comment: "Nav title")
 
     func reloadOneAction(_ transactionId: String, viewHandles: Bool) async 
throws -> Transaction {
         let response = try await model.getTransactionByIdT(transactionId, 
viewHandles: viewHandles)
diff --git 
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift 
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift
index 65277ca..684f0fe 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift
@@ -60,7 +60,9 @@ struct WithdrawAcceptView: View {
                                      topTitle: String(localized: "Chosen 
amount to withdraw:"),
                                     topAbbrev: String(localized: "Withdraw:", 
comment: "Chosen amount to withdraw:"),
                                     topAmount: raw,
+                                       noFees: exchange.noFees,
                                           fee: fee,
+                                feeIsNegative: true,
                                   bottomTitle: String(localized: "Amount to 
obtain:"),
                                  bottomAbbrev: String(localized: "Obtain:", 
comment: "Amount to obtain:"),
                                  bottomAmount: effective,
@@ -68,7 +70,6 @@ struct WithdrawAcceptView: View {
                                       pending: false,
                                      incoming: true,
                                       baseURL: exchange.exchangeBaseUrl,
-                                       noFees: exchange.noFees,
                                    txStateLcl: nil,        // 
common.txState.major.localizedState
                                       summary: nil,
                                      merchant: nil)
diff --git 
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift 
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
index 6f25caa..d783a5d 100755
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -11,7 +11,7 @@ import SymLog
 
 // Called either when scanning a QR code or tapping the provided link, both 
from the bank's website.
 // We show the user the bank-integrated withdrawal details in a sheet - but 
first the ToS must be accepted.
-// After the user confirmed the withdrawal, we show a button to return to the 
bank website to confirm there, too
+// After the user confirmed the withdrawal, we show a button to return to the 
bank website to authorize (2FA)
 struct WithdrawURIView: View {
     private let symLog = SymLogV()
     let stack: CallStack
@@ -57,9 +57,7 @@ struct WithdrawURIView: View {
         amountShortcut = shortcut
         shortcutSelected = true
     }
-    private func buttonAction() {
-        buttonSelected = true
-    }
+    private func buttonAction() { buttonSelected = true }
 
     private func feeLabel(_ feeString: String) -> String {
         feeString.count > 0 ? String(localized: "\(feeString) fee")
@@ -188,7 +186,7 @@ struct WithdrawURIView: View {
             let message: String? = nil
 #endif
             LoadingView(scopeInfo: nil, message: message)
-                .task {
+                .task { // this runs only once
                     symLog.log(".task")
                     if let uriInfoResponse = try? await 
model.getWithdrawalDetailsForUriM(url.absoluteString) {
                         let amount = uriInfoResponse.amount
@@ -203,7 +201,7 @@ struct WithdrawURIView: View {
                         possibleExchanges = uriInfoResponse.possibleExchanges
                         await loadExchange(baseUrl)
                         symLog.log("\(baseUrl.trimURL()) loaded")
-                        await controller.checkInfo(for: baseUrl, model: model)
+                        await controller.checkCurrencyInfo(for: baseUrl, 
model: model)
                         symLog.log("Info(for: \(baseUrl.trimURL())) loaded")
                     }
 
diff --git a/TalerWallet1/Views/Transactions/ManualDetailsV.swift 
b/TalerWallet1/Views/Transactions/ManualDetailsV.swift
index c33c3b6..12d78ff 100644
--- a/TalerWallet1/Views/Transactions/ManualDetailsV.swift
+++ b/TalerWallet1/Views/Transactions/ManualDetailsV.swift
@@ -209,6 +209,9 @@ struct ManualDetailsV: View {
                                 .frame(maxWidth: .infinity, alignment: .center)
                                 .accessibilityLabel("QR Code")
                                 .listRowSeparator(.hidden)
+                            CopyShare(textToCopy: spec.qrContent)
+                                .disabled(false)
+//                    .padding(.bottom)
 
 //                            Text(specDetails)
 //                                .listRowSeparator(.automatic)
diff --git a/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift 
b/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift
index a0c2182..2579fd8 100644
--- a/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift
+++ b/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift
@@ -8,7 +8,7 @@
 import SwiftUI
 import taler_swift
 
-struct ThreeAmountsSheet: View {
+struct ThreeAmountsSheet: View {    // should be in a separate file
     let stack: CallStack
     @Binding var currencyInfo: CurrencyInfo
     var common: TransactionCommon
@@ -18,6 +18,7 @@ struct ThreeAmountsSheet: View {
     var bottomAbbrev: String?
     let baseURL: String?
     let noFees: Bool?                       // true if exchange charges no 
fees at all
+    var feeIsNegative: Bool?                // show fee with minus (or plus) 
sign, or no sign if nil
     let large: Bool               // set to false for QR or IBAN
     let summary: String?
     let merchant: String?
@@ -53,7 +54,9 @@ struct ThreeAmountsSheet: View {
                          topTitle: topTitle,
                         topAbbrev: topAbbrev,
                         topAmount: raw,
+                           noFees: noFees,
                               fee: fee,
+                    feeIsNegative: feeIsNegative,
                       bottomTitle: bottomTitle ?? defaultBottomTitle,
                      bottomAbbrev: bottomAbbrev ?? defaultBottomAbbrev,
                      bottomAmount: incomplete ? nil : effective,
@@ -61,7 +64,6 @@ struct ThreeAmountsSheet: View {
                           pending: pending,
                          incoming: incoming,
                           baseURL: baseURL,
-                           noFees: noFees,
                        txStateLcl: txStateLcl,
                           summary: summary,
                          merchant: merchant)
@@ -74,7 +76,9 @@ struct ThreeAmountsSection: View {
     var topTitle: String
     var topAbbrev: String
     var topAmount: Amount
+    let noFees: Bool?                       // true if exchange charges no 
fees at all
     var fee: Amount?                        // nil = don't show fee line, zero 
= no fee for this tx
+    var feeIsNegative: Bool?                // show fee with minus (or plus) 
sign, or no sign if nil
     var bottomTitle: String
     var bottomAbbrev: String
     var bottomAmount: Amount?               // nil = incomplete (aborted, 
timed out)
@@ -82,7 +86,6 @@ struct ThreeAmountsSection: View {
     let pending: Bool
     let incoming: Bool
     let baseURL: String?
-    let noFees: Bool?                       // true if exchange charges no 
fees at all
     let txStateLcl: String?                 // localizedState
     let summary: String?
     let merchant: String?
@@ -113,7 +116,7 @@ struct ThreeAmountsSection: View {
                 currencyInfo: $currencyInfo,
                        title: minimalistic ? topAbbrev : topTitle,
                       amount: topAmount,
-                  isNegative: !incoming,
+                  isNegative: nil,
                        color: labelColor,
                        large: false)
                 .padding(.bottom, 4)
@@ -125,7 +128,7 @@ struct ThreeAmountsSection: View {
                         currencyInfo: $currencyInfo,
                                title: title,
                               amount: fee,
-                          isNegative: !incoming,
+                          isNegative: fee.isZero ? nil : feeIsNegative,
                                color: labelColor,
                                large: false)
                     .padding(.bottom, 4)
@@ -135,7 +138,7 @@ struct ThreeAmountsSection: View {
                         currencyInfo: $currencyInfo,
                                title: minimalistic ? bottomAbbrev : 
bottomTitle,
                               amount: bottomAmount,
-                          isNegative: !incoming,
+                          isNegative: nil,
                                color: foreColor,
                                large: large)
                 }
diff --git a/TalerWallet1/Views/Transactions/TransactionDetailV.swift 
b/TalerWallet1/Views/Transactions/TransactionPayDetailV.swift
similarity index 93%
rename from TalerWallet1/Views/Transactions/TransactionDetailV.swift
rename to TalerWallet1/Views/Transactions/TransactionPayDetailV.swift
index 535dd6a..2079eda 100755
--- a/TalerWallet1/Views/Transactions/TransactionDetailV.swift
+++ b/TalerWallet1/Views/Transactions/TransactionPayDetailV.swift
@@ -9,7 +9,7 @@
  */
 import SwiftUI
 
-struct TransactionDetailV: View {
+struct TransactionPayDetailV: View {
     let paymentTx: PaymentTransaction
 
     var body: some View {
@@ -18,7 +18,7 @@ struct TransactionDetailV: View {
         let info = details.info
         Section {
             if let posConfirmation = details.posConfirmation {
-                Text("Confirmation:")
+                Text("Confirmation:", comment: "purchase may have a pos 
validation / confirmation")
                     .talerFont(.title3)
                     .listRowSeparator(.hidden)
                 Text(posConfirmation)
diff --git a/TalerWallet1/Views/Transactions/TransactionRowView.swift 
b/TalerWallet1/Views/Transactions/TransactionRowView.swift
index 714b110..e4c7c92 100644
--- a/TalerWallet1/Views/Transactions/TransactionRowView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionRowView.swift
@@ -46,7 +46,8 @@ struct TransactionRowView: View {
                : colorScheme == .dark ? .secondary
                   : increasedContrast ? Color(.darkGray)
                                       : .secondary  // Color(.tertiaryLabel)
-        let refreshZero = common.type.isRefresh && 
common.amountEffective.isZero
+        let isZero = common.amountEffective.isZero
+        let refreshZero = common.type.isRefresh && isZero
         let foreColor = refreshZero ? textColor
                           : pending ? WalletColors().pendingColor(incoming)
                              : done ? WalletColors().transactionColor(incoming)
@@ -55,7 +56,7 @@ struct TransactionRowView: View {
         let iconBadge = TransactionIconBadge(type: common.type, foreColor: 
foreColor,
                                              done: done, incoming: incoming,
                                     shouldConfirm: shouldConfirm, needsKYC: 
needsKYC)
-        let amountV = AmountV($currencyInfo, common.amountEffective, 
isNegative: !incoming)
+        let amountV = AmountV($currencyInfo, common.amountEffective, 
isNegative: isZero ? nil : !incoming)
             .foregroundColor(foreColor)
 
         let topString = topString()
diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift 
b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
index 64e07d7..8c8b677 100755
--- a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
+++ b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
@@ -288,6 +288,19 @@ struct TransactionSummaryV: View {
             return nil
         }
 
+        func abortedHint(_ delay: RelativeTime?) -> String? {
+            if let delay {
+                if let microseconds = try? delay.microseconds() {
+                    let days = microseconds / (24 * 3600 * 1000 * 1000)
+                    if days > 0 {
+                        return String(days)
+                    }
+                }
+                return "a few"
+            }
+            return nil
+        }
+
         var body: some View {
             let common = transaction.common
             let pending = transaction.isPending
@@ -302,6 +315,12 @@ struct TransactionSummaryV: View {
                             // has its own accessibilityLabel
                     case .withdrawal(let withdrawalTransaction): Group {
                         let details = withdrawalTransaction.details
+                        if common.isAborted && details.withdrawalDetails.type 
== .manual {
+                            if let dayStr = 
abortedHint(details.withdrawalDetails.reserveClosingDelay) {
+                                Text("The withdrawal was aborted.\nIf you have 
already sent money to the exchange, it will wire it back in \(dayStr) days.")
+                                    .talerFont(.callout)
+                            }
+                        }
                         if pending {
                             PendingWithdrawalDetails(transaction: 
$transaction, details: details)
                         } // ManualDetails or Confirm now (with bank)
@@ -312,6 +331,7 @@ struct TransactionSummaryV: View {
                                        topTitle: String(localized: "Chosen 
amount to withdraw:"),
                                         baseURL: details.exchangeBaseUrl,
                                          noFees: nil,               // TODO: 
noFees
+                                  feeIsNegative: true,
                                           large: false,
                                         summary: nil,
                                        merchant: nil)
@@ -325,13 +345,14 @@ struct TransactionSummaryV: View {
                                        topTitle: String(localized: "Amount to 
deposit:"),
                                         baseURL: nil,               // TODO: 
baseURL
                                          noFees: nil,               // TODO: 
noFees
+                                  feeIsNegative: false,
                                           large: true,
                                         summary: nil,
                                        merchant: nil)
                     }
                     case .payment(let paymentTransaction): Group {
                         let details = paymentTransaction.details
-                        TransactionDetailV(paymentTx: paymentTransaction)
+                        TransactionPayDetailV(paymentTx: paymentTransaction)
                         ThreeAmountsSheet(stack: stack.push(),
                                    currencyInfo: $currencyInfo,
                                          common: common,
@@ -339,6 +360,7 @@ struct TransactionSummaryV: View {
                                        topTitle: String(localized: "Price 
(net):"),
                                         baseURL: nil,               // TODO: 
baseURL
                                          noFees: nil,               // TODO: 
noFees
+                                  feeIsNegative: false,
                                           large: true,
                                         summary: details.info.summary,
                                        merchant: details.info.merchant.name)
@@ -352,6 +374,7 @@ struct TransactionSummaryV: View {
                                        topTitle: String(localized: "Refunded 
amount:"),
                                         baseURL: nil,               // TODO: 
baseURL
                                          noFees: nil,               // TODO: 
noFees
+                                  feeIsNegative: true,
                                           large: true,
                                         summary: details.info?.summary,
                                        merchant: details.info?.merchant.name)
@@ -368,7 +391,7 @@ struct TransactionSummaryV: View {
                                 currencyInfo: $currencyInfo,
                                        title: minimalistic ? "Refreshed:" : 
"Refreshed amount:",
                                       amount: input,
-                                  isNegative: false,
+                                  isNegative: nil,
                                        color: labelColor,
                                        large: true)
                             if let fee = refreshFee(input: input, output: 
details.refreshOutputAmount) {
@@ -376,7 +399,7 @@ struct TransactionSummaryV: View {
                                     currencyInfo: $currencyInfo,
                                            title: minimalistic ? "Fee:" : 
"Refreshed fee:",
                                           amount: fee,
-                                      isNegative: !fee.isZero,
+                                      isNegative: fee.isZero ? nil : true,
                                            color: labelColor,
                                            large: true)
                             }
@@ -440,7 +463,9 @@ struct TransactionSummaryV: View {
                                          common: common,
                                       topAbbrev: localizedType + colon,
                                        topTitle: localizedType + colon,
-                                        baseURL: details.exchangeBaseUrl, 
noFees: nil,         // TODO: noFees
+                                        baseURL: details.exchangeBaseUrl,
+                                         noFees: nil,         // TODO: noFees
+                                  feeIsNegative: true,
                                           large: false,
                                         summary: details.info.summary,
                                        merchant: nil)
@@ -455,6 +480,7 @@ struct TransactionSummaryV: View {
                                        topTitle: String(localized: "Recoup:"),
                                         baseURL: nil,
                                          noFees: nil,
+                                  feeIsNegative: nil,
                                           large: true,             // TODO: 
baseURL, noFees
                                         summary: nil,
                                        merchant: nil)
@@ -468,6 +494,7 @@ struct TransactionSummaryV: View {
                                        topTitle: String(localized: "Money 
lost:"),
                                         baseURL: details.exchangeBaseUrl,
                                          noFees: nil,
+                                  feeIsNegative: nil,
                                           large: true,             // TODO: 
baseURL, noFees
                                         summary: 
details.lossEventType.rawValue,
                                        merchant: nil)
@@ -486,6 +513,7 @@ struct TransactionSummaryV: View {
                 if let talerURI = details[TALERURI] {
                     if talerURI.count > 10 {
                         QRCodeDetailView(talerURI: talerURI,
+                                   talerCopyShare: talerURI,
                                          incoming: transaction.isP2pIncoming,
                                            amount: 
transaction.common.amountRaw)
                     }
@@ -499,7 +527,7 @@ struct TransactionSummaryV: View {
             }
         }
     }
-}
+} // TransactionSummaryV
 // MARK: -
 #if DEBUG
 //struct TransactionSummary_Previews: PreviewProvider {
diff --git a/taler-swift/Sources/taler-swift/Time.swift 
b/taler-swift/Sources/taler-swift/Time.swift
index 084ad09..0eee5ee 100644
--- a/taler-swift/Sources/taler-swift/Time.swift
+++ b/taler-swift/Sources/taler-swift/Time.swift
@@ -59,8 +59,17 @@ public enum RelativeTime: Codable, Hashable, Sendable {
     }
 }
 
-
-
+extension RelativeTime {
+    public func microseconds() throws -> UInt64 {
+        switch self {
+            case .microseconds(let d_us):
+                return d_us
+            case .forever:
+                throw TimestampError.invalidUInt64Value
+        }
+    }
+}
+// MARK: -
 /// A point in time, represented by milliseconds from January 1, 1970..
 public enum Timestamp: Codable, Hashable, Sendable {
     case milliseconds(UInt64)
@@ -129,7 +138,6 @@ extension Timestamp {
         return Timestamp.milliseconds(now + (UInt64(minutes) * seconds * 1000))
     }
 
-
     /// convenience initializer from UInt64 (milliseconds from January 1, 1970)
     public init(from: UInt64) {
         self = Timestamp.milliseconds(from)
@@ -145,7 +153,7 @@ extension Timestamp {
         }
     }
 }
-
+// MARK: -
 /// extend iOS Date to work with milliseconds since 1970
 extension Date {
     public var millisecondsSince1970: UInt64 {
@@ -156,7 +164,7 @@ extension Date {
         self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
     }
 }
-
+// MARK: -
 /// A duration of time, measured in milliseconds.
 public enum Duration: Equatable {
     case milliseconds(UInt64)

-- 
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]