[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.
- [taler-taler-ios] branch master updated (a0c6bdb -> bf7f8e3),
gnunet <=
- [taler-taler-ios] 01/11: Assets cleanup, gnunet, 2023/10/24
- [taler-taler-ios] 02/11: Native Logging for wallet-core (QuickJS), gnunet, 2023/10/24
- [taler-taler-ios] 03/11: Logger, gnunet, 2023/10/24
- [taler-taler-ios] 05/11: Only call DetailsForAmount if non-zero, gnunet, 2023/10/24
- [taler-taler-ios] 10/11: CharacterSet+contains, gnunet, 2023/10/24
- [taler-taler-ios] 11/11: Layout for Pending - wip, gnunet, 2023/10/24
- [taler-taler-ios] 04/11: ExchangeRowView, gnunet, 2023/10/24
- [taler-taler-ios] 08/11: Cleanup, gnunet, 2023/10/24
- [taler-taler-ios] 09/11: DD51 - CurrencySpecification, gnunet, 2023/10/24
- [taler-taler-ios] 07/11: intValue, fracValue, valueAsTuple, gnunet, 2023/10/24