gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-ios] branch master updated (a0c6bdb -> bf7f8e3)


From: gnunet
Subject: [taler-taler-ios] branch master updated (a0c6bdb -> bf7f8e3)
Date: Tue, 24 Oct 2023 22:45:16 +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 a0c6bdb  Minimalistic
     new bcdec95  Assets cleanup
     new b41fb74  Native Logging for wallet-core (QuickJS)
     new cc6b3bc  Logger
     new f941fe2  ExchangeRowView
     new 846c821  Only call DetailsForAmount if non-zero
     new ed9cab2  Fix for NavigationView popping back
     new 1bb3094  intValue, fracValue, valueAsTuple
     new e937aac  Cleanup
     new 7efecc6  DD51 - CurrencySpecification
     new 812977b  CharacterSet+contains
     new bf7f8e3  Layout for Pending - wip

The 11 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 ++
 .../AppIconBackground.colorset/Contents.json       |  38 -----
 .../Taler-logo.imageset/Contents.json              |  12 --
 .../Taler-logo.imageset/Taler-logo.jpg             | Bin 11038 -> 0 bytes
 .../TalerLogoBackground.colorset/Contents.json     |  38 -----
 TalerWallet1/Backend/WalletCore.swift              |   2 +-
 TalerWallet1/Controllers/Controller.swift          |   2 +-
 TalerWallet1/Controllers/DebugViewC.swift          |   2 +-
 TalerWallet1/Controllers/PublicConstants.swift     |   2 +
 TalerWallet1/Controllers/TalerWallet1App.swift     |   4 +-
 TalerWallet1/Helper/CharacterSet+contains.swift    |  27 ++++
 TalerWallet1/Helper/CurrencySpecification.swift    | 119 +++++++++-------
 TalerWallet1/Model/Model+Transactions.swift        |  10 +-
 TalerWallet1/Model/WalletModel.swift               |   9 +-
 TalerWallet1/Quickjs/quickjs.swift                 |  31 ++++-
 TalerWallet1/Views/Balances/BalanceRowView.swift   |  11 +-
 .../Views/Balances/BalancesSectionView.swift       |  10 +-
 TalerWallet1/Views/Balances/PendingRowView.swift   | 155 ++++++++++++++++++---
 ...angeSectionView.swift => ExchangeRowView.swift} |  47 ++-----
 .../Views/Exchange/ExchangeSectionView.swift       |  69 +--------
 TalerWallet1/Views/Exchange/ManualWithdraw.swift   |  16 ++-
 .../Views/HelperViews/View+needVStack.swift        |  19 ++-
 TalerWallet1/Views/Main/MainView.swift             |   6 +-
 TalerWallet1/Views/Peer2peer/SendDone.swift        |   5 +-
 TalerWallet1/Views/Sheets/Sheet.swift              |   2 +-
 taler-swift/Sources/taler-swift/Amount.swift       |  42 ++++--
 26 files changed, 374 insertions(+), 316 deletions(-)
 delete mode 100644 
TalerWallet1/Assets.xcassets/AppIconBackground.colorset/Contents.json
 delete mode 100644 
TalerWallet1/Assets.xcassets/Taler-logo.imageset/Contents.json
 delete mode 100644 
TalerWallet1/Assets.xcassets/Taler-logo.imageset/Taler-logo.jpg
 delete mode 100644 
TalerWallet1/Assets.xcassets/TalerLogoBackground.colorset/Contents.json
 create mode 100644 TalerWallet1/Helper/CharacterSet+contains.swift
 copy TalerWallet1/Views/Exchange/{ExchangeSectionView.swift => 
ExchangeRowView.swift} (70%)

diff --git a/TalerWallet.xcodeproj/project.pbxproj 
b/TalerWallet.xcodeproj/project.pbxproj
index cbefbd1..56565e8 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -233,6 +233,10 @@
                4EBA82AD2A3F580500E5F39A /* QuiteSomeCoins.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EBA82AC2A3F580500E5F39A /* 
QuiteSomeCoins.swift */; };
                4EC400892AE3E7E800DF72C7 /* AboutView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EC400882AE3E7E800DF72C7 /* AboutView.swift */; 
};
                4EC4008A2AE3E7E800DF72C7 /* AboutView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = 4EC400882AE3E7E800DF72C7 /* AboutView.swift */; 
};
+               4EC4008C2AE5664100DF72C7 /* CharacterSet+contains.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EC4008B2AE5664100DF72C7 /* 
CharacterSet+contains.swift */; };
+               4EC4008D2AE5664100DF72C7 /* CharacterSet+contains.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EC4008B2AE5664100DF72C7 /* 
CharacterSet+contains.swift */; };
+               4EC4008F2AE8019700DF72C7 /* ExchangeRowView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EC4008E2AE8019700DF72C7 /* 
ExchangeRowView.swift */; };
+               4EC400902AE8019700DF72C7 /* ExchangeRowView.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = 4EC4008E2AE8019700DF72C7 /* 
ExchangeRowView.swift */; };
                4EC90C782A1B528B0071DC58 /* ExchangeSectionView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 4EC90C772A1B528B0071DC58 /* 
ExchangeSectionView.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 */; 
};
@@ -402,6 +406,8 @@
                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>"; };
                4EC400882AE3E7E800DF72C7 /* AboutView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= AboutView.swift; sourceTree = "<group>"; };
+               4EC4008B2AE5664100DF72C7 /* CharacterSet+contains.swift */ = 
{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
"CharacterSet+contains.swift"; sourceTree = "<group>"; };
+               4EC4008E2AE8019700DF72C7 /* ExchangeRowView.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= ExchangeRowView.swift; sourceTree = "<group>"; };
                4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; 
path = ExchangeSectionView.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>"; };
@@ -588,6 +594,7 @@
                                4E9320422A14F6EA00A87B0E /* WalletColors.swift 
*/,
                                4E8E25322A1CD39700A27BFA /* 
EqualIconWidthDomain.swift */,
                                4EBA563E2A7FD9390084948B /* 
SuperScriptDigits.swift */,
+                               4EC4008B2AE5664100DF72C7 /* 
CharacterSet+contains.swift */,
                        );
                        path = Helper;
                        sourceTree = "<group>";
@@ -658,6 +665,7 @@
                        children = (
                                4EB095292989CBFE0043A8A1 /* 
ExchangeListView.swift */,
                                4EC90C772A1B528B0071DC58 /* 
ExchangeSectionView.swift */,
+                               4EC4008E2AE8019700DF72C7 /* 
ExchangeRowView.swift */,
                                4E50B34F2A1BEE8000F9F01C /* 
ManualWithdraw.swift */,
                                4EBA82AC2A3F580500E5F39A /* 
QuiteSomeCoins.swift */,
                                4EB431662A1E55C700C5690E /* 
ManualWithdrawDone.swift */,
@@ -1080,6 +1088,7 @@
                                4E3EAE492A990778009F1BE8 /* 
ManualWithdrawDone.swift in Sources */,
                                4E3EAE4A2A990778009F1BE8 /* 
PaymentPurpose.swift in Sources */,
                                4E3EAE4B2A990778009F1BE8 /* ShareSheet.swift in 
Sources */,
+                               4EC4008F2AE8019700DF72C7 /* 
ExchangeRowView.swift in Sources */,
                                4E3EAE4C2A990778009F1BE8 /* AmountView.swift in 
Sources */,
                                4E605DBA2AB05FB6002FB9A7 /* BarGraph.swift in 
Sources */,
                                4E3EAE4D2A990778009F1BE8 /* P2pAcceptDone.swift 
in Sources */,
@@ -1097,6 +1106,7 @@
                                4E3EAE582A990778009F1BE8 /* CurrencyField.swift 
in Sources */,
                                4E983C292ADBDD3500FA9CC5 /* 
SingleAxisGeometryReader.swift in Sources */,
                                4E3EAE592A990778009F1BE8 /* 
Model+Settings.swift in Sources */,
+                               4EC4008C2AE5664100DF72C7 /* 
CharacterSet+contains.swift in Sources */,
                                4E3EAE5A2A990778009F1BE8 /* ErrorView.swift in 
Sources */,
                                4E3EAE5B2A990778009F1BE8 /* 
View+Notification.swift in Sources */,
                                4E3EAE5C2A990778009F1BE8 /* Model+Pending.swift 
in Sources */,
@@ -1186,6 +1196,7 @@
                                4EB431672A1E55C700C5690E /* 
ManualWithdrawDone.swift in Sources */,
                                4E9320472A164BC700A87B0E /* 
PaymentPurpose.swift in Sources */,
                                4E753A082A0B6A5F002D9328 /* ShareSheet.swift in 
Sources */,
+                               4EC400902AE8019700DF72C7 /* 
ExchangeRowView.swift in Sources */,
                                4EB0956C2989CBFE0043A8A1 /* AmountView.swift in 
Sources */,
                                4E605DBB2AB05FB6002FB9A7 /* BarGraph.swift in 
Sources */,
                                4E3B4BC32A42252300CC88B8 /* P2pAcceptDone.swift 
in Sources */,
@@ -1203,6 +1214,7 @@
                                4E53A33729F50B7B00830EC2 /* CurrencyField.swift 
in Sources */,
                                4E983C2A2ADBDD3500FA9CC5 /* 
SingleAxisGeometryReader.swift in Sources */,
                                4EB095152989CBB00043A8A1 /* 
Model+Settings.swift in Sources */,
+                               4EC4008D2AE5664100DF72C7 /* 
CharacterSet+contains.swift in Sources */,
                                4EB095692989CBFE0043A8A1 /* ErrorView.swift in 
Sources */,
                                4E3B4BC72A429F2A00CC88B8 /* 
View+Notification.swift in Sources */,
                                4EB0956E2989CBFE0043A8A1 /* Model+Pending.swift 
in Sources */,
diff --git 
a/TalerWallet1/Assets.xcassets/AppIconBackground.colorset/Contents.json 
b/TalerWallet1/Assets.xcassets/AppIconBackground.colorset/Contents.json
deleted file mode 100644
index 537c338..0000000
--- a/TalerWallet1/Assets.xcassets/AppIconBackground.colorset/Contents.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "colors" : [
-    {
-      "color" : {
-        "color-space" : "srgb",
-        "components" : {
-          "alpha" : "1.000",
-          "blue" : "0.000",
-          "green" : "0.000",
-          "red" : "0.733"
-        }
-      },
-      "idiom" : "universal"
-    },
-    {
-      "appearances" : [
-        {
-          "appearance" : "luminosity",
-          "value" : "dark"
-        }
-      ],
-      "color" : {
-        "color-space" : "srgb",
-        "components" : {
-          "alpha" : "1.000",
-          "blue" : "0.000",
-          "green" : "0.000",
-          "red" : "0.733"
-        }
-      },
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
-}
diff --git a/TalerWallet1/Assets.xcassets/Taler-logo.imageset/Contents.json 
b/TalerWallet1/Assets.xcassets/Taler-logo.imageset/Contents.json
deleted file mode 100644
index eb70695..0000000
--- a/TalerWallet1/Assets.xcassets/Taler-logo.imageset/Contents.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "Taler-logo.jpg",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
-}
diff --git a/TalerWallet1/Assets.xcassets/Taler-logo.imageset/Taler-logo.jpg 
b/TalerWallet1/Assets.xcassets/Taler-logo.imageset/Taler-logo.jpg
deleted file mode 100644
index d499bdf..0000000
Binary files a/TalerWallet1/Assets.xcassets/Taler-logo.imageset/Taler-logo.jpg 
and /dev/null differ
diff --git 
a/TalerWallet1/Assets.xcassets/TalerLogoBackground.colorset/Contents.json 
b/TalerWallet1/Assets.xcassets/TalerLogoBackground.colorset/Contents.json
deleted file mode 100644
index d791e44..0000000
--- a/TalerWallet1/Assets.xcassets/TalerLogoBackground.colorset/Contents.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "colors" : [
-    {
-      "color" : {
-        "color-space" : "srgb",
-        "components" : {
-          "alpha" : "1.000",
-          "blue" : "0.824",
-          "green" : "0.796",
-          "red" : "0.784"
-        }
-      },
-      "idiom" : "universal"
-    },
-    {
-      "appearances" : [
-        {
-          "appearance" : "luminosity",
-          "value" : "dark"
-        }
-      ],
-      "color" : {
-        "color-space" : "srgb",
-        "components" : {
-          "alpha" : "1.000",
-          "blue" : "0.824",
-          "green" : "0.796",
-          "red" : "0.784"
-        }
-      },
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
-}
diff --git a/TalerWallet1/Backend/WalletCore.swift 
b/TalerWallet1/Backend/WalletCore.swift
index a3b8dbb..9886363 100644
--- a/TalerWallet1/Backend/WalletCore.swift
+++ b/TalerWallet1/Backend/WalletCore.swift
@@ -30,7 +30,7 @@ class WalletCore: QuickjsMessageHandler {
 
     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")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "WalletCore")
 
     private struct FullRequest: Encodable {
         let operation: String
diff --git a/TalerWallet1/Controllers/Controller.swift 
b/TalerWallet1/Controllers/Controller.swift
index 33169ee..788438c 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -38,7 +38,7 @@ class Controller: ObservableObject {
     @AppStorage("playSounds") var playSounds: Int = 0       // extension 
mustn't define this, so it must be here
     @AppStorage("talerFont") var talerFont: Int = 0         // extension 
mustn't define this, so it must be here
     let hapticCapability = CHHapticEngine.capabilitiesForHardware()
-    let logger = Logger (subsystem: "net.taler.gnu", category: "Controller")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "Controller")
     let player = AVQueuePlayer()
     let semaphore = AsyncSemaphore(value: 1)
 
diff --git a/TalerWallet1/Controllers/DebugViewC.swift 
b/TalerWallet1/Controllers/DebugViewC.swift
index 990f53a..bf73067 100644
--- a/TalerWallet1/Controllers/DebugViewC.swift
+++ b/TalerWallet1/Controllers/DebugViewC.swift
@@ -142,7 +142,7 @@ class DebugViewC: ObservableObject {
 #else
     @AppStorage("developerMode") var developerMode: Bool = false
 #endif
-    let logger = Logger (subsystem: "net.taler.gnu", category: "DebugView")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "DebugView")
 
     @Published var viewID: Int = 0
     @Published var sheetID: Int = 0
diff --git a/TalerWallet1/Controllers/PublicConstants.swift 
b/TalerWallet1/Controllers/PublicConstants.swift
index 0271bdc..3b778bd 100644
--- a/TalerWallet1/Controllers/PublicConstants.swift
+++ b/TalerWallet1/Controllers/PublicConstants.swift
@@ -4,6 +4,8 @@
  */
 import Foundation
 
+public let HSPACING = CGFloat(10)                  // space between items in 
HStack
+
 public let LAUNCHDURATION: Double = 1.60
 public let SLIDEDURATION: Double = 0.45
 
diff --git a/TalerWallet1/Controllers/TalerWallet1App.swift 
b/TalerWallet1/Controllers/TalerWallet1App.swift
index 4adf008..7f7fa50 100644
--- a/TalerWallet1/Controllers/TalerWallet1App.swift
+++ b/TalerWallet1/Controllers/TalerWallet1App.swift
@@ -26,7 +26,7 @@ struct TalerWallet1App: App {
     private let controller = Controller.shared
     private let model = WalletModel.shared
     private let debugViewC = DebugViewC.shared
-    let logger = Logger (subsystem: "net.taler.gnu", category: "Main App")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "Main App")
     let sqlite3 = true                                                         
 // true = SQLITE3, false = JSON
 
     func scheduleAppRefresh() {
@@ -103,7 +103,7 @@ struct TalerWallet1App: App {
 final class ViewState : ObservableObject {
     static let shared = ViewState()
     @Published var rootViewId = UUID()
-    let logger = Logger (subsystem: "net.taler.gnu", category: "ViewState")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "ViewState")
 
     public func popToRootView() -> Void {
         logger.info("popToRootView")
diff --git a/TalerWallet1/Helper/CharacterSet+contains.swift 
b/TalerWallet1/Helper/CharacterSet+contains.swift
new file mode 100644
index 0000000..ad7f7a3
--- /dev/null
+++ b/TalerWallet1/Helper/CharacterSet+contains.swift
@@ -0,0 +1,27 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+import Foundation
+
+public extension CharacterSet {
+
+    func contains(_ character: Character) -> Bool {
+        character.unicodeScalars.allSatisfy(contains)
+    }
+
+    func containsAll(in string: String) -> Bool {
+        string.unicodeScalars.allSatisfy(contains)
+    }
+}
+
+public extension CharacterSet {
+
+    static func + (lhs: CharacterSet, rhs: CharacterSet) -> CharacterSet {
+        lhs.union(rhs)
+    }
+
+    static func - (lhs: CharacterSet, rhs: CharacterSet) -> CharacterSet {
+        lhs.subtracting(rhs)
+    }
+}
diff --git a/TalerWallet1/Helper/CurrencySpecification.swift 
b/TalerWallet1/Helper/CurrencySpecification.swift
index 6b8a059..cbbefc1 100644
--- a/TalerWallet1/Helper/CurrencySpecification.swift
+++ b/TalerWallet1/Helper/CurrencySpecification.swift
@@ -10,53 +10,78 @@ public struct CurrencyInfo {
     let specs: CurrencySpecification
     let formatter: CurrencyFormatter
 
-    func string(for value: Double, useSymbol: Bool = true) -> String {
+    /// returns all characters left from the decimalSeparator
+    func integerPartStr(_ integerStr: String, decimalSeparator: String) -> 
String {
+        if let integerIndex = integerStr.endIndex(of: decimalSeparator) {
+            // decimalSeparator was found ==> return all characters left of it
+            return String(integerStr[..<integerIndex])
+        }
+        guard let firstChar = integerStr.first else { return "" }    // TODO: 
should NEVER happen! Show error
+        let digitSet = CharacterSet.decimalDigits
+        if digitSet.contains(firstChar) {
+            // Currency Symbol is after the amount ==> return only the digits
+            return String(integerStr.unicodeScalars.filter { 
digitSet.contains($0) })
+        } else {
+            // Currency Symbol is in front of the amount ==> return everything
+            return integerStr
+        }
+    }
+
+    func string(for valueTuple: (Double, Double), useSymbol: Bool = true) -> 
String {
         formatter.setUseSymbol(useSymbol)
-        if let valueStr = formatter.string(for: value) {
-            let decimalSeparator = formatter.decimalSeparator ?? 
specs.decimalSeparator
-            if let decimalIndex = valueStr.endIndex(of: decimalSeparator) {
-                var fraction = 1
-                var integerStr = String(valueStr[..<decimalIndex])
-                let fractionStr = valueStr[decimalIndex...]
-                for character in fractionStr {
-                    let charStr = String(character)
-                    if let digit = Int(charStr) {
-                        let digitStr = fraction > specs.fractionalNormalDigits 
?
-                                                    SuperScriptDigits(charStr) 
: charStr
-                        integerStr += digitStr
-                    } else { integerStr += charStr }
-                    fraction += 1
+        let (integer, fraction) = valueTuple
+        if let integerStr = formatter.string(for: integer) {
+            if fraction == 0 { return integerStr }              // TODO: add 
trailing zeroes
+            if let fractionStr = formatter.string(for: fraction) {
+                if let decimalSeparator = formatter.currencyDecimalSeparator {
+                    if let fractionIndex = fractionStr.endIndex(of: 
decimalSeparator) {
+                        var fractionPartStr = 
String(fractionStr[fractionIndex...])
+                        var resultStr = integerPartStr(integerStr, 
decimalSeparator: decimalSeparator)
+                        if !resultStr.contains(decimalSeparator) {
+                            resultStr += decimalSeparator
+                        }
+//            print(resultStr, fractionPartStr)
+                        var fractionCnt = 1
+                        for character in fractionPartStr {
+                            let isSuper = fractionCnt > 
specs.fractionalNormalDigits
+                            let charStr = String(character)
+                            if let digit = Int(charStr) {
+                                let digitStr = isSuper ? 
SuperScriptDigits(charStr) : charStr
+                                resultStr += digitStr
+                                if (fractionCnt > 0) { fractionCnt += 1 }
+                            } else {
+                                // probably the Currency Code or Symbol. Just 
pass it on...
+                                resultStr += charStr
+                                // make sure any following digits (part of the 
currency name) are not converted to SuperScript
+                                fractionCnt = 0
+                            }
+                        }
+//            print(resultStr)
+                        return resultStr
+                    }
+                    // if we arrive here then fractionStr doesn't have a 
decimal separator. Yikes!
                 }
-                return integerStr
+                // if we arrive here then the formatter doesn't have a 
currencyDecimalSeparator
             }
-            return valueStr
-        } else {        // formatter doesn't work - we need to format ourselves
-            var madeUpStr = ""
-            var currencyName = scope.currency
-            var hasSymbol = false
-            if useSymbol && formatter.hasAltUnitName0 {
+            // if we arrive here then we do not get a formatted string for 
fractionStr. Yikes!
+        }
+        // if we arrive here then we do not get a formatted string for 
integerStr. Yikes!
+        // TODO: log.error(formatter doesn't work)
+        // we need to format ourselves
+        var currencyName = scope.currency
+        if useSymbol {
+            if formatter.hasAltUnitName0 {
                 if let symbol = specs.altUnitNames?[0] {
                     currencyName = symbol
-                    hasSymbol = true
                 }
             }
-            if specs.isCurrencyNameLeading {
-                madeUpStr = currencyName
-                if !hasSymbol {
-                    madeUpStr += " "
-                }
-            }
-            let integerPart = Int(value)
-            madeUpStr += String(integerPart)
-            madeUpStr += specs.decimalSeparator
-            if !specs.isCurrencyNameLeading {
-                if !hasSymbol {
-                    madeUpStr += " "
-                }
-                madeUpStr += currencyName
-            }
-            return madeUpStr
-        } // DIY
+        }
+        var madeUpStr = currencyName + " " + String(integer)
+//        let homeCurrency = Locale.current.currency      //'currency' is only 
available in iOS 16 or newer
+        madeUpStr += Locale.current.decimalSeparator ?? "."     // 
currencyDecimalSeparator
+        madeUpStr += String(String(fraction).dropFirst())       // remove the 
leading 0
+        // TODO: fractionalNormalDigits, fractionalTrailingZeroDigits
+        return madeUpStr
     }
 }
 
@@ -67,20 +92,20 @@ public struct CurrencySpecification2: Codable, Sendable {
 public struct CurrencySpecification: Codable, Sendable {
     enum CodingKeys: String, CodingKey {
         case name = "name"
-        case decimalSeparator = "decimal_separator"
-        case groupSeparator = "group_separator"
+//        case decimalSeparator = "decimal_separator"
+//        case groupSeparator = "group_separator"
         case fractionalInputDigits = "num_fractional_input_digits"
         case fractionalNormalDigits = "num_fractional_normal_digits"
         case fractionalTrailingZeroDigits = 
"num_fractional_trailing_zero_digits"
-        case isCurrencyNameLeading = "is_currency_name_leading"
+//        case isCurrencyNameLeading = "is_currency_name_leading"
         case altUnitNames = "alt_unit_names"
     }
     /// some name for this CurrencySpecification
     let name: String
     /// e.g. “.” for $, and “,” for €
-    let decimalSeparator: String
-    /// e.g. “,” for $, and “.” or “ ” for €     (France uses a narrow space 
character)
-    let groupSeparator: String?
+//    let decimalSeparator: String      taken from Locale.current
+    /// e.g. “,” for $, and “.” or “ ” for €     (France uses a narrow space 
character, Hungaria a normal one)
+//    let groupSeparator: String?       taken from Locale.current
     /// how much digits the user may enter after the decimal separator
     let fractionalInputDigits: Int
     /// €,$,£: 2;  some arabic currencies: 3,  ¥: 0
@@ -88,7 +113,7 @@ public struct CurrencySpecification: Codable, Sendable {
     /// usually same as numFractionalNormalDigits, but e.g. might be 2 for ¥
     let fractionalTrailingZeroDigits: Int
     /// true for “$ 3.50”;  false for “3,50 €”
-    let isCurrencyNameLeading: Bool
+//    let isCurrencyNameLeading: Bool
     /// map of powers of 10 to alternative currency names / symbols
     /// must always have an entry under "0" that defines the base name
     /// e.g.  "0 => €" or "3 => k€". For BTC, would be "0 => BTC, -3 => mBTC".
diff --git a/TalerWallet1/Model/Model+Transactions.swift 
b/TalerWallet1/Model/Model+Transactions.swift
index 2e59bfb..6c3869d 100644
--- a/TalerWallet1/Model/Model+Transactions.swift
+++ b/TalerWallet1/Model/Model+Transactions.swift
@@ -129,32 +129,32 @@ extension WalletModel {
     /// abort the specified transaction from Wallet-Core. No networking 
involved
     func abortTransaction(transactionId: String) async throws {
         let request = AbortTransaction(transactionId: transactionId)
-        logger.info("abortTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
+        logger.notice("abortTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
         let _ = try await sendRequest(request, ASYNCDELAY)
     }
 
     /// delete the specified transaction from Wallet-Core. No networking 
involved
     func deleteTransaction(transactionId: String) async throws {
         let request = DeleteTransaction(transactionId: transactionId)
-        logger.info("deleteTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
+        logger.notice("deleteTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
         let _ = try await sendRequest(request, ASYNCDELAY)
     }
 
     func failTransaction(transactionId: String) async throws {
         let request = FailTransaction(transactionId: transactionId)
-        logger.info("failTransaction: \(transactionId, privacy: .private(mask: 
.hash))")
+        logger.notice("failTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
         let _ = try await sendRequest(request, ASYNCDELAY)
     }
 
     func suspendTransaction(transactionId: String) async throws {
         let request = SuspendTransaction(transactionId: transactionId)
-        logger.info("suspendTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
+        logger.notice("suspendTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
         let _ = try await sendRequest(request, ASYNCDELAY)
     }
 
     func resumeTransaction(transactionId: String) async throws {
         let request = ResumeTransaction(transactionId: transactionId)
-        logger.info("resumeTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
+        logger.notice("resumeTransaction: \(transactionId, privacy: 
.private(mask: .hash))")
         let _ = try await sendRequest(request, ASYNCDELAY)
     }
 }
diff --git a/TalerWallet1/Model/WalletModel.swift 
b/TalerWallet1/Model/WalletModel.swift
index 1bc239f..1133ef7 100644
--- a/TalerWallet1/Model/WalletModel.swift
+++ b/TalerWallet1/Model/WalletModel.swift
@@ -20,11 +20,10 @@ struct HTTPError: Codable, Hashable {
     var stack: String?
 }
 // MARK: -
-/// The "virtual" base class for all models
+/// Communicate with wallet-core
 class WalletModel: ObservableObject {
     public static let shared = WalletModel()
-    static func className() -> String {"\(self)"}
-    let logger = Logger (subsystem: "net.taler.gnu", category: "WalletModel")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "WalletModel")
     let semaphore = AsyncSemaphore(value: 1)
     var cachedBalances: [Balance]? = nil
 
@@ -94,13 +93,15 @@ fileprivate struct InitRequest: 
WalletBackendFormattedRequest {
     func args() -> Args {
         return Args(persistentStoragePath: persistentStoragePath,
 //                       cryptoWorkerType: "sync",
-                                 logLevel: "info") // trace, info, warn, 
error, none
+                                 logLevel: "info", // trace, info, warn, 
error, none
+                         useNativeLogging: true)
     }
 
     struct Args: Encodable {
         var persistentStoragePath: String
 //        var cryptoWorkerType: String
         var logLevel: String
+        var useNativeLogging: Bool
     }
 
     var persistentStoragePath: String
diff --git a/TalerWallet1/Quickjs/quickjs.swift 
b/TalerWallet1/Quickjs/quickjs.swift
index b301190..54f42bd 100644
--- a/TalerWallet1/Quickjs/quickjs.swift
+++ b/TalerWallet1/Quickjs/quickjs.swift
@@ -3,13 +3,14 @@
  * See LICENSE.md
  */
 import Foundation
+import os.log
 
 import FTalerWalletcore
 
 public protocol QuickjsMessageHandler: AnyObject {
     func handleMessage(message: String)
 }
-
+// MARK: -
 func notification_callback(userdata: Optional<UnsafeMutableRawPointer>,
                            payload: Optional<UnsafePointer<Int8>>) {
     let native = Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
@@ -17,15 +18,43 @@ func notification_callback(userdata: 
Optional<UnsafeMutableRawPointer>,
     native.internalOnNotify(payload: string)
 }
 
+func logging_callback(userdata: Optional<UnsafeMutableRawPointer>,
+                          level: TALER_WALLET_LogLevel,
+                            tag: Optional<UnsafePointer<Int8>>,
+                        message: Optional<UnsafePointer<Int8>>) {
+    let native = Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
+    let theTag = String(cString: tag!)
+    let theMessage = String(cString: message!)
+
+    switch level {
+        case TALER_WALLET_LOG_ERROR:
+            native.logger.error("\(theTag, privacy: .public)  \(theMessage, 
privacy: .public)")
+        case TALER_WALLET_LOG_WARN:
+            native.logger.warning("\(theTag, privacy: .public)  \(theMessage, 
privacy: .public)")
+        case TALER_WALLET_LOG_MESSAGE:
+            native.logger.notice("\(theTag, privacy: .public)  \(theMessage, 
privacy: .public)")
+        case TALER_WALLET_LOG_INFO:
+            native.logger.info("\(theTag, privacy: .public)  \(theMessage, 
privacy: .public)")
+        case TALER_WALLET_LOG_TRACE:
+            native.logger.trace("\(theTag, privacy: .public)  \(theMessage, 
privacy: .public)")
+        default: break
+    }
+}
+// MARK: -
 public class Quickjs {
     var talerWalletInstance: OpaquePointer!
     public weak var messageHandler: QuickjsMessageHandler?
+    var logger: Logger
 
     public init() {
+        self.logger = Logger(subsystem: "net.taler.gnu", category: "QuickJS")
         self.talerWalletInstance = TALER_WALLET_create()
         TALER_WALLET_set_message_handler(talerWalletInstance,
                                          notification_callback,
                                          
Unmanaged.passUnretained(self).toOpaque())
+        TALER_WALLET_set_log_handler(talerWalletInstance,
+                                     logging_callback,
+                                     Unmanaged.passUnretained(self).toOpaque())
         TALER_WALLET_run(talerWalletInstance);
     }
 
diff --git a/TalerWallet1/Views/Balances/BalanceRowView.swift 
b/TalerWallet1/Views/Balances/BalanceRowView.swift
index fcff95e..27ded57 100644
--- a/TalerWallet1/Views/Balances/BalanceRowView.swift
+++ b/TalerWallet1/Views/Balances/BalanceRowView.swift
@@ -5,8 +5,6 @@
 import SwiftUI
 import taler_swift
 
-let SPACING = CGFloat(10)                  // space between the two buttons
-
 struct BalanceLabel: View {
     let balanceTitle: String
     let horizontal: Bool
@@ -50,7 +48,7 @@ struct BalanceButton: View {
                     let amountFont = TalerFont.uiFont(.title)
                     let titles = [(balanceTitle, balancesFont),
                                   (amountStr, amountFont)]
-                    let needVStack = !iconOnly && Self.needVStack(titles, 
width: width, spacing: SPACING, sameSize: false)
+                    let needVStack = !iconOnly && Self.needVStack(titles, 
width: width, spacing: HSPACING, sameSize: false)
                     if needVStack {
                         VStack(alignment: .leading, spacing: 0) {
                             BalanceLabel(balanceTitle: balanceTitle, 
horizontal: false, amountStr: amountStr, iconOnly: iconOnly)
@@ -87,10 +85,9 @@ struct BalanceRowView: View {
     let requestTitle2 = String(localized: "Payment", comment: "Bottom of 
button <Request Payment>")
 
     var body: some View {
-
         SingleAxisGeometryReader { width in
             VStack (alignment: .trailing) {
-                let amountStr = currencyInfo?.string(for: amount.value)
+                let amountStr = currencyInfo?.string(for: amount.valueAsTuple)
                 BalanceButton(amountStr: amountStr ?? amount.valueStr,
                               rowAction: rowAction)
                 let uiFont = TalerFont.uiFont(.title3)
@@ -101,10 +98,10 @@ struct BalanceRowView: View {
                                                   lineLimit: 5, sendDisabled: 
amount.isZero,
                                                   sendAction: sendAction, 
recvAction: recvAction)
 //  let _ = print("Screenwidth: \(UIScreen.screenWidth)  Geometry: \(width)  
\(sizeCategory): \(sizeCategory)")
-                if Self.needVStack(titles, width: width, spacing: SPACING) {
+                if Self.needVStack(titles, width: width, spacing: HSPACING) {
                     VStack { twoRowButtons }
                 } else {
-                    HStack(spacing: SPACING) { twoRowButtons }
+                    HStack(spacing: HSPACING) { twoRowButtons }
                 }
             }
             .accessibilityElement(children: .combine)
diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift 
b/TalerWallet1/Views/Balances/BalancesSectionView.swift
index 80e446d..91872a8 100644
--- a/TalerWallet1/Views/Balances/BalancesSectionView.swift
+++ b/TalerWallet1/Views/Balances/BalancesSectionView.swift
@@ -89,7 +89,7 @@ extension BalancesSectionView: View {
             if hasPending {
                 BalancesPendingRowView(symLog: symLog,
                                         stack: stack.push(),
-                                     currency: currency,
+                                 currencyInfo: currencyInfo,
                           pendingTransactions: $pendingTransactions,
                                 reloadPending: reloadPending,
                               reloadOneAction: reloadOneAction)
@@ -160,7 +160,8 @@ extension BalancesSectionView: View {
 fileprivate struct BalancesPendingRowView: View {
     let symLog: SymLogV?
     let stack: CallStack
-    let currency: String
+    let currencyInfo: CurrencyInfo?
+//
     @Binding var pendingTransactions: [Transaction]
     let reloadPending: (_ stack: CallStack) async -> ()
     let reloadOneAction: ((_ transactionId: String) async throws -> 
Transaction)
@@ -187,6 +188,7 @@ fileprivate struct BalancesPendingRowView: View {
     }
 
     var body: some View {
+        let currency: String = currencyInfo?.scope.currency ?? ""
         let (pendingIncoming, pendingOutgoing) = computePending(currency: 
currency)
 
         NavigationLink {
@@ -204,11 +206,11 @@ fileprivate struct BalancesPendingRowView: View {
             VStack(spacing: 6) {
                 var rows = 0
                 if !pendingIncoming.isZero {
-                    PendingRowView(amount: pendingIncoming, incoming: true)
+                    PendingRowView(amount: pendingIncoming, currencyInfo: 
currencyInfo, incoming: true)
                     let _ = (rows+=1)
                 }
                 if !pendingOutgoing.isZero {
-                    PendingRowView(amount: pendingOutgoing, incoming: false)
+                    PendingRowView(amount: pendingOutgoing, currencyInfo: 
currencyInfo, incoming: false)
                     let _ = (rows+=1)
                 }
                 if rows == 0 {
diff --git a/TalerWallet1/Views/Balances/PendingRowView.swift 
b/TalerWallet1/Views/Balances/PendingRowView.swift
index c883f57..6604bc1 100644
--- a/TalerWallet1/Views/Balances/PendingRowView.swift
+++ b/TalerWallet1/Views/Balances/PendingRowView.swift
@@ -5,43 +5,158 @@
 import SwiftUI
 import taler_swift
 
-/// This view shows a pending transaction row in a currency section
-struct PendingRowView: View {
-    let amount: Amount
+struct InOrOutView: View {
+    let title: (String, String)
+    let horizontal: Bool
     let incoming: Bool
+    let imageName: String
+
+    public static func width(image1: String, title1: String, title2: String) 
-> CGFloat {
+        let imageFont = TalerFont.uiFont(.largeTitle)
+        let uiFont = TalerFont.uiFont(.body)
+
+        let image2 = "++"
+        let imageWidth = image2.widthOfString(usingUIFont: imageFont) + 8.0    
 //.padding(.trailing)
+        let title1Width = title1.widthOfString(usingUIFont: uiFont)
+        let title2Width = title2.widthOfString(usingUIFont: uiFont)
+//    print("image: ", imageWidth, " title: ", max(title1Width, title2Width))
+        return imageWidth + max(title1Width, title2Width)
+    }
 
     var body: some View {
-        HStack {
+        let (title1, title2) = title
+        HStack(spacing: 0) {
             let pendingColor = WalletColors().pendingColor(incoming)
-            Image(systemName: incoming ? "text.badge.plus"
-                                       : "text.badge.minus")
+            Image(systemName: imageName)
                 .foregroundColor(pendingColor)
                 .accessibilityFont(.largeTitle)
                 .accessibility(hidden: true)
-
-            Spacer()
-            Text("pending\n" + (incoming ? "incoming" : "outgoing"))
+//                .padding(.trailing)
+            Text(horizontal ? (title1 + "\n" + title2)
+                            : (title1 + " " + title2))
+                .lineLimit(2)
                 .accessibilityFont(.body)
-            Spacer()
-            VStack(alignment: .trailing) {
-                let sign = incoming ? "+" : "-"
-                let valueStr = sign + amount.valueStr
-                Text(valueStr)
-                    .foregroundColor(pendingColor)
-                    .accessibilityFont(.title)
-                    .monospacedDigit()
+        }
+    }
+}
+
+struct PendingAmountView: View {
+    let amount: Amount
+    let currencyInfo: CurrencyInfo?
+    let incoming: Bool
+
+    public static func amountStr(amount: Amount, currencyInfo: CurrencyInfo?, 
incoming: Bool) -> String {
+        let sign = incoming ? "+ " : "- "
+        let amountStr = currencyInfo?.string(for: amount.valueAsTuple)
+        return sign + (amountStr ?? amount.valueStr)
+    }
+    
+    public static func width(amount: Amount, currencyInfo: CurrencyInfo?, 
incoming: Bool) -> CGFloat {
+        let valueStr = Self.amountStr(amount: amount, currencyInfo: 
currencyInfo, incoming: incoming)
+        let uiFont = TalerFont.uiFont(.title)
+        let width = valueStr.widthOfString(usingUIFont: uiFont)
+//    print("Amount width: ", width)
+        return width
+    }
+
+    var body: some View {
+        let pendingColor = WalletColors().pendingColor(incoming)
+        let valueStr = Self.amountStr(amount: amount, currencyInfo: 
currencyInfo, incoming: incoming)
+        Text(valueStr)
+            .foregroundColor(pendingColor)
+            .accessibilityFont(.title)
+            .monospacedDigit()
+    }
+}
+
+struct PendingLabel: View {
+    let amount: Amount
+    let currencyInfo: CurrencyInfo?
+    let incoming: Bool
+    let horizontal: Bool        // true: HStack{ image + pending Xcoming + 
amount }
+    let title: (String, String)
+    let imageName: String
+
+    var body: some View {
+        Group {         // can either be horizontal (preferred) or vertical 
(if doesn't fit horizontally)
+            InOrOutView(title: title, horizontal: horizontal, incoming: 
incoming, imageName: imageName)
+            if horizontal {     // Group is an HStack already => just add 
Spacer + Amount
+                Spacer(minLength: 0)
+                PendingAmountView(amount: amount, currencyInfo: currencyInfo, 
incoming: incoming)
+            } else {            // Group is a VStack => need HStack + Spacer 
to shift Amount to the trailing edge
+                HStack(spacing: 0) {
+                    Spacer(minLength: 0)
+                    PendingAmountView(amount: amount, currencyInfo: 
currencyInfo, incoming: incoming)
+}   }   }   }   }
+
+/// This view shows a pending transaction row in a currency section
+struct PendingRowView: View {
+    let amount: Amount
+    let currencyInfo: CurrencyInfo?
+    let incoming: Bool
+
+    let inTitle1 = String(localized: "pending", comment: "Top of line <pending 
incoming>")
+    let inTitle2 = String(localized: "incoming", comment: "Bottom of line 
<pending incoming>")
+    let outTitle1 = String(localized: "pending", comment: "Top of line 
<pending outgoing>")
+    let outTitle2 = String(localized: "outgoing", comment: "Bottom of line 
<pending outgoing>")
+
+    func needVStack(available: CGFloat, inOrOutWidth: CGFloat, valueWidth: 
CGFloat) -> Bool {
+        available < (inOrOutWidth + valueWidth + 40)
+    }
+
+    var body: some View {
+        let imageName = incoming ? "text.badge.plus"
+                                 : "text.badge.minus"
+        let imageStr = String("\(Image(systemName: imageName))")
+        SingleAxisGeometryReader { width in
+            Group {
+                let title = incoming ? (inTitle1, inTitle2)
+                                     : (outTitle1, outTitle2)
+                let inOrOutWidth = InOrOutView.width(image1: imageStr,
+                                                     title1: incoming ? 
inTitle1 : outTitle1,
+                                                     title2: incoming ? 
inTitle2 : outTitle2)
+                let valueWidth = PendingAmountView.width(amount: amount,
+                                                   currencyInfo: currencyInfo,
+                                                       incoming: incoming)
+//    let _ = print(width, " - ", inOrOutWidth + valueWidth, " = ", width - 
(inOrOutWidth + valueWidth))
+                if needVStack(available: width, inOrOutWidth: inOrOutWidth, 
valueWidth: valueWidth) {
+                    VStack(alignment: .leading, spacing: 0) {
+                        PendingLabel(amount: amount, currencyInfo: 
currencyInfo,
+                                   incoming: incoming, horizontal: false,
+                                      title: title,     imageName: imageName)
+                    }
+                } else {
+                    HStack(spacing: 0) {
+                        PendingLabel(amount: amount, currencyInfo: 
currencyInfo,
+                                   incoming: incoming, horizontal: true,
+                                      title: title,     imageName: imageName)
+                    }
+                }
             }
+            .accessibilityElement(children: .combine)
         }
-        .accessibilityElement(children: .combine)
     }
 }
 // MARK: -
 #if DEBUG
 struct PendingRowView_Previews: PreviewProvider {
     static var previews: some View {
+        let scope = ScopeInfo(type: .global, currency: TESTCURRENCY)
+        let specs = CurrencySpecification(name: TESTCURRENCY,
+//                                          decimalSeparator: ".", 
groupSeparator: "'",
+                                          fractionalInputDigits: 0,
+                                          fractionalNormalDigits: 0,
+                                          fractionalTrailingZeroDigits: 0,
+//                                          isCurrencyNameLeading: true,
+                                          altUnitNames: [0 : "¥"])
+        let formatter = CurrencyFormatter.formatter(scope: scope,
+                                                    specs: specs)
+        let currencyInfo = CurrencyInfo(scope: scope, specs: specs, formatter: 
formatter)
+        let test = try! Amount(fromString: TESTCURRENCY + ":1.23")
+        let demo = try! Amount(fromString: DEMOCURRENCY + ":1234.56")
         List {
-            PendingRowView(amount: try! Amount(fromString: LONGCURRENCY + 
":4.8"), incoming: true)
-            PendingRowView(amount: try! Amount(fromString: LONGCURRENCY + 
":3.25"), incoming: false)
+            PendingRowView(amount: test, currencyInfo: currencyInfo, incoming: 
true)
+            PendingRowView(amount: demo, currencyInfo: currencyInfo, incoming: 
false)
         }
     }
 }
diff --git a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift 
b/TalerWallet1/Views/Exchange/ExchangeRowView.swift
similarity index 70%
copy from TalerWallet1/Views/Exchange/ExchangeSectionView.swift
copy to TalerWallet1/Views/Exchange/ExchangeRowView.swift
index 73e8dbf..fa08d80 100644
--- a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeRowView.swift
@@ -17,7 +17,7 @@ struct ExchangeRowView: View {
 
     func selectAndUpdate(_ button: Int) {
         buttonSelected = button      // will trigger NavigationLink
-        // while navigation animation runs, contact Exchange to update Fees
+        // TODO: while navigation animation runs, contact Exchange to update 
Fees
 //        Task { // runs on MainActor
 //            do {
 //                try await model.updateExchange(scopeInfo: balance.scopeInfo)
@@ -59,49 +59,19 @@ struct ExchangeRowView: View {
                                                   lineLimit: 5, sendDisabled: 
true,     // TODO: amount.isZero
                                                  sendAction: { 
selectAndUpdate(1) },
                                                  recvAction: { 
selectAndUpdate(2) })
-                let spacing = CGFloat(10)                  // space between 
the two buttons
-                if Self.needVStack(titles, width: width, spacing: spacing) {
+                if Self.needVStack(titles, width: width, spacing: HSPACING + 
4, currency: currency) {
                     VStack { twoRowButtons }
                 } else {
-                    HStack(spacing: spacing) { twoRowButtons }
+                    HStack(spacing: HSPACING) { twoRowButtons }
                 }
             }
         }
     }
 }
-// MARK: -
-/// This view shows the currency name in an exchange section
-///         currency
-/// [Deposit Coins]  [Withdraw Coins]
-struct ExchangeSectionView: View {
-    let stack: CallStack
-//    let amount: Amount
-    let currency: String          // TODO: amount.currencyStr
-    let exchanges: [Exchange]
-    @Binding var centsToTransfer: UInt64
 
-    var body: some View {
-#if DEBUG
-        let _ = Self._printChanges()
-//        let _ = symLog.vlog()       // just to get the # to compare it with 
.onAppear & onDisappear
-#endif
-        Section {
-            ForEach(exchanges) { exchange in
-                ExchangeRowView(stack: stack.push(),
-                             exchange: exchange,
-//                               amount: amount,
-                             currency: currency,            // TODO: 
(balance.available) amount.isZero to disable Deposit-button
-                      centsToTransfer: $centsToTransfer)
-            }
-            .accessibilityElement(children: .combine)
-        } header: {
-            BarGraphHeader(stack: stack.push(), currency: currency)
-        }
-    }
-}
 // MARK: -
 #if DEBUG
-struct ExchangeRow_Container : View {
+fileprivate struct ExchangeRow_Container : View {
     @State private var centsToTransfer: UInt64 = 100
 
 //    let amount = try! Amount(fromString: LONGCURRENCY + ":1234.56")
@@ -120,13 +90,14 @@ struct ExchangeRow_Container : View {
                              exchangeEntryStatus: .ephemeral,
                             exchangeUpdateStatus: .ready,
                            ageRestrictionOptions: [])
-        ExchangeSectionView(stack: CallStack("Preview"), currency: 
LONGCURRENCY,
-                            exchanges: [exchange1, exchange2],
-                            centsToTransfer: $centsToTransfer)
+        ExchangeRowView(stack: CallStack("Preview"),
+                     exchange: exchange1,
+                     currency: LONGCURRENCY,
+              centsToTransfer: $centsToTransfer)
     }
 }
 
-struct ExchangeRow_Previews: PreviewProvider {
+fileprivate struct ExchangeRow_Previews: PreviewProvider {
     static var previews: some View {
         List {
             ExchangeRow_Container()
diff --git a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift 
b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
index 73e8dbf..e13ebc1 100644
--- a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift
@@ -5,71 +5,6 @@
 import SwiftUI
 import taler_swift
 
-struct ExchangeRowView: View {
-    let stack: CallStack
-    let exchange: Exchange
-//    let amount: Amount
-    let currency: String
-    @Binding var centsToTransfer: UInt64
-
-    @Environment(\.sizeCategory) var sizeCategory
-    @State private var buttonSelected: Int? = nil
-
-    func selectAndUpdate(_ button: Int) {
-        buttonSelected = button      // will trigger NavigationLink
-        // while navigation animation runs, contact Exchange to update Fees
-//        Task { // runs on MainActor
-//            do {
-//                try await model.updateExchange(scopeInfo: balance.scopeInfo)
-//            } catch {    // TODO: error handling - couldn't updateExchange
-//                //                symLog.log("error: \(error)")
-//            }
-//        }
-    }
-
-    let depositTitle = String(localized: "Deposit", comment: "Top of button 
<Deposit (currency)>")
-    let withdrawTitle = String(localized: "Withdraw", comment: "Top of button 
<Withdraw (currency)>")
-
-    var body: some View {
-        let baseURL = exchange.exchangeBaseUrl
-
-        HStack(spacing: 0) {    // can't use the built in Label because it 
adds the accessory arrow
-            Text(baseURL.trimURL())
-                .accessibilityFont(.body)
-
-            NavigationLink(destination: LazyView {
-                EmptyView()     // TODO: Deposit
-            }, tag: 1, selection: $buttonSelected
-            ) { EmptyView() }.frame(width: 0).opacity(0)
-            NavigationLink(destination: LazyView {
-                ManualWithdraw(stack: stack.push(),
-                            exchange: exchange,
-                     centsToTransfer: $centsToTransfer)
-            }, tag: 2, selection: $buttonSelected
-            ) { EmptyView() }.frame(width: 0).opacity(0)
-        }.listRowSeparator(.hidden)
-
-        SingleAxisGeometryReader { width in
-            Group {
-                let uiFont = TalerFont.uiFont(.title3)
-                let titles = [(depositTitle, uiFont), (withdrawTitle, uiFont), 
(currency, uiFont)]
-                let sendTitle = depositTitle + "\n" + currency                 
         // TODO:  amount.currencyStr
-                let recvTitle = withdrawTitle + "\n" + currency                
         // TODO:  amount.currencyStr
-                let twoRowButtons = TwoRowButtons(sendTitle: sendTitle, 
recvTitle: recvTitle,
-                                                  lineLimit: 5, sendDisabled: 
true,     // TODO: amount.isZero
-                                                 sendAction: { 
selectAndUpdate(1) },
-                                                 recvAction: { 
selectAndUpdate(2) })
-                let spacing = CGFloat(10)                  // space between 
the two buttons
-                if Self.needVStack(titles, width: width, spacing: spacing) {
-                    VStack { twoRowButtons }
-                } else {
-                    HStack(spacing: spacing) { twoRowButtons }
-                }
-            }
-        }
-    }
-}
-// MARK: -
 /// This view shows the currency name in an exchange section
 ///         currency
 /// [Deposit Coins]  [Withdraw Coins]
@@ -101,7 +36,7 @@ struct ExchangeSectionView: View {
 }
 // MARK: -
 #if DEBUG
-struct ExchangeRow_Container : View {
+fileprivate struct ExchangeRow_Container : View {
     @State private var centsToTransfer: UInt64 = 100
 
 //    let amount = try! Amount(fromString: LONGCURRENCY + ":1234.56")
@@ -126,7 +61,7 @@ struct ExchangeRow_Container : View {
     }
 }
 
-struct ExchangeRow_Previews: PreviewProvider {
+fileprivate struct ExchangeSection_Previews: PreviewProvider {
     static var previews: some View {
         List {
             ExchangeRow_Container()
diff --git a/TalerWallet1/Views/Exchange/ManualWithdraw.swift 
b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
index 78356be..0492c95 100644
--- a/TalerWallet1/Views/Exchange/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
@@ -81,13 +81,15 @@ struct ManualWithdraw: View {
             DebugViewC.shared.setViewID(VIEW_WITHDRAWAL, stack: stack.push())
         }
         .task(id: centsToTransfer) { // re-run this whenever centsToTransfer 
changes
-            let amount = Amount.amountFromCents(currency, centsToTransfer)
-            do {
-                withdrawalAmountDetails = try await 
model.loadWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl, amount: amount)
-//                agePicker.setAges(ages: 
withdrawalAmountDetails?.ageRestrictionOptions)
-            } catch {    // TODO: error
-                symLog.log(error.localizedDescription)
-                withdrawalAmountDetails = nil
+            if centsToTransfer > 0 {
+                let amount = Amount.amountFromCents(currency, centsToTransfer)
+                do {
+                    withdrawalAmountDetails = try await 
model.loadWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl, amount: amount)
+//                  agePicker.setAges(ages: 
withdrawalAmountDetails?.ageRestrictionOptions)
+                } catch {    // TODO: error
+                    symLog.log(error.localizedDescription)
+                    withdrawalAmountDetails = nil
+                }
             }
         }
     }
diff --git a/TalerWallet1/Views/HelperViews/View+needVStack.swift 
b/TalerWallet1/Views/HelperViews/View+needVStack.swift
index e71cf72..fc6f18b 100644
--- a/TalerWallet1/Views/HelperViews/View+needVStack.swift
+++ b/TalerWallet1/Views/HelperViews/View+needVStack.swift
@@ -6,9 +6,16 @@ import SwiftUI
 import UIKit
 
 extension View {
-    /// returns true if any of the strings in 'titles' wouldn't fit in a view 
1/'numViews' the size of 'width', with 'spacing'
-    static func needVStack(_ titles: [(String, UIFont)], width: CGFloat, 
spacing: CGFloat,
-                           sameSize: Bool = true, numViews: Int = 2) -> Bool {
+    /// if sameSize then this searches for the longest title
+    /// returns true if any of the strings in 'titles' wouldn't fit in a view 
1/'numViews' of the size of 'width', with 'spacing'
+    /// if !sameSize then all titles are added with spacing
+    static func needVStack(_ titles: [(String, UIFont)],
+                              width: CGFloat,           // total width 
available
+                            spacing: CGFloat,           // between titles
+                           sameSize: Bool = true,
+                           numViews: Int = 2,
+                           currency: String = "")
+    -> Bool {
         let padding: CGFloat = 20        // TODO: depend on myListStyle
         var maxTitleWidth: CGFloat = 0
         var totalWidth = padding
@@ -25,7 +32,11 @@ extension View {
         let totalSpacing = spacing * CGFloat(numViews - 1)
         let availableWidth = (width / CGFloat(numViews)) - totalSpacing
         totalWidth += totalSpacing
-
+        if sameSize {
+            print("❗️\(currency) available: \(availableWidth)   needed: 
\(neededWidth)")
+        } else {
+            print("❗️\(currency) width: \(width)   total: \(totalWidth)")
+        }
         return sameSize ? neededWidth > availableWidth
                         : totalWidth > width
     }
diff --git a/TalerWallet1/Views/Main/MainView.swift 
b/TalerWallet1/Views/Main/MainView.swift
index a0abc93..a53dfb7 100644
--- a/TalerWallet1/Views/Main/MainView.swift
+++ b/TalerWallet1/Views/Main/MainView.swift
@@ -151,7 +151,7 @@ extension MainView {
                                   navTitle: balancesTitle,
                                   balances: $balances,
                       shouldReloadBalances: $shouldReloadBalances)
-                }
+                }.navigationViewStyle(.stack)
                 .tabItem {
                     Image(systemName: "chart.bar.xaxis")             // 
creditcard     system will automatically use filled variant
                     if !iconOnly { Text(balancesTitle) }
@@ -163,7 +163,7 @@ extension MainView {
                     ExchangeListView(stack: stack.push(exchangesTitle),
 //                                  balances: $balances,
                                   navTitle: exchangesTitle)
-                }
+                }.navigationViewStyle(.stack)
                 .tabItem {
                     Image(systemName: "building.columns")
                     if !iconOnly { Text(exchangesTitle) }
@@ -172,7 +172,7 @@ extension MainView {
 
                 NavigationView {
                     SettingsView(stack: stack.push(), navTitle: settingsTitle)
-                }
+                }.navigationViewStyle(.stack)
                 .tabItem {
                     Image(systemName: "gear")                   // system will 
automatically use filled variant
                     if !iconOnly { Text(settingsTitle) }
diff --git a/TalerWallet1/Views/Peer2peer/SendDone.swift 
b/TalerWallet1/Views/Peer2peer/SendDone.swift
index 5cfe04d..5d09df6 100644
--- a/TalerWallet1/Views/Peer2peer/SendDone.swift
+++ b/TalerWallet1/Views/Peer2peer/SendDone.swift
@@ -50,13 +50,12 @@ struct SendDone: View {
                                resumeAction: nil)
                 .navigationBarBackButtonHidden(true)
                 .interactiveDismissDisabled()           // can only use "Done" 
button to dismiss
-                .navigationTitle(navTitle)
             } else {
                 WithdrawProgressView(message: "Loading...")
-                    .navigationTitle(navTitle)
             }
         }
 //        
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+        .navigationTitle(navTitle)
         .task {
             symLog.log(".task")
             do {
@@ -69,6 +68,7 @@ struct SendDone: View {
                                         purse_expiration: timestamp)
                     // TODO: user might choose baseURL
                     let response = try await model.initiatePeerPushDebitM(nil, 
terms: terms)
+                    // will switch from WithdrawProgressView to 
TransactionDetailView
                     transactionId = response.transactionId
                 } else if let amountToReceive {
                     let terms = PeerContractTerms(amount: amountToReceive,
@@ -76,6 +76,7 @@ struct SendDone: View {
                                         purse_expiration: timestamp)
                     // TODO: user might choose baseURL
                     let response = try await 
model.initiatePeerPullCreditM(nil, terms: terms)
+                    // will switch from WithdrawProgressView to 
TransactionDetailView
                     transactionId = response.transactionId
                 } else { fatalError() }
             } catch {    // TODO: error
diff --git a/TalerWallet1/Views/Sheets/Sheet.swift 
b/TalerWallet1/Views/Sheets/Sheet.swift
index 1daa1e6..b1f0cda 100644
--- a/TalerWallet1/Views/Sheets/Sheet.swift
+++ b/TalerWallet1/Views/Sheets/Sheet.swift
@@ -14,7 +14,7 @@ struct Sheet: View {
 
     var sheetView: AnyView
 
-    let logger = Logger (subsystem: "net.taler.gnu", category: "Sheet")
+    let logger = Logger(subsystem: "net.taler.gnu", category: "Sheet")
 
     var cancelButton: some View {
         Button("Cancel") {
diff --git a/taler-swift/Sources/taler-swift/Amount.swift 
b/taler-swift/Sources/taler-swift/Amount.swift
index ea952a8..25706cf 100644
--- a/taler-swift/Sources/taler-swift/Amount.swift
+++ b/taler-swift/Sources/taler-swift/Amount.swift
@@ -50,12 +50,12 @@ public final class Amount: Codable, Hashable, @unchecked 
Sendable, CustomStringC
     /// The size of `integer` in relation to `fraction`.
     private static let fractionalBase: UInt32 = 100000000
     
-    /// The greatest number of decimal digits that can be represented.
+    /// The greatest number of fractional digits that can be represented.
     private static let fractionalBaseDigits: UInt = 8
     
-    /// The currency of the amount.
-    var currency: String
-    
+    /// The currency of the amount. Cannot be changed later
+    private let currency: String
+
     /// The integer value of the amount (number to the left of the decimal 
point).
     var integer: UInt64
     
@@ -73,18 +73,34 @@ public final class Amount: Codable, Hashable, @unchecked 
Sendable, CustomStringC
         }
     }
 
-    /// The floating point representation of the value
+    /// The floating point representation of the integer.
+    public var intValue: Double {
+        Double(integer)
+    }
+
+    /// The floating point representation of the fraction.
+    public var fracValue: Double {
+        let oneThousand = 1000.0
+        let base = Double(Amount.fractionalBase) / oneThousand
+        let thousandths = Double(fraction) / base
+        return thousandths / oneThousand
+    }
+
+    /// The floating point representation of the value.
+    /// Be careful, the value might exceed 15 digits which is the limit for 
Double.
+    /// When more significant digits are needed, use valueAsTuple.
     public var value: Double {
-        let value = Double(integer)
-        if fraction == 0 {
-            return value
-        } else {
-            let thousandths = Double(fraction / (Amount.fractionalBase / 1000))
-            return value + (thousandths / 1000.0)
-        }
+        fraction == 0 ? intValue
+                      : intValue + fracValue
+    }
+
+    /// The tuple representation of the value.
+    public var valueAsTuple: (Double, Double) {
+        (intValue, fracValue)
     }
 
-    /// The string representation of the value, formatted as 
"`integer`.`fraction`".
+    /// The string representation of the value, formatted as 
"`integer`.`fraction`",
+    /// no trailing zeroes, no group separator.
     public var valueStr: String {
         var decimalSeparator = "."
 //        if let currencySpecification {      // TODO: use locale

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