[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] branch master updated (8475ec0 -> 9453c61)
From: |
gnunet |
Subject: |
[taler-taler-ios] branch master updated (8475ec0 -> 9453c61) |
Date: |
Thu, 29 Feb 2024 17:19:07 +0100 |
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 8475ec0 Bump version to 0.9.4 (7)
new f7f015c Accessibility: don't automatically show keyboard when
VoiceOver is on
new cce5bdd Prepare HTML ToS
new d6a3539 fake Swiss Francs
new 0303ad6 fix JSON keys for ExchangeUpdateStatus
new 4e96de0 cleanup
new dbb3a3e ViewIDs
new 7927b34 Error, Status
new df19d03 Use HTTP lib of quickjs-tart, still with curl
new 0ce3022 Helpers
new d6e2f84 Debugging
new f39b4ca Native Networking via URLSession.dataTask
new db603ba Bump version to 0.9.4 (10)
new 23f77fb Preparation for Builtin
new c4dfcb2 Empty Exchanges
new 15d533a Empty Wallet
new 9453c61 Bump version to 0.9.4 (11)
The 16 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 | 26 +++-
TalerWallet1/Backend/WalletBackendError.swift | 9 +-
TalerWallet1/Backend/WalletCore.swift | 11 +-
TalerWallet1/Controllers/Controller.swift | 3 +-
TalerWallet1/Controllers/DebugViewC.swift | 20 +--
TalerWallet1/Controllers/PublicConstants.swift | 1 +
.../{Binding+onChange.swift => Atomic.swift} | 63 ++++++---
TalerWallet1/Helper/CStringArray.swift | 74 ++++++++++
TalerWallet1/Helper/CurrencySpecification.swift | 12 ++
TalerWallet1/Model/Model+Exchange.swift | 9 +-
TalerWallet1/Model/Model+Withdraw.swift | 32 +++--
TalerWallet1/Model/WalletModel.swift | 7 +
TalerWallet1/Quickjs/QuickDataTask.swift | 156 +++++++++++++++++++++
TalerWallet1/Quickjs/quickjs.swift | 92 ++++++++----
TalerWallet1/Views/Balances/BalanceRowView.swift | 15 +-
TalerWallet1/Views/Balances/TwoRowButtons.swift | 39 +++---
TalerWallet1/Views/Banking/DepositAmountV.swift | 2 +-
TalerWallet1/Views/Banking/DepositIbanV.swift | 12 +-
TalerWallet1/Views/Banking/ExchangeListView.swift | 22 ++-
TalerWallet1/Views/Banking/ExchangeRowView.swift | 22 +--
TalerWallet1/Views/Banking/ManualWithdraw.swift | 22 ++-
TalerWallet1/Views/HelperViews/AmountInputV.swift | 4 +-
TalerWallet1/Views/HelperViews/Buttons.swift | 4 +-
.../Views/HelperViews/CurrencyInputView.swift | 2 +-
TalerWallet1/Views/HelperViews/SelectDays.swift | 9 +-
TalerWallet1/Views/HelperViews/SubjectInputV.swift | 12 +-
TalerWallet1/Views/Main/WalletEmptyView.swift | 18 ++-
TalerWallet1/Views/Peer2peer/P2PSubjectV.swift | 14 +-
TalerWallet1/Views/Peer2peer/RequestPayment.swift | 2 +-
TalerWallet1/Views/Settings/AboutView.swift | 7 +-
.../WithdrawBankIntegrated/WithdrawTOSView.swift | 2 +-
.../WithdrawBankIntegrated/WithdrawURIView.swift | 9 +-
TalerWallet1/Views/Sheets/WithdrawExchangeV.swift | 7 +-
.../Views/Transactions/ThreeAmountsV.swift | 1 +
.../Views/Transactions/TransactionSummaryV.swift | 14 +-
.../Views/Transactions/TransactionsEmptyView.swift | 7 +-
TestFlight/WhatToTest.en-US.txt | 23 +++
37 files changed, 600 insertions(+), 184 deletions(-)
copy TalerWallet1/Helper/{Binding+onChange.swift => Atomic.swift} (55%)
create mode 100644 TalerWallet1/Helper/CStringArray.swift
create mode 100644 TalerWallet1/Quickjs/QuickDataTask.swift
diff --git a/TalerWallet.xcodeproj/project.pbxproj
b/TalerWallet.xcodeproj/project.pbxproj
index a2faa33..31b80f7 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -240,6 +240,12 @@
4ECB62802A0BA6DF004ABBB7 /* Model+P2P.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */;
};
4ECB62822A0BB01D004ABBB7 /* SelectDays.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */;
};
4ED2F94B2A278F5100453B40 /* ThreeAmountsV.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift
*/; };
+ 4ED80E882B8F5FB8008BD576 /* CStringArray.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ED80E872B8F5FB8008BD576 /* CStringArray.swift
*/; };
+ 4ED80E892B8F5FB8008BD576 /* CStringArray.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ED80E872B8F5FB8008BD576 /* CStringArray.swift
*/; };
+ 4ED80E8B2B8F60E7008BD576 /* Atomic.swift in Sources */ = {isa =
PBXBuildFile; fileRef = 4ED80E8A2B8F60E7008BD576 /* Atomic.swift */; };
+ 4ED80E8C2B8F60E7008BD576 /* Atomic.swift in Sources */ = {isa =
PBXBuildFile; fileRef = 4ED80E8A2B8F60E7008BD576 /* Atomic.swift */; };
+ 4ED80E8E2B8F6212008BD576 /* QuickDataTask.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ED80E8D2B8F6212008BD576 /* QuickDataTask.swift
*/; };
+ 4ED80E8F2B8F6212008BD576 /* QuickDataTask.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4ED80E8D2B8F6212008BD576 /* QuickDataTask.swift
*/; };
4EDBDCD92AB787CB00925C02 /* CallStack.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4EDBDCD82AB787CB00925C02 /* CallStack.swift */;
};
4EDBDCDA2AB787CB00925C02 /* CallStack.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4EDBDCD82AB787CB00925C02 /* CallStack.swift */;
};
4EE171882B49635800BF9FF5 /* MarkdownUI in Frameworks */ = {isa
= PBXBuildFile; productRef = 4EE171872B49635800BF9FF5 /* MarkdownUI */; };
@@ -425,6 +431,9 @@
4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= "Model+P2P.swift"; sourceTree = "<group>"; };
4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= SelectDays.swift; sourceTree = "<group>"; };
4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= ThreeAmountsV.swift; sourceTree = "<group>"; };
+ 4ED80E872B8F5FB8008BD576 /* CStringArray.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= CStringArray.swift; sourceTree = "<group>"; };
+ 4ED80E8A2B8F60E7008BD576 /* Atomic.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= Atomic.swift; sourceTree = "<group>"; };
+ 4ED80E8D2B8F6212008BD576 /* QuickDataTask.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= QuickDataTask.swift; sourceTree = "<group>"; };
4EDBDCD82AB787CB00925C02 /* CallStack.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= CallStack.swift; sourceTree = "<group>"; };
4EEC118C2B83DE4700146CFF /* AmountInputV.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= AmountInputV.swift; sourceTree = "<group>"; };
4EEC11922B83FB7A00146CFF /* SubjectInputV.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= SubjectInputV.swift; sourceTree = "<group>"; };
@@ -600,7 +609,9 @@
children = (
4E363CBD2A23CB2100D7E98C /*
AnyTransition+backslide.swift */,
4E3327B92AD1635100BF5AD6 /*
AsyncSemaphore.swift */,
+ 4ED80E8A2B8F60E7008BD576 /* Atomic.swift */,
4EDBDCD82AB787CB00925C02 /* CallStack.swift */,
+ 4ED80E872B8F5FB8008BD576 /* CStringArray.swift
*/,
4E16E12229F3BB99008B9C86 /*
CurrencySpecification.swift */,
4EAD117529F672FA008EDD0B /*
KeyboardResponder.swift */,
4E363CC12A2621C200D7E98C /*
LocalizedAlertError.swift */,
@@ -626,6 +637,7 @@
isa = PBXGroup;
children = (
4EB0950D2989CB9A0043A8A1 /* quickjs.swift */,
+ 4ED80E8D2B8F6212008BD576 /* QuickDataTask.swift
*/,
);
path = Quickjs;
sourceTree = "<group>";
@@ -1091,6 +1103,7 @@
4E3EAE2B2A990778009F1BE8 /* LoadingView.swift
in Sources */,
4E3EAE8C2AA0933C009F1BE8 /* Font+Taler.swift in
Sources */,
4E3327BA2AD1635100BF5AD6 /*
AsyncSemaphore.swift in Sources */,
+ 4ED80E8E2B8F6212008BD576 /* QuickDataTask.swift
in Sources */,
4E3EAE2C2A990778009F1BE8 /*
ManualWithdraw.swift in Sources */,
4E3EAE2D2A990778009F1BE8 /*
Model+Exchange.swift in Sources */,
4EBC0F012B7B3CD600C0CB19 /* DepositIbanV.swift
in Sources */,
@@ -1162,6 +1175,7 @@
4E3EAE692A990778009F1BE8 /* URLSheet.swift in
Sources */,
4E3EAE6A2A990778009F1BE8 /* ThreeAmountsV.swift
in Sources */,
4E3EAE6B2A990778009F1BE8 /*
Model+Withdraw.swift in Sources */,
+ 4ED80E882B8F5FB8008BD576 /* CStringArray.swift
in Sources */,
4E3EAE6C2A990778009F1BE8 /*
ExchangeSectionView.swift in Sources */,
4E3EAE6D2A990778009F1BE8 /* P2PSubjectV.swift
in Sources */,
4E6EF56B2B65A33300AF252A /* PaymentDone.swift
in Sources */,
@@ -1169,6 +1183,7 @@
4E3EAE6F2A990778009F1BE8 /* TalerStrings.swift
in Sources */,
4E3EAE702A990778009F1BE8 /*
CurrencyInputView.swift in Sources */,
4E3EAE712A990778009F1BE8 /* URL+id+iban.swift
in Sources */,
+ 4ED80E8B2B8F60E7008BD576 /* Atomic.swift in
Sources */,
4EEC3A712B2285A200D05F9D /*
WithdrawExchangeV.swift in Sources */,
4EDBDCD92AB787CB00925C02 /* CallStack.swift in
Sources */,
4E3EAE722A990778009F1BE8 /*
RequestPayment.swift in Sources */,
@@ -1204,6 +1219,7 @@
4EB0956D2989CBFE0043A8A1 /* LoadingView.swift
in Sources */,
4E3EAE8D2AA0933C009F1BE8 /* Font+Taler.swift in
Sources */,
4E3327BB2AD1635100BF5AD6 /*
AsyncSemaphore.swift in Sources */,
+ 4ED80E8F2B8F6212008BD576 /* QuickDataTask.swift
in Sources */,
4E50B3502A1BEE8000F9F01C /*
ManualWithdraw.swift in Sources */,
4E3B4BC92A42BC4800CC88B8 /*
Model+Exchange.swift in Sources */,
4EBC0F022B7B3CD600C0CB19 /* DepositIbanV.swift
in Sources */,
@@ -1275,6 +1291,7 @@
4EB0955A2989CBFE0043A8A1 /* URLSheet.swift in
Sources */,
4ED2F94B2A278F5100453B40 /* ThreeAmountsV.swift
in Sources */,
4EB095622989CBFE0043A8A1 /*
Model+Withdraw.swift in Sources */,
+ 4ED80E892B8F5FB8008BD576 /* CStringArray.swift
in Sources */,
4EC90C782A1B528B0071DC58 /*
ExchangeSectionView.swift in Sources */,
4E7940DE29FC307C00A9AEA1 /* P2PSubjectV.swift
in Sources */,
4E6EF56C2B65A33300AF252A /* PaymentDone.swift
in Sources */,
@@ -1282,6 +1299,7 @@
4EB0950A2989CB7C0043A8A1 /* TalerStrings.swift
in Sources */,
4EA551252A2C923600FEC9A8 /*
CurrencyInputView.swift in Sources */,
4E363CBC2A237E0900D7E98C /* URL+id+iban.swift
in Sources */,
+ 4ED80E8C2B8F60E7008BD576 /* Atomic.swift in
Sources */,
4EEC3A722B2285A200D05F9D /*
WithdrawExchangeV.swift in Sources */,
4EDBDCDA2AB787CB00925C02 /* CallStack.swift in
Sources */,
4E9320452A1645B600A87B0E /*
RequestPayment.swift in Sources */,
@@ -1335,7 +1353,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 7;
+ CURRENT_PROJECT_VERSION = 11;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1377,7 +1395,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 7;
+ CURRENT_PROJECT_VERSION = 11;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1536,7 +1554,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 7;
+ CURRENT_PROJECT_VERSION = 11;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1578,7 +1596,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 7;
+ CURRENT_PROJECT_VERSION = 11;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
diff --git a/TalerWallet1/Backend/WalletBackendError.swift
b/TalerWallet1/Backend/WalletBackendError.swift
index 802d027..9b4cea4 100644
--- a/TalerWallet1/Backend/WalletBackendError.swift
+++ b/TalerWallet1/Backend/WalletBackendError.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import Foundation
/// Errors for `WalletBackend`.
@@ -40,4 +43,8 @@ extension WalletCore {
static func parseFailureError() -> WalletBackendResponseError {
return WalletBackendResponseError(talerErrorCode: -3, talerErrorHint:
"Could not parse error detail.", message: "")
}
+
+ static func walletError() -> WalletBackendResponseError {
+ return WalletBackendResponseError(talerErrorCode: -4, talerErrorHint:
"Error detail.", message: "")
+ }
}
diff --git a/TalerWallet1/Backend/WalletCore.swift
b/TalerWallet1/Backend/WalletCore.swift
index d251897..6e50295 100644
--- a/TalerWallet1/Backend/WalletCore.swift
+++ b/TalerWallet1/Backend/WalletCore.swift
@@ -102,20 +102,21 @@ extension WalletCore {
if let walletError = decoded.error { // wallet-core sent an
error message
do {
let jsonData = try JSONEncoder().encode(walletError)
+ logger.error("wallet-core sent back an error for request
\(requestId, privacy: .public)")
+ symLog.log("id:\(requestId) \(walletError)")
+ // TODO: decode jsonData to WalletBackendResponseError - or
HTTPError
+ completion(requestId, timeSent, jsonData,
WalletCore.walletError())
} catch { // JSON encoding of response.result failed /
should never happen
symLog.log(decoded)
logger.error("cannot encode wallet-core Error")
// TODO: show error alert
completion(requestId, timeSent, nil,
WalletCore.parseFailureError())
}
- // TODO: decode jsonData to WalletBackendResponseError - or
HTTPError
- logger.error("wallet-core sent back an error for request
\(requestId, privacy: .public)")
-// completion(requestId, timeSent, nil, walletError)
- completion(requestId, timeSent, nil,
WalletCore.parseFailureError())
- } else { // JSON decoding of
error message failed
+ } else { // JSON decoding of error message failed
completion(requestId, timeSent, nil,
WalletCore.parseFailureError())
}
}
+
private func handleResponse(_ decoded: ResponseOrNotification) throws {
guard let requestId = decoded.id else {
logger.error("didn't find requestId in response")
diff --git a/TalerWallet1/Controllers/Controller.swift
b/TalerWallet1/Controllers/Controller.swift
index cc8d3f0..51dd5a3 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -69,7 +69,8 @@ class Controller: ObservableObject {
}
func info(for currency: String) -> CurrencyInfo? {
-// return CurrencyInfo.euro() // FAKE EURO instead of the
real Currency
+// return CurrencyInfo.euro() // Fake EUR instead of the
real Currency
+// return CurrencyInfo.francs() // Fake CHF instead of the
real Currency
for info in currencyInfos {
if info.scope.currency == currency {
return info
diff --git a/TalerWallet1/Controllers/DebugViewC.swift
b/TalerWallet1/Controllers/DebugViewC.swift
index 0f05cab..8cd8108 100644
--- a/TalerWallet1/Controllers/DebugViewC.swift
+++ b/TalerWallet1/Controllers/DebugViewC.swift
@@ -25,23 +25,24 @@ import os.log
// Numbering Scheme for Views
// MARK: - Main View
-public let VIEW_EMPTY = 10 // 10
WalletEmptyView
-public let VIEW_BALANCES = VIEW_EMPTY + 1 // 11
BalancesListView
-public let VIEW_EXCHANGES = VIEW_BALANCES + 1 // 12
ExchangeListView
-public let VIEW_SETTINGS = VIEW_EXCHANGES + 1 // 13
SettingsView
+public let VIEW_EMPTY_WALLET = 10 // 10
WalletEmptyView
+public let VIEW_BALANCES = VIEW_EMPTY_WALLET + 1 // 11
BalancesListView
+public let VIEW_BANKING = VIEW_BALANCES + 1 // 12
ExchangeListView
+public let VIEW_SETTINGS = VIEW_BANKING + 1 // 13
SettingsView
public let VIEW_ABOUT = VIEW_SETTINGS + 1 // 14
AboutView
//public let VIEW_PENDING = VIEW_ABOUT + 1 // 15
PendingOpsListView
// MARK: Transactions
-public let VIEW_TRANSACTIONLIST = VIEW_EMPTY + 10 // 20
TransactionsListView
-public let VIEW_TRANSACTIONSUMMARY = VIEW_TRANSACTIONLIST + 1 // 21
TransactionSummary
-public let VIEW_TRANSACTIONDETAIL = VIEW_TRANSACTIONSUMMARY + 1 // 22
TransactionDetail
+public let VIEW_EMPTY_HISTORY = VIEW_EMPTY_WALLET + 10 // 20
TransactionsEmptyView
+public let VIEW_TRANSACTIONLIST = VIEW_EMPTY_HISTORY + 1 // 21
TransactionsListView
+public let VIEW_TRANSACTIONSUMMARY = VIEW_TRANSACTIONLIST + 1 // 22
TransactionSummary
+public let VIEW_TRANSACTIONDETAIL = VIEW_TRANSACTIONSUMMARY + 1 // 23
TransactionDetail
// MARK: - Manual Withdrawal (from Banking / ExchangeList)
// receive coins from bank ==> shows IBAN + Purpose/Subject for manual wire
transfer
-public let VIEW_WITHDRAWAL = VIEW_TRANSACTIONLIST + 10 // 30
WithdrawAmount
+public let VIEW_WITHDRAWAL = VIEW_EMPTY_HISTORY + 10 // 30
WithdrawAmount
public let VIEW_WITHDRAW_TOS = VIEW_WITHDRAWAL + 1 // 31
WithdrawTOSView
public let VIEW_WITHDRAW_ACCEPT = VIEW_WITHDRAW_TOS + 1 // 32
@@ -77,6 +78,9 @@ public let SHEET_WITHDRAW_TOS = SHEET_WITHDRAWAL + 1
// 131 Withd
public let SHEET_WITHDRAW_ACCEPT = SHEET_WITHDRAW_TOS + 1 // 132
WithdrawAcceptView
public let SHEET_WITHDRAW_CONFIRM = SHEET_WITHDRAW_ACCEPT + 1 // 133
waiting for bank confirmation
+public let SHEET_WITHDRAW_EXCHANGE = SHEET_WITHDRAWAL + 5 // 135
WithdrawExchangeV
+
+
// MARK: Merchant Payment
// openURL (Link, NFC or scan QR) ==> pays merchant
public let SHEET_PAYMENT = SHEET_WITHDRAWAL + 10 // 140 Pay
Merchant
diff --git a/TalerWallet1/Controllers/PublicConstants.swift
b/TalerWallet1/Controllers/PublicConstants.swift
index 6fda1f3..2eb2ad8 100644
--- a/TalerWallet1/Controllers/PublicConstants.swift
+++ b/TalerWallet1/Controllers/PublicConstants.swift
@@ -51,6 +51,7 @@ public let LONGCURRENCY = "GOLDLATINUM"
// 11 characters
public let PLAINTEXT = "text/plain"
public let MARKDOWN = "text/markdown"
+public let HTML = "text/html"
public let EXCHANGEBASEURL = "exchangeBaseUrl"
public let TALERURI = "talerUri"
diff --git a/TalerWallet1/Helper/Binding+onChange.swift
b/TalerWallet1/Helper/Atomic.swift
similarity index 55%
copy from TalerWallet1/Helper/Binding+onChange.swift
copy to TalerWallet1/Helper/Atomic.swift
index 7bf8a5f..fb9604a 100644
--- a/TalerWallet1/Helper/Binding+onChange.swift
+++ b/TalerWallet1/Helper/Atomic.swift
@@ -1,5 +1,5 @@
-// MIT License
-// Copyright © Paul Hudson
+//
+// Copyright 2023 Marc Stibane
//
// Permission is hereby granted, free of charge, to any person obtaining a
copy of this software
// and associated documentation files (the "Software"), to deal in the
Software without restriction,
@@ -16,30 +16,47 @@
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
//
-import SwiftUI
+import Foundation
+
+@propertyWrapper
+class Atomic<Value> where Value: BinaryInteger {
-/// Pass the handler directly to the Binding
-extension Binding {
- func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value> {
- Binding (
- get: { self.wrappedValue },
- set: { newValue in
- self.wrappedValue = newValue
- handler(newValue)
- }
- )
+ private let lock: NSLock
+ private var value: Value
+
+ init(default: Value) {
+ self.lock = NSLock()
+ self.value = `default`
}
-}
-#if false
-// use like this:
-struct BindingView: View {
- @State private var rating = 0.0
- var body: some View {
- Slider (value: $rating.onChange(sliderChanged))
+ var wrappedValue: Value {
+ get {
+ lock.lock()
+ defer { lock.unlock() }
+ return value
+ }
+ set {
+ lock.lock()
+ value = newValue
+ lock.unlock()
+ }
}
- func sliderChanged(_ value: Double) {
- print ("Rating changed to \(value)")
+
+ var projectedValue: Atomic<Value> { self }
+
+ @discardableResult
+ func atomicIncrement() -> Value {
+ lock.lock()
+ defer { lock.unlock() }
+ self.value += 1
+ return value
+ }
+
+ @discardableResult
+ func atomicAdd(_ value: Value) -> Value {
+ lock.lock()
+ defer { lock.unlock() }
+ self.value += value
+ return value
}
}
-#endif
diff --git a/TalerWallet1/Helper/CStringArray.swift
b/TalerWallet1/Helper/CStringArray.swift
new file mode 100644
index 0000000..62b8e96
--- /dev/null
+++ b/TalerWallet1/Helper/CStringArray.swift
@@ -0,0 +1,74 @@
+//
+// Copyright 2020 Robert Salesas
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
copy of this software
+// and associated documentation files (the "Software"), to deal in the
Software without restriction,
+// including without limitation the rights to use, copy, modify, merge,
publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to
whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING
+// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+//
+import Foundation
+
+/// `CStringArray` represents a C null-terminated array of pointers to C
strings.
+///
+/// The lifetime of the C strings will correspond to the lifetime of the
`CStringArray`
+/// instance so be careful about copying the buffer as it may contain dangling
pointers.
+
+public struct CStringArray {
+ public let pointer: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>
+ public let count: Int
+ private var data: Data
+
+ public init(_ array: [String]) {
+ let count = array.count
+
+ // Allocate memory to hold the CStrings and a terminating nil
+ let pointer =
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>.allocate(capacity: count + 1)
+ pointer.initialize(repeating: nil, count: count + 1) // Implicit
terminating nil at the end of the array
+
+ // Populate the allocated memory with pointers to CStrings
+ var e = 0
+ array.forEach {
+ pointer[e] = strdup($0)
+ e += 1
+ }
+
+ // This uses the deallocator available on the data structure as a
solution to the fact that structs do not have `deinit`
+ self.data = Data(bytesNoCopy: pointer, count:
MemoryLayout<UnsafeMutablePointer<CChar>>.size * count, deallocator:
.custom({_,_ in
+ for i in 0...count - 1 {
+ free(pointer[i])
+ }
+ pointer.deallocate()
+ }))
+
+ self.pointer = pointer
+ self.count = array.count
+ }
+
+ public subscript(index: Data.Index) -> UnsafeMutablePointer<CChar>? {
+ get {
+ precondition(index >= 0 && index < count, "Index out of range")
+ return pointer[index]
+ }
+ }
+
+ public subscript(index: Data.Index) -> String? {
+ get {
+ precondition(index >= 0 && index < count, "Index out of range")
+ if let pointee = pointer[index] {
+ return String(cString: pointee)
+ }
+
+ return nil
+ }
+ }
+}
diff --git a/TalerWallet1/Helper/CurrencySpecification.swift
b/TalerWallet1/Helper/CurrencySpecification.swift
index 2f0319b..96a32ca 100644
--- a/TalerWallet1/Helper/CurrencySpecification.swift
+++ b/TalerWallet1/Helper/CurrencySpecification.swift
@@ -90,6 +90,18 @@ public struct CurrencyInfo {
return CurrencyInfo(scope: scope, specs: specs, formatter: formatter)
}
+ public static func francs() -> CurrencyInfo {
+ let currency = "CHF"
+ let scope = ScopeInfo(type: .global, currency: currency)
+ let specs = CurrencySpecification(name: currency,
+ fractionalInputDigits: 2,
+ fractionalNormalDigits: 2,
+ fractionalTrailingZeroDigits: 2,
+ altUnitNames: [0 : "CHF"])
+ let formatter = CurrencyFormatter.formatter(scope: scope, specs: specs)
+ return CurrencyInfo(scope: scope, specs: specs, formatter: formatter)
+ }
+
/// returns all characters left from the decimalSeparator
func integerPartStr(_ integerStr: String, decimalSeparator: String) ->
String {
if let integerIndex = integerStr.endIndex(of: decimalSeparator) {
diff --git a/TalerWallet1/Model/Model+Exchange.swift
b/TalerWallet1/Model/Model+Exchange.swift
index f99bda1..e51caa8 100644
--- a/TalerWallet1/Model/Model+Exchange.swift
+++ b/TalerWallet1/Model/Model+Exchange.swift
@@ -1,5 +1,5 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
import Foundation
@@ -19,12 +19,12 @@ enum ExchangeEntryStatus: String, Codable {
enum ExchangeUpdateStatus: String, Codable {
case initial
- case initialUpdate = "initial(update)"
+ case initialUpdate = "initial-update"
case suspended
case failed
- case outdatedUpdate = "outdated(update)"
+ case outdatedUpdate = "outdated-update"
case ready
- case readyUpdate = "ready(update)"
+ case readyUpdate = "ready-update"
}
// MARK: -
/// The result from wallet-core's ListExchanges
@@ -176,6 +176,7 @@ extension WalletModel {
let response = try await sendRequest(request, ASYNCDELAY)
return response.exchanges
} catch {
+ // TODO: Error
return [] // empty, but not nil
}
}
diff --git a/TalerWallet1/Model/Model+Withdraw.swift
b/TalerWallet1/Model/Model+Withdraw.swift
index a2d3ca9..3a624c4 100644
--- a/TalerWallet1/Model/Model+Withdraw.swift
+++ b/TalerWallet1/Model/Model+Withdraw.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import Foundation
import taler_swift
import SymLog
@@ -180,32 +183,31 @@ fileprivate struct AcceptManualWithdrawal:
WalletBackendFormattedRequest {
// MARK: -
extension WalletModel {
/// load withdraw-exchange details. Networking involved
- @MainActor
- func loadWithdrawalExchangeForUriM(_ talerUri: String) // M
for MainActor
+ @MainActor // M for MainActor
+ func loadWithdrawalExchangeForUriM(_ talerUri: String)
async throws -> WithdrawExchangeResponse {
let request = PrepareWithdrawExchange(talerUri: talerUri)
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
/// load withdrawal details. Networking involved
- @MainActor
- func loadWithdrawalDetailsForUriM(_ talerWithdrawUri: String)
// M for MainActor
+ @MainActor // M for MainActor
+ func getWithdrawalDetailsForUriM(_ talerWithdrawUri: String)
async throws -> WithdrawUriInfoResponse {
let request = GetWithdrawalDetailsForURI(talerWithdrawUri:
talerWithdrawUri)
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
- @MainActor
- func loadWithdrawalDetailsForAmountM(_ exchangeBaseUrl: String, amount:
Amount) // M for MainActor
+ @MainActor // M for MainActor
+ func getWithdrawalDetailsForAmountM(_ exchangeBaseUrl: String, amount:
Amount)
async throws -> WithdrawalAmountDetails {
let request = GetWithdrawalDetailsForAmount(exchangeBaseUrl:
exchangeBaseUrl,
amount: amount)
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
- @MainActor
+ @MainActor // M for MainActor
func loadExchangeTermsOfServiceM(_ exchangeBaseUrl: String,
acceptedFormat: [String], acceptLanguage: String)
- // M for MainActor
async throws -> ExchangeTermsOfService {
let request = GetExchangeTermsOfService(exchangeBaseUrl:
exchangeBaseUrl,
acceptedFormat:
acceptedFormat,
@@ -213,22 +215,22 @@ extension WalletModel {
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
- @MainActor
- func setExchangeTOSAcceptedM(_ exchangeBaseUrl: String, etag: String)
// M for MainActor
+ @MainActor // M for MainActor
+ func setExchangeTOSAcceptedM(_ exchangeBaseUrl: String, etag: String)
async throws -> Decodable {
let request = SetExchangeTOSAccepted(exchangeBaseUrl: exchangeBaseUrl,
etag: etag)
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
- @MainActor
- func sendAcceptIntWithdrawalM(_ exchangeBaseUrl: String, withdrawURL:
String) // M for MainActor
+ @MainActor // M for MainActor
+ func sendAcceptIntWithdrawalM(_ exchangeBaseUrl: String, withdrawURL:
String)
async throws -> AcceptWithdrawalResponse? {
let request = AcceptBankIntegratedWithdrawal(talerWithdrawUri:
withdrawURL, exchangeBaseUrl: exchangeBaseUrl)
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
- @MainActor
- func sendAcceptManualWithdrawalM(_ exchangeBaseUrl: String, amount:
Amount, restrictAge: Int?) // M for MainActor
+ @MainActor // M for MainActor
+ func sendAcceptManualWithdrawalM(_ exchangeBaseUrl: String, amount:
Amount, restrictAge: Int?)
async throws -> AcceptManualWithdrawalResult? {
let request = AcceptManualWithdrawal(exchangeBaseUrl: exchangeBaseUrl,
amount: amount, restrictAge: restrictAge)
let response = try await sendRequest(request, ASYNCDELAY)
diff --git a/TalerWallet1/Model/WalletModel.swift
b/TalerWallet1/Model/WalletModel.swift
index 86cf4e6..49ee759 100644
--- a/TalerWallet1/Model/WalletModel.swift
+++ b/TalerWallet1/Model/WalletModel.swift
@@ -92,6 +92,8 @@ fileprivate struct InitRequest: WalletBackendFormattedRequest
{
func operation() -> String { "init" }
func args() -> Args {
let testing = Testing(devModeActive: false) // true, false
+ let builtin = Builtin(exchanges: [])
+// let config = Config(testing: testing, builtin: builtin)
let config = Config(testing: testing)
return Args(persistentStoragePath: persistentStoragePath,
// cryptoWorkerType: "sync",
@@ -106,8 +108,13 @@ fileprivate struct InitRequest:
WalletBackendFormattedRequest {
var devModeActive: Bool
// more to come...
}
+ struct Builtin: Encodable {
+ var exchanges: [String]
+ // more to come...
+ }
struct Config: Encodable {
var testing: Testing
+// var builtin: Builtin
}
struct Args: Encodable {
var persistentStoragePath: String
diff --git a/TalerWallet1/Quickjs/QuickDataTask.swift
b/TalerWallet1/Quickjs/QuickDataTask.swift
new file mode 100644
index 0000000..e4afe88
--- /dev/null
+++ b/TalerWallet1/Quickjs/QuickDataTask.swift
@@ -0,0 +1,156 @@
+/*
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
+ * See LICENSE.md
+ */
+/**
+ * @author Marc Stibane
+ */
+import Foundation
+//import "Foundation/NSURLError.h"
+import os.log
+
+import FTalerWalletcore
+
+// will be called from wallet-core for networking
+func request_create(userdata: Optional<UnsafeMutableRawPointer>,
+ requestInfo:
Optional<UnsafeMutablePointer<JSHttpRequestInfo>>) -> Int32 {
+ let quickjs =
Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
+
+ if let requestInfo {
+ if let url = URL(string: String(cString: requestInfo.pointee.url)) {
+ let responseCb = requestInfo.pointee.response_cb
+ let responseCbCls = requestInfo.pointee.response_cb_cls
+ let method = String(cString: requestInfo.pointee.method)
+ let requestHeaders = requestInfo.pointee.request_headers
+ let redirect = requestInfo.pointee.redirect //
TODO: redirect
+ let timeoutMs = requestInfo.pointee.timeout_ms
+ let debug = requestInfo.pointee.debug //
TODO: debug
+ let reqBody = requestInfo.pointee.req_body
+ let bodyLen = requestInfo.pointee.req_body_len
+
+ var request = URLRequest(url: url)
+ request.httpMethod = method
+ request.timeoutInterval = TimeInterval(timeoutMs)
+ if let reqBody { // caller will deallocate the req_body
after dataTask finish or cancel
+ let body = Data(bytesNoCopy: reqBody, count: Int(bodyLen),
deallocator: .none)
+ request.httpBody = body
+ }
+ if var ptr = requestHeaders {
+ while let cString = ptr.pointee {
+ let string = String(cString: cString)
+ if let index = string.firstIndex(of: ":") {
+ let headerField = string.prefix(upTo: index)
+ let nextIndex = string.index(index, offsetBy: 1)
// skip the ":"
+ let value = string.suffix(from: nextIndex)
+ request.addValue(String(value), forHTTPHeaderField:
String(headerField))
+ }
+ ptr += 1
+ }
+ }
+
+ return quickjs.reqCreate(request, responseCb, responseCbCls)
+ }
+ }
+ return 0
+}
+
+func request_cancel(userdata: Optional<UnsafeMutableRawPointer>,
+ requestID: Int32) -> Int32 {
+ let quickjs =
Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
+ return quickjs.reqCancel(requestID)
+}
+// MARK: -
+class QuickDataTask: NSObject {
+ let urlSession: URLSession
+ let request: URLRequest
+ let requestID: Int32
+ var requests: [Int32: QuickDataTask]
+ let responseCb: JSHttpResponseCb?
+ let responseCbCls: Optional<UnsafeMutableRawPointer>
+
+ var dataTask: URLSessionDataTask? = nil
+ var logger: Logger
+
+ init(urlSession: URLSession,
+ request: URLRequest,
+ requestID: Int32,
+ requests: inout [Int32: QuickDataTask],
+ responseCb: JSHttpResponseCb?,
+ responseCbCls: Optional<UnsafeMutableRawPointer>
+ ) {
+ self.logger = Logger(subsystem: "net.taler.gnu", category:
"Networking")
+ self.urlSession = urlSession
+ self.request = request
+ self.requestID = requestID
+ self.requests = requests
+ self.responseCb = responseCb
+ self.responseCbCls = responseCbCls
+ }
+ func run() {
+ if let responseCb, let responseCbCls {
+ let method = self.request.httpMethod ?? "Unknown"
+ let url = self.request.url?.absoluteString ?? EMPTYSTRING
+ logger.trace("❓\(self.requestID, privacy: .public) \(method,
privacy: .public) \(url, privacy: .public)")
+ dataTask = urlSession.dataTask(with: request) { [self] data,
response, error in
+ let err: Error
+ if let response = response as? HTTPURLResponse {
+ var headerArray: [String] = []
+ var numHeaders: Int32 = 0
+ var status = Int32(response.statusCode)
+ var errmsg =
HTTPURLResponse.localizedString(forStatusCode: Int(status))
+ var errmsg_p0 = UnsafeMutablePointer<CChar>(mutating:
errmsg.cString(using: .utf8))
+ // Initialization of 'UnsafeMutablePointer<CChar>' (aka
'UnsafeMutablePointer<Int8>') results in a dangling pointer
+ let headers = response.allHeaderFields
+ for (key,value) in headers {
+ headerArray.append("\(key): \(value)")
+ numHeaders += 1
+ }
+ let cHeaders = CStringArray(headerArray)
+
+ if let data {
+ var ndata:NSData = data as NSData
+ var bodyPtr = UnsafeMutableRawPointer(mutating:
ndata.bytes)
+ var responseInfo = JSHttpResponseInfo(request_id:
self.requestID,
+ status: status,
+ errmsg:
errmsg_p0,
+ response_headers:
cHeaders.pointer,
+ num_response_headers:
numHeaders,
+ body: bodyPtr,
+ body_len:
data.count)
+ let responseInfoPtr =
UnsafeMutablePointer<JSHttpResponseInfo>(&responseInfo)
+ // Initialization of
'UnsafeMutablePointer<JSHttpResponseInfo>' results in a dangling pointer
+ logger.trace("❗️ \(self.requestID, privacy: .public)
\(url, privacy: .public)")
+ responseCb(responseCbCls, responseInfoPtr)
+ return
+ } else { // data == nil
+ logger.error("‼️\(self.requestID, privacy: .public)
\(method, privacy: .public) \(response.statusCode, privacy: .public) \(errmsg,
privacy: .public)")
+ var responseInfo = JSHttpResponseInfo(request_id:
self.requestID,
+ status:
status,
+ errmsg:
errmsg_p0,
+ response_headers:
cHeaders.pointer,
+ num_response_headers:
numHeaders,
+ body: nil,
+ body_len: 0)
+ let responseInfoPtr =
UnsafeMutablePointer<JSHttpResponseInfo>(&responseInfo)
+ responseCb(responseCbCls, responseInfoPtr)
+ }
+ } else {
+ var errmsg = "No http response from \(url)"
+ logger.error("⁉️\(self.requestID, privacy: .public)
\(method, privacy: .public) \(errmsg, privacy: .public)")
+ var errmsg_p0 = UnsafeMutablePointer<CChar>(mutating:
errmsg.cString(using: .utf8))
+ var responseInfo = JSHttpResponseInfo(request_id:
self.requestID,
+ status: 0,
+ errmsg: errmsg_p0,
+ response_headers:
nil,
+
num_response_headers: 0,
+ body: nil,
+ body_len: 0)
+ let responseInfoPtr =
UnsafeMutablePointer<JSHttpResponseInfo>(&responseInfo)
+ responseCb(responseCbCls, responseInfoPtr)
+ }
+ requests[requestID] = nil
+ }
+ dataTask?.resume()
+ }
+ }
+}
diff --git a/TalerWallet1/Quickjs/quickjs.swift
b/TalerWallet1/Quickjs/quickjs.swift
index 89728ac..dbe796d 100644
--- a/TalerWallet1/Quickjs/quickjs.swift
+++ b/TalerWallet1/Quickjs/quickjs.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import Foundation
import os.log
@@ -13,40 +16,48 @@ public protocol QuickjsMessageHandler: AnyObject {
// MARK: -
func notification_callback(userdata: Optional<UnsafeMutableRawPointer>,
payload: Optional<UnsafePointer<Int8>>) {
- let native = Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
+ let quickjs =
Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
let string = String(cString: payload!)
- native.internalOnNotify(payload: string)
+ quickjs.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 logger = native.logger
- let theTag = String(cString: tag!)
- let theMessage = String(cString: message!)
+ let quickjs =
Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
+ let logger = quickjs.logger
+ let swiftTag = String(cString: tag!)
+ let swiftMessage = String(cString: message!)
switch level {
case TALER_WALLET_LOG_ERROR:
- logger.error("\(theTag, privacy: .public) \(theMessage, privacy:
.public)")
+ logger.error("\(swiftTag, privacy: .public) \(swiftMessage,
privacy: .public)")
case TALER_WALLET_LOG_WARN:
- logger.warning("\(theTag, privacy: .public) \(theMessage,
privacy: .public)")
+ logger.warning("\(swiftTag, privacy: .public) \(swiftMessage,
privacy: .public)")
case TALER_WALLET_LOG_MESSAGE:
- logger.notice("\(theTag, privacy: .public) \(theMessage, privacy:
.public)")
+ logger.notice("\(swiftTag, privacy: .public) \(swiftMessage,
privacy: .public)")
case TALER_WALLET_LOG_INFO:
- logger.info("\(theTag, privacy: .public) \(theMessage, privacy:
.public)")
+ logger.info("\(swiftTag, privacy: .public) \(swiftMessage,
privacy: .public)")
case TALER_WALLET_LOG_TRACE:
- logger.trace("\(theTag, privacy: .public) \(theMessage, privacy:
.public)")
+ logger.trace("\(swiftTag, privacy: .public) \(swiftMessage,
privacy: .public)")
default: break
}
}
// MARK: -
-public class Quickjs {
+public class Quickjs { // acts as singleton, since only one instance ever
exists
var talerWalletInstance: OpaquePointer!
public weak var messageHandler: QuickjsMessageHandler?
var logger: Logger
+ @Atomic(default: 0)
+ private var lastRequestID: Int32
+ private var requests: [Int32: QuickDataTask] = [:]
+
+ private lazy var urlSession: URLSession = {
+ return URLSession(configuration: .default)
+ }()
+
public init() {
self.logger = Logger(subsystem: "net.taler.gnu", category: "QuickJS")
self.talerWalletInstance = TALER_WALLET_create()
@@ -56,16 +67,48 @@ public class Quickjs {
TALER_WALLET_set_log_handler(talerWalletInstance,
logging_callback,
Unmanaged.passUnretained(self).toOpaque())
- TALER_WALLET_run(talerWalletInstance);
+#if USE_HTTP_CLIENT_CURL
+ let http_impl = js_curl_http_client_create()
+#else
+ let http_impl = TALER_pack_http_client_implementation(request_create,
request_cancel,
+
Unmanaged.passUnretained(self).toOpaque())
+#endif
+ // http_impl got malloc'd, and could possibly be free'd when the app
terminates
+ TALER_set_http_client_implementation(talerWalletInstance, http_impl)
+ // - but we never free anything on termination, thus we don't save
http_impl here
+ TALER_WALLET_run(talerWalletInstance)
}
- deinit {
- // FIXME: TALER_WALLET_destroy
-// TALER_WALLET_destroy(talerWalletInstance)
+ func reqCreate(_ request: URLRequest,
+ _ responseCb: JSHttpResponseCb?,
+ _ responseCbCls: Optional<UnsafeMutableRawPointer>) -> Int32 {
+ let requestID = $lastRequestID.atomicIncrement()
+ let quickDataTask = QuickDataTask(urlSession: urlSession,
+ request: request,
+ requestID: requestID,
+ requests: &requests,
+ responseCb: responseCb,
+ responseCbCls: responseCbCls)
+ quickDataTask.run()
+ requests[requestID] = quickDataTask
+ return requestID
+ }
+
+ func reqCancel(_ requestID: Int32) -> Int32 {
+ if let quickDataTask = requests[requestID] {
+ if let dataTask = quickDataTask.dataTask {
+ dataTask.cancel()
+ }
+ }
+ requests[requestID] = nil
+ return 0
}
+ deinit {
+ // No need to call TALER_WALLET_destroy - memory gets purged anyway
+ }
- public func internalOnNotify(payload: String) {
+ func internalOnNotify(payload: String) {
if let handler = messageHandler {
handler.handleMessage(message: payload)
}
@@ -84,17 +127,4 @@ public class Quickjs {
public func sendMessage(message: String) {
TALER_WALLET_send_request(talerWalletInstance, message)
}
-
- /// Note: This *must* be called before releasing the object, or else the
thread will keep going.
-// public func waitStopped() {
-// scheduleNodeThreadSync {
-// self.stopped = true
-// }
-// thread.cancel()
-// }
-
-// public func putModuleCode(modName: String, code: String) {
-// __putModuleCodeNative(self.instance, modName.cString(using: .utf8),
-// code.cString(using: .utf8))
-// }
}
diff --git a/TalerWallet1/Views/Balances/BalanceRowView.swift
b/TalerWallet1/Views/Balances/BalanceRowView.swift
index ac15ea2..ca0bd58 100644
--- a/TalerWallet1/Views/Balances/BalanceRowView.swift
+++ b/TalerWallet1/Views/Balances/BalanceRowView.swift
@@ -90,13 +90,14 @@ struct BalanceRowView: View {
let sendTitle = minimalistic ? sendTitle0 : sendTitle1
let requTitle = minimalistic ? requestTitle0 : requestTitle1
- let twoRowButtons = TwoRowButtons(sendTitle: sendTitle,
- recvTitle: requTitle,
- fitsSideBySide: false,
- lineLimit: 5,
- sendDisabled: amount.isZero,
- sendAction: sendAction,
- recvAction: recvAction)
+ let twoRowButtons = TwoRowButtons(stack: stack.push(),
+ sendTitle: sendTitle,
+ recvTitle: requTitle,
+ fitsSideBySide: false,
+ lineLimit: 5,
+ sendDisabled: amount.isZero,
+ sendAction: sendAction,
+ recvAction: recvAction)
if #available(iOS 16.0, *) {
ViewThatFits(in: .horizontal) {
HStack(spacing: HSPACING) {
diff --git a/TalerWallet1/Views/Balances/TwoRowButtons.swift
b/TalerWallet1/Views/Balances/TwoRowButtons.swift
index f057936..d9c0713 100644
--- a/TalerWallet1/Views/Balances/TwoRowButtons.swift
+++ b/TalerWallet1/Views/Balances/TwoRowButtons.swift
@@ -6,6 +6,7 @@ import SwiftUI
import taler_swift
struct TwoRowButtons: View {
+ let stack: CallStack
let sendTitle: String
let recvTitle: String
let fitsSideBySide: Bool
@@ -16,13 +17,14 @@ struct TwoRowButtons: View {
// @Environment(\.sizeCategory) var sizeCategory
func makeCopy(fitsSideBySide: Bool) -> TwoRowButtons {
- TwoRowButtons(sendTitle: sendTitle,
- recvTitle: recvTitle,
- fitsSideBySide: fitsSideBySide,
- lineLimit: lineLimit,
- sendDisabled: sendDisabled,
- sendAction: sendAction,
- recvAction: recvAction)
+ TwoRowButtons(stack: stack.push(),
+ sendTitle: sendTitle,
+ recvTitle: recvTitle,
+ fitsSideBySide: fitsSideBySide,
+ lineLimit: lineLimit,
+ sendDisabled: sendDisabled,
+ sendAction: sendAction,
+ recvAction: recvAction)
}
var body: some View {
@@ -35,6 +37,7 @@ struct TwoRowButtons: View {
.disabled(sendDisabled)
.buttonStyle(TalerButtonStyle(type: .bordered,
dimmed: false,
+ disabled: sendDisabled,
aligned: .center))
let recvButtonTitle = recvTitle.tabbed(oneLine: !fitsSideBySide)
let recvVoiceOverTitle = recvTitle.tabbed(oneLine: true)
@@ -53,17 +56,19 @@ struct TwoRowButtons: View {
struct TwoRowButtons_Previews: PreviewProvider {
static var previews: some View {
List {
- TwoRowButtons(sendTitle: "Send " + TESTCURRENCY,
- recvTitle: "Request" + LONGCURRENCY,
- fitsSideBySide: false,
- lineLimit: 2, sendDisabled: true,
- sendAction: {}, recvAction: {})
+ TwoRowButtons(stack: CallStack("Preview"),
+ sendTitle: "Send " + TESTCURRENCY,
+ recvTitle: "Request " + LONGCURRENCY,
+ fitsSideBySide: false,
+ lineLimit: 2, sendDisabled: true,
+ sendAction: {}, recvAction: {})
.listRowSeparator(.hidden)
- TwoRowButtons(sendTitle: "Send" + DEMOCURRENCY,
- recvTitle: "Request" + DEMOCURRENCY,
- fitsSideBySide: true,
- lineLimit: 2, sendDisabled: true,
- sendAction: {}, recvAction: {})
+ TwoRowButtons(stack: CallStack("Preview"),
+ sendTitle: "Send " + DEMOCURRENCY,
+ recvTitle: "Request " + DEMOCURRENCY,
+ fitsSideBySide: true,
+ lineLimit: 2, sendDisabled: true,
+ sendAction: {}, recvAction: {})
.listRowSeparator(.hidden)
}
}
diff --git a/TalerWallet1/Views/Banking/DepositAmountV.swift
b/TalerWallet1/Views/Banking/DepositAmountV.swift
index 0635481..5358d0a 100644
--- a/TalerWallet1/Views/Banking/DepositAmountV.swift
+++ b/TalerWallet1/Views/Banking/DepositAmountV.swift
@@ -134,7 +134,7 @@ struct DepositAmountV: View {
}
}
}
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled || depositStarted))
.disabled(disabled || depositStarted)
.accessibilityHint(disabled ? "enabled when amount is
non-zero, but not higher than your available amount" : EMPTYSTRING)
}.padding(.horizontal) } // ScrollVStack
diff --git a/TalerWallet1/Views/Banking/DepositIbanV.swift
b/TalerWallet1/Views/Banking/DepositIbanV.swift
index ef1e169..6b6fc9c 100644
--- a/TalerWallet1/Views/Banking/DepositIbanV.swift
+++ b/TalerWallet1/Views/Banking/DepositIbanV.swift
@@ -85,10 +85,12 @@ struct DepositIbanV: View {
.textFieldStyle(.roundedBorder)
.padding(minimalistic ? .bottom : .vertical)
.onAppear {
- symLog.log("dispatching kbd...")
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
- isFocused = true // make first responder -
raise keybord
- symLog.log("...kbd isFocused")
+ if !UIAccessibility.isVoiceOverRunning {
+ symLog.log("dispatching kbd...")
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
+ isFocused = true // make first responder -
raise keybord
+ symLog.log("...kbd isFocused")
+ }
}
}
@@ -110,7 +112,7 @@ struct DepositIbanV: View {
NavigationLink(destination: destination) {
Text(buttonTitle(amountToTransfer, currencyInfo))
}
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
.accessibilityHint(disabled ? "enabled when account holder and
IBAN are set" : EMPTYSTRING)
}.padding(.horizontal) } // ScrollVStack
diff --git a/TalerWallet1/Views/Banking/ExchangeListView.swift
b/TalerWallet1/Views/Banking/ExchangeListView.swift
index 7800583..44e8191 100644
--- a/TalerWallet1/Views/Banking/ExchangeListView.swift
+++ b/TalerWallet1/Views/Banking/ExchangeListView.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -109,12 +112,23 @@ extension ExchangeListCommonV: View {
.listStyle(myListStyle.style).anyView
}
.onAppear() {
- DebugViewC.shared.setViewID(VIEW_EXCHANGES, stack: stack.push())
+ DebugViewC.shared.setViewID(VIEW_BANKING, stack: stack.push())
}
.overlay {
if exchanges.isEmpty {
- Text("No Payment Services yet...")
- .talerFont(.body)
+ List {
+ Section {
+ Text("There are no Payment Services yet.")
+ .talerFont(.title3)
+ }
+ Section {
+ Text("Use the Add button to add a service.")
+ .talerFont(.body)
+ .listRowSeparator(.hidden)
+ Text("You can also scan a withdrawal QR code from your
bank on the Balances tab to automatically add a payment service.")
+ .talerFont(.body)
+ }
+ }
}
}
.onNotification(.ExchangeAdded) { notification in
diff --git a/TalerWallet1/Views/Banking/ExchangeRowView.swift
b/TalerWallet1/Views/Banking/ExchangeRowView.swift
index d4af147..3edc3e8 100644
--- a/TalerWallet1/Views/Banking/ExchangeRowView.swift
+++ b/TalerWallet1/Views/Banking/ExchangeRowView.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -65,7 +68,7 @@ struct ExchangeRowView: View {
amountToTransfer: $amountToTransfer)
}
let manualWithdraw = LazyView {
- ManualWithdraw(stack: stack.push(),
+ ManualWithdraw(stack: stack.push(), isSheet: false,
exchangeBaseUrl: baseURL,
amountToTransfer: $amountToTransfer)
}
@@ -76,13 +79,14 @@ struct ExchangeRowView: View {
acceptAction: nil) // pop back to here
}
let disableDeposit = false // TODO: availableAmount.isZero
- let twoRowButtons = TwoRowButtons(sendTitle: minimalistic ?
depositTitle0 : depositTitle1,
- recvTitle: minimalistic ?
withdrawTitle0 : withdrawTitle1,
- fitsSideBySide: false,
- lineLimit: 5,
- sendDisabled: disableDeposit,
- sendAction: { selectAndUpdate(1) },
- recvAction: { selectAndUpdate(2) })
+ let twoRowButtons = TwoRowButtons(stack: stack.push(),
+ sendTitle: minimalistic ? depositTitle0
: depositTitle1,
+ recvTitle: minimalistic ? withdrawTitle0
: withdrawTitle1,
+ fitsSideBySide: false,
+ lineLimit: 5,
+ sendDisabled: disableDeposit,
+ sendAction: { selectAndUpdate(1) },
+ recvAction: { selectAndUpdate(2) })
Group {
NavigationLink(destination: showToS) {
VStack(alignment: .leading) {
diff --git a/TalerWallet1/Views/Banking/ManualWithdraw.swift
b/TalerWallet1/Views/Banking/ManualWithdraw.swift
index b675135..b4a3efb 100644
--- a/TalerWallet1/Views/Banking/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Banking/ManualWithdraw.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -11,6 +14,7 @@ import SymLog
struct ManualWithdraw: View {
private let symLog = SymLogV(0)
let stack: CallStack
+ let isSheet: Bool
let exchangeBaseUrl: String
@Binding var amountToTransfer: Amount
@@ -72,7 +76,7 @@ struct ManualWithdraw: View {
NavigationLink(destination: destination) {
Text("Confirm Withdrawal") // VIEW_WITHDRAW_ACCEPT
}
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
.padding(.top)
} else {
@@ -88,7 +92,11 @@ struct ManualWithdraw: View {
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.navigationTitle(navTitle)
.onAppear {
- DebugViewC.shared.setViewID(VIEW_WITHDRAWAL, stack:
stack.push())
+ if isSheet {
+ DebugViewC.shared.setSheetID(SHEET_WITHDRAW_EXCHANGE)
+ } else {
+ DebugViewC.shared.setViewID(VIEW_WITHDRAWAL, stack:
stack.push())
+ }
symLog.log("❗️ \(navTitle) onAppear")
}
.onDisappear {
@@ -108,7 +116,7 @@ struct ManualWithdraw: View {
}
if !amountToTransfer.isZero {
do {
- let details = try await
model.loadWithdrawalDetailsForAmountM(exchangeBaseUrl,
+ let details = try await
model.getWithdrawalDetailsForAmountM(exchangeBaseUrl,
amount: amountToTransfer)
withdrawalAmountDetails = details
// agePicker.setAges(ages:
withdrawalAmountDetails?.ageRestrictionOptions)
@@ -124,12 +132,12 @@ struct ManualWithdraw: View {
#if DEBUG
struct ManualWithdraw_Previews: PreviewProvider {
struct StateContainer : View {
- @State private var amountToTransfer = Amount(currency: LONGCURRENCY,
cent: 510)
+ @State private var amountToPreview = Amount(currency: LONGCURRENCY,
cent: 510)
var body: some View {
- ManualWithdraw(stack: CallStack("Preview"),
+ ManualWithdraw(stack: CallStack("Preview"), isSheet: false,
exchangeBaseUrl: DEMOEXCHANGE,
- amountToTransfer: $amountToTransfer)
+ amountToTransfer: $amountToPreview)
}
}
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift
b/TalerWallet1/Views/HelperViews/AmountInputV.swift
index 80c4d98..2b542af 100644
--- a/TalerWallet1/Views/HelperViews/AmountInputV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountInputV.swift
@@ -90,13 +90,13 @@ struct AmountInputV: View {
NavigationLink(destination: destination) {
Text("Next")
}
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
} else {
Button("Next") {
buttonAction()
}
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent,
disabled: disabled))
.disabled(disabled)
}
}
diff --git a/TalerWallet1/Views/HelperViews/Buttons.swift
b/TalerWallet1/Views/HelperViews/Buttons.swift
index 6a01913..53530ca 100644
--- a/TalerWallet1/Views/HelperViews/Buttons.swift
+++ b/TalerWallet1/Views/HelperViews/Buttons.swift
@@ -92,9 +92,6 @@ struct ReloadButton : View {
}
struct TalerButtonStyle: ButtonStyle {
- @Environment(\.isEnabled) private var isEnabled: Bool
- var disabled: Bool { !isEnabled }
-
enum TalerButtonStyleType {
case plain
case balance
@@ -104,6 +101,7 @@ struct TalerButtonStyle: ButtonStyle {
var type: TalerButtonStyleType = .plain
var dimmed: Bool = false
var narrow: Bool = false
+ var disabled: Bool = false
var aligned: TextAlignment = .center
var badge: String = EMPTYSTRING
diff --git a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
index c73b479..da78ab2 100644
--- a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
+++ b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
@@ -145,7 +145,7 @@ struct CurrencyInputView: View {
}.onAppear { // make CurrencyField show the keyboard after 0.4
seconds
if hasBeenShown {
// print("❗️Yikes: CurrencyInputView hasBeenShown")
- } else {
+ } else if !UIAccessibility.isVoiceOverRunning {
print("❗️CurrencyInputView❗️")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
hasBeenShown = true
diff --git a/TalerWallet1/Views/HelperViews/SelectDays.swift
b/TalerWallet1/Views/HelperViews/SelectDays.swift
index 3e49a07..ba8383d 100644
--- a/TalerWallet1/Views/HelperViews/SelectDays.swift
+++ b/TalerWallet1/Views/HelperViews/SelectDays.swift
@@ -47,7 +47,8 @@ struct SelectDays: View {
} else {
Text("\(ONEDAY) Day", comment: "1 Day, might get
plural (e.g. 2..3 Days), 4 letters max., abbreviate if longer") // TODO:
Plural
}
- }.buttonStyle(TalerButtonStyle(type: (selected == ONEDAY) ?
.prominent : .bordered, dimmed: true))
+ }.buttonStyle(TalerButtonStyle(type: (selected == ONEDAY) ?
.prominent : .bordered,
+ dimmed: true, disabled:
!isEnabled))
.accessibilityAddTraits(selected == ONEDAY ? .isSelected :
[])
.disabled(!isEnabled)
@@ -57,7 +58,8 @@ struct SelectDays: View {
} else {
Text("\(SEVENDAYS) Days", comment: "7 Days, always
plural (3..9), 4 letters max., abbreviate if longer")
}
- }.buttonStyle(TalerButtonStyle(type: (selected == SEVENDAYS) ?
.prominent : .bordered, dimmed: true))
+ }.buttonStyle(TalerButtonStyle(type: (selected == SEVENDAYS) ?
.prominent : .bordered, dimmed: true,
+ disabled: !isEnabled ||
maxExpiration < SEVENDAYS))
.accessibilityAddTraits(selected == SEVENDAYS ?
.isSelected : [])
.disabled(!isEnabled || maxExpiration < SEVENDAYS)
@@ -67,7 +69,8 @@ struct SelectDays: View {
} else {
Text("\(THIRTYDAYS) Days", comment: "30 Days, always
plural (10..30), 4 letters max., abbreviate if longer")
}
- }.buttonStyle(TalerButtonStyle(type: (selected == THIRTYDAYS)
? .prominent : .bordered, dimmed: true))
+ }.buttonStyle(TalerButtonStyle(type: (selected == THIRTYDAYS)
? .prominent : .bordered, dimmed: true,
+ disabled: !isEnabled ||
maxExpiration < THIRTYDAYS))
.accessibilityAddTraits(selected == THIRTYDAYS ?
.isSelected : [])
.disabled(!isEnabled || maxExpiration < THIRTYDAYS)
} // 3 buttons
diff --git a/TalerWallet1/Views/HelperViews/SubjectInputV.swift
b/TalerWallet1/Views/HelperViews/SubjectInputV.swift
index 3634226..56135f8 100644
--- a/TalerWallet1/Views/HelperViews/SubjectInputV.swift
+++ b/TalerWallet1/Views/HelperViews/SubjectInputV.swift
@@ -92,10 +92,12 @@ struct SubjectInputV<TargetView: View>: View {
.background(WalletColors().fieldBackground)
.textFieldStyle(.roundedBorder)
.onAppear {
- symLog.log("dispatching kbd...")
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
- isFocused = true // make first responder - raise
keybord
- symLog.log("...kbd isFocused")
+ if !UIAccessibility.isVoiceOverRunning {
+ symLog.log("dispatching kbd...")
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
+ isFocused = true // make first responder -
raise keybord
+ symLog.log("...kbd isFocused")
+ }
}
}
@@ -110,7 +112,7 @@ struct SubjectInputV<TargetView: View>: View {
.padding(4)
NavigationLink("Next", destination: targetView)
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
// .accessibility(sortPriority: 0)
}.padding(.horizontal)
diff --git a/TalerWallet1/Views/Main/WalletEmptyView.swift
b/TalerWallet1/Views/Main/WalletEmptyView.swift
index 1ecb492..ff72980 100644
--- a/TalerWallet1/Views/Main/WalletEmptyView.swift
+++ b/TalerWallet1/Views/Main/WalletEmptyView.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import SymLog
@@ -18,15 +21,22 @@ struct WalletEmptyView: View {
Section {
Text("There is no digital cash in your wallet.")
.talerFont(.title3)
+ }
+ Section {
+ Text("You can register an account in the demo bank, then
withdraw some digital cash to experience how to pay with the money of the
future.")
+ .talerFont(.body)
.listRowSeparator(.hidden)
- let title = String(localized: "LinkTitle_Test_Money",
defaultValue: "Get some test money")
+ let title = String(localized: "LinkTitle_Test_Money",
defaultValue: "Get demo money")
Link(title, destination: URL(string: DEMOBANK)!)
.buttonStyle(TalerButtonStyle(type: .prominent, narrow:
false, aligned: .center))
.padding(.vertical)
.accessibilityHint("Will go to the demo bank website.")
}
Section {
- Text("Just register a test account in the demo bank, then
withdraw some electronic cash.")
+ Text("Use the QR code scan button to start a withdrawal if
your bank already supports Taler payments.")
+ .talerFont(.body)
+ .listRowSeparator(.hidden)
+ Text("You can also add a payment service manually on the
Banking tab.")
.talerFont(.body)
}
}
@@ -34,7 +44,7 @@ struct WalletEmptyView: View {
.talerFont(.title2)
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear() {
- DebugViewC.shared.setViewID(VIEW_EMPTY, stack:
stack.push("onAppear")) // 10
+ DebugViewC.shared.setViewID(VIEW_EMPTY_WALLET, stack:
stack.push("onAppear")) // 10
}
}
}
diff --git a/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
b/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
index 05892b0..6982490 100644
--- a/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
+++ b/TalerWallet1/Views/Peer2peer/P2PSubjectV.swift
@@ -19,7 +19,7 @@ struct P2PSubjectV: View {
private let symLog = SymLogV(0)
let stack: CallStack
let feeLabel: String?
- let feeIsNotZero: Bool? // nil = no fees at all, false = no fee
for this tx
+ let feeIsNotZero: Bool? // nil = no fees at all, false = no
fee for this tx
let currencyInfo: CurrencyInfo
let amountToSend: Bool
@Binding var amountToTransfer: Amount
@@ -89,10 +89,12 @@ struct P2PSubjectV: View {
.background(WalletColors().fieldBackground)
.textFieldStyle(.roundedBorder)
.onAppear {
- symLog.log("dispatching kbd...")
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
- isFocused = true // make first responder -
raise keybord
- symLog.log("...kbd isFocused")
+ if !UIAccessibility.isVoiceOverRunning {
+ symLog.log("dispatching kbd...")
+ DispatchQueue.main.asyncAfter(deadline: .now() +
0.7) {
+ isFocused = true // make first
responder - raise keybord
+ symLog.log("...kbd isFocused")
+ }
}
}
Text(verbatim: "\(summary.count)/100")
// maximum 100 characters
@@ -116,7 +118,7 @@ struct P2PSubjectV: View {
}) {
Text(buttonTitle(amountToTransfer, currencyInfo))
}
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
.accessibilityHint(disabled ? "enabled when subject and
expiration are set" : EMPTYSTRING)
}.padding(.horizontal) } // ScrollVStack
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
index b37109f..90a5bc8 100644
--- a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -85,7 +85,7 @@ struct RequestPayment: View {
currencyInfo: currencyInfo,
amountEffective: peerPullCheck?.amountEffective)
NavigationLink(destination: inputDestination) { Text("Next") }
- .buttonStyle(TalerButtonStyle(type: .prominent))
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
.background(NavigationLink(destination: shortcutDestination,
isActive: $buttonSelected)
{ EmptyView() }.frame(width: 0).opacity(0).hidden()
diff --git a/TalerWallet1/Views/Settings/AboutView.swift
b/TalerWallet1/Views/Settings/AboutView.swift
index 03c4ce7..dc0569e 100644
--- a/TalerWallet1/Views/Settings/AboutView.swift
+++ b/TalerWallet1/Views/Settings/AboutView.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -38,7 +41,7 @@ struct AboutView: View {
// .accessibilityLabel("Progress indicator")
.onTapGesture(count: 1) { rotationEnabled.toggle() }
SettingsItem(name: "Visit the taler.net website", id1: "web",
- description: minimalistic ? nil :
String(localized: "More info about Gnu Taler in general...")) { }
+ description: minimalistic ? nil :
String(localized: "More info about GNU Taler in general...")) { }
.accessibilityAddTraits(.isLink)
.accessibilityRemoveTraits(.isStaticText)
.onTapGesture() {
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
index 3fae19d..1c9ada3 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawTOSView.swift
@@ -25,7 +25,7 @@ struct WithdrawTOSView: View {
func loadToS(_ language: String) async {
do {
if let exchangeBaseUrl {
- let acceptedFormat: [String] = [MARKDOWN, PLAINTEXT]
+ let acceptedFormat: [String] = [MARKDOWN, PLAINTEXT] //
MARKDOWN, HTML, PLAINTEXT
let someTOS = try await
model.loadExchangeTermsOfServiceM(exchangeBaseUrl,
acceptedFormat:
acceptedFormat,
acceptLanguage:
language)
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
index 43b04c3..04685d8 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -91,13 +94,13 @@ struct WithdrawURIView: View {
.task {
do { // TODO: cancelled
symLog.log(".task")
- let withdrawUriInfo = try await
model.loadWithdrawalDetailsForUriM(url.absoluteString)
+ let withdrawUriInfo = try await
model.getWithdrawalDetailsForUriM(url.absoluteString)
let amount = withdrawUriInfo.amount
let baseUrl = withdrawUriInfo.defaultExchangeBaseUrl
??
withdrawUriInfo.possibleExchanges.first?.exchangeBaseUrl
if let baseUrl, let exc = await model.getExchangeByUrl(url:
baseUrl) {
exchange = exc
- let details = try await
model.loadWithdrawalDetailsForAmountM(baseUrl, amount: amount)
+ let details = try await
model.getWithdrawalDetailsForAmountM(baseUrl, amount: amount)
withdrawalAmountDetails = details
// agePicker.setAges(ages: details?.ageRestrictionOptions)
} else { // TODO: error
diff --git a/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
b/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
index 8859513..eab5268 100644
--- a/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawExchangeV.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -24,7 +27,7 @@ struct WithdrawExchangeV: View {
#endif
Group {
if let exchangeBaseUrl {
- ManualWithdraw(stack: stack.push(),
+ ManualWithdraw(stack: stack.push(), isSheet: true,
exchangeBaseUrl: exchangeBaseUrl,
amountToTransfer: $amountToTransfer)
} else {
diff --git a/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
b/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
index c7fbbf1..6e61e21 100644
--- a/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
+++ b/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
@@ -110,6 +110,7 @@ struct ThreeAmountsV: View {
}
if let baseURL {
VStack(alignment: .leading) {
+ // TODO: "Issued by" for withdrawals
Text(minimalistic ? "Payment provider:" : "Using payment
service provider:")
.multilineTextAlignment(.leading)
.talerFont(.body)
diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
index 050bf40..ccfb638 100644
--- a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
+++ b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import taler_swift
import SymLog
@@ -121,13 +124,10 @@ struct TransactionSummaryV: View {
.listRowSeparator(.hidden)
VStack(alignment: .trailing) {
let majorState = common.txState.major.localizedState
-#if DEBUG
let minorState = common.txState.minor?.localizedState ??
nil
- let state = transaction.isPending ? minorState ??
majorState
- : majorState
-#else
- let state = majorState
-#endif
+ let state = developerMode ? transaction.isPending ?
minorState ?? majorState
+ :
majorState
+ : majorState
HStack {
Text(verbatim: "|") // only reason for this
leading-aligned text is to get a nice full length listRowSeparator
.accessibilityHidden(true)
diff --git a/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
b/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
index e9569d4..cd849ef 100644
--- a/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift
@@ -1,7 +1,10 @@
/*
- * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * This file is part of GNU Taler, ©2022-24 Taler Systems S.A.
* See LICENSE.md
*/
+/**
+ * @author Marc Stibane
+ */
import SwiftUI
import SymLog
@@ -26,7 +29,7 @@ struct TransactionsEmptyView: View {
// .padding(.vertical)
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear() {
- DebugViewC.shared.setViewID(VIEW_EMPTY, stack: stack.push())
// 10
+ DebugViewC.shared.setViewID(VIEW_EMPTY_HISTORY, stack:
stack.push()) // 20
}
}
}
diff --git a/TestFlight/WhatToTest.en-US.txt b/TestFlight/WhatToTest.en-US.txt
index 99cdbbb..592c67e 100644
--- a/TestFlight/WhatToTest.en-US.txt
+++ b/TestFlight/WhatToTest.en-US.txt
@@ -1,3 +1,26 @@
+Version 0.9.4 (11)
+
+• New views for empty wallet (Balances) and zero payment providers (Banking)
+
+
+Version 0.9.4 (10)
+
+• New feature: Native Networking instead of curl
+
+
+Version 0.9.4 (9)
+
+• debug version WITHOUT c-ares
+
+
+Version 0.9.4 (8)
+
+• New feature: LocalConsole for GNU Taler only. Find it in Settings...
+
+also GNU Taler no longer claims the taler:// URL scheme. You can now install
GNU Taler for debugging/testing in parallel to Taler Wallet, and all System
events (System Camera, Mail Messages, NFC Tags, ...) will always go to Taler
Wallet.
+Thus you need to scan a QR code from another device (laptop, tablet, phone,
...) to withdraw into GNU Taler, and cannot use the browser on this iPhone for
bank-integrated withdrawals, because attempting to open a taler://withdraw/
will open Taler Wallet and not GNU Taler.
+
+
Version 0.9.4 (7)
• New feature: Pay-Templates
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] branch master updated (8475ec0 -> 9453c61),
gnunet <=
- [taler-taler-ios] 07/16: Error, Status, gnunet, 2024/02/29
- [taler-taler-ios] 13/16: Preparation for Builtin, gnunet, 2024/02/29
- [taler-taler-ios] 06/16: ViewIDs, gnunet, 2024/02/29
- [taler-taler-ios] 04/16: fix JSON keys for ExchangeUpdateStatus, gnunet, 2024/02/29
- [taler-taler-ios] 08/16: Use HTTP lib of quickjs-tart, still with curl, gnunet, 2024/02/29
- [taler-taler-ios] 10/16: Debugging, gnunet, 2024/02/29
- [taler-taler-ios] 03/16: fake Swiss Francs, gnunet, 2024/02/29
- [taler-taler-ios] 09/16: Helpers, gnunet, 2024/02/29
- [taler-taler-ios] 16/16: Bump version to 0.9.4 (11), gnunet, 2024/02/29
- [taler-taler-ios] 15/16: Empty Wallet, gnunet, 2024/02/29