[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] branch master updated (18d895c -> c4761b4)
From: |
gnunet |
Subject: |
[taler-taler-ios] branch master updated (18d895c -> c4761b4) |
Date: |
Tue, 28 May 2024 09:05:43 +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 18d895c Bump version to 0.10.2 (0.10.7)
new 584c084 Bank links
new 35d07ff currencyInfo instead of readableDescription
new 56c0058 checkInternetConnection
new f03a19f cleanup
new a2df784 CurrencyFormatter for manual withdrawals
new 78157b3 non-breaking space
new afc1a89 crash fix 8780
new 5564918 canonical
new 95ed69a debugging
new 1979eb6 prepare pending tx reload on errors
new abb3cf7 cleanup
new 256c0e1 Bump version to 0.10.3 (0.10.8)
new 479eadc addingPercentEncoding
new cbcb924 merge-kyc translation
new 417a07d Decode payee
new bcc52d9 Networking: hintNetworkAvailability()
new e309b6b make announce() passable in closures
new 9181daa don't announce debugView
new a6dff37 checkPayForTemplate preparation
new 10f6373 RelativeTime
new ca158ae Localization hints
new 33421ae localizedState
new 815c71b escape "\t"
new e522d43 Logging
new 1f0c84a checkPayForTemplate
new 7c515cf German localization
new 1797026 Spanish localization
new 292eec0 prepare bankIntegrated without amount
new c4761b4 Bump version to 0.11.0 (0.11.1)
The 29 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 | 25 +-
TalerWallet1/Backend/WalletBackendError.swift | 2 +-
TalerWallet1/Backend/WalletBackendRequest.swift | 1 +
TalerWallet1/Backend/WalletCore.swift | 41 +-
TalerWallet1/Controllers/Controller.swift | 38 +-
TalerWallet1/Controllers/DebugViewC.swift | 16 +-
TalerWallet1/Controllers/PublicConstants.swift | 9 +-
TalerWallet1/GNU_Taler InfoPlist.xcstrings | 78 +
TalerWallet1/Helper/CurrencySpecification.swift | 18 +-
TalerWallet1/Helper/LocalizedAlertError.swift | 2 +-
TalerWallet1/Helper/TalerStrings.swift | 10 +
TalerWallet1/Localizable.xcstrings | 1991 +++++++++++++++++++-
TalerWallet1/Model/Model+Exchange.swift | 4 +-
TalerWallet1/Model/Model+Payment.swift | 70 +-
TalerWallet1/Model/Model+Withdraw.swift | 5 +-
TalerWallet1/Model/Transaction.swift | 7 +-
TalerWallet1/Model/WalletModel.swift | 43 +-
TalerWallet1/Quickjs/QuickDataTask.swift | 30 +-
TalerWallet1/Quickjs/quickjs.swift | 6 +-
TalerWallet1/Taler_Wallet InfoPlist.xcstrings | 78 +
TalerWallet1/Views/Balances/BalancesListView.swift | 5 +-
TalerWallet1/Views/Balances/PendingRowView.swift | 4 +-
TalerWallet1/Views/Banking/DepositAmountV.swift | 25 +-
TalerWallet1/Views/Banking/ExchangeListView.swift | 6 +-
TalerWallet1/Views/HelperViews/AmountInputV.swift | 125 +-
TalerWallet1/Views/HelperViews/AmountV.swift | 9 +-
.../Views/HelperViews/LaunchAnimationView.swift | 3 +-
.../Views/HelperViews/QRCodeDetailView.swift | 8 +-
TalerWallet1/Views/HelperViews/SubjectInputV.swift | 70 +-
.../Views/HelperViews/View+fitsSideBySide.swift | 2 +-
TalerWallet1/Views/Main/MainView.swift | 9 +-
TalerWallet1/Views/Peer2peer/SendAmount.swift | 39 +-
TalerWallet1/Views/Settings/AboutView.swift | 7 +-
TalerWallet1/Views/Settings/SettingsView.swift | 12 +-
TalerWallet1/Views/Sheets/ErrorSheet.swift | 4 +-
.../Views/Sheets/P2P_Sheets/P2pPayURIView.swift | 10 +-
.../Sheets/P2P_Sheets/P2pReceiveURIView.swift | 8 +-
.../Views/Sheets/Payment/PayTemplateV.swift | 186 +-
.../Views/Sheets/Payment/PaymentView.swift | 78 +-
TalerWallet1/Views/Sheets/QRSheet.swift | 14 +-
TalerWallet1/Views/Sheets/Sheet.swift | 2 +-
TalerWallet1/Views/Sheets/URLSheet.swift | 8 +-
.../WithdrawBankIntegrated/WithdrawURIView.swift | 27 +-
.../Views/Transactions/ManualDetailsV.swift | 43 +-
.../Views/Transactions/ThreeAmountsV.swift | 13 +-
.../Views/Transactions/TransactionRowView.swift | 2 +-
.../Views/Transactions/TransactionSummaryV.swift | 17 +-
TestFlight/WhatToTest.en-US.txt | 12 +
taler-swift/Sources/taler-swift/Amount.swift | 5 +-
taler-swift/Sources/taler-swift/Time.swift | 45 +
50 files changed, 2843 insertions(+), 429 deletions(-)
create mode 100644 TalerWallet1/GNU_Taler InfoPlist.xcstrings
create mode 100644 TalerWallet1/Taler_Wallet InfoPlist.xcstrings
diff --git a/TalerWallet.xcodeproj/project.pbxproj
b/TalerWallet.xcodeproj/project.pbxproj
index df17b89..34d5ddb 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -257,6 +257,8 @@
4EE171882B49635800BF9FF5 /* MarkdownUI in Frameworks */ = {isa
= PBXBuildFile; productRef = 4EE171872B49635800BF9FF5 /* MarkdownUI */; };
4EE171902B49FE2B00BF9FF5 /* OrderedCollections in Frameworks */
= {isa = PBXBuildFile; productRef = 4EE1718F2B49FE2B00BF9FF5 /*
OrderedCollections */; };
4EE171922B49FE4E00BF9FF5 /* OrderedCollections in Frameworks */
= {isa = PBXBuildFile; productRef = 4EE171912B49FE4E00BF9FF5 /*
OrderedCollections */; };
+ 4EE77E7D2C0280E5007C9064 /* GNU_Taler InfoPlist.xcstrings in
Resources */ = {isa = PBXBuildFile; fileRef = 4EE77E7C2C0280E5007C9064 /*
GNU_Taler InfoPlist.xcstrings */; };
+ 4EE77E7F2C0280E5007C9064 /* Taler_Wallet InfoPlist.xcstrings in
Resources */ = {isa = PBXBuildFile; fileRef = 4EE77E7E2C0280E5007C9064 /*
Taler_Wallet InfoPlist.xcstrings */; };
4EEC118D2B83DE4800146CFF /* AmountInputV.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4EEC118C2B83DE4700146CFF /* AmountInputV.swift
*/; };
4EEC118E2B83DE4800146CFF /* AmountInputV.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4EEC118C2B83DE4700146CFF /* AmountInputV.swift
*/; };
4EEC11932B83FB7A00146CFF /* SubjectInputV.swift in Sources */ =
{isa = PBXBuildFile; fileRef = 4EEC11922B83FB7A00146CFF /* SubjectInputV.swift
*/; };
@@ -448,6 +450,8 @@
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>"; };
+ 4EE77E7C2C0280E5007C9064 /* GNU_Taler InfoPlist.xcstrings */ =
{isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path =
"GNU_Taler InfoPlist.xcstrings"; sourceTree = "<group>"; };
+ 4EE77E7E2C0280E5007C9064 /* Taler_Wallet InfoPlist.xcstrings */
= {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path =
"Taler_Wallet InfoPlist.xcstrings"; 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>"; };
4EEC11952B840F1100146CFF /* PayTemplateV.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= PayTemplateV.swift; sourceTree = "<group>"; };
@@ -589,6 +593,8 @@
4E2254942A822B8100E41D29 /* Sounds */,
4E3EAEA62AA12750009F1BE8 /* Fonts */,
4EFFDD6A2A501121000C1C6A /*
Localizable.xcstrings */,
+ 4EE77E7C2C0280E5007C9064 /* GNU_Taler
InfoPlist.xcstrings */,
+ 4EE77E7E2C0280E5007C9064 /* Taler_Wallet
InfoPlist.xcstrings */,
4E363CBF2A24754200D7E98C /* Settings.bundle */,
4EB094F529897A9A0043A8A1 /* Preview Content */,
4E3208562BB550CA00211E9E /*
PrivacyInfo.xcprivacy */,
@@ -1023,6 +1029,7 @@
en,
Base,
de,
+ es,
);
mainGroup = D14AFD1424D232B300C51073;
packageReferences = (
@@ -1059,6 +1066,7 @@
4E3EAE9C2AA12467009F1BE8 /* Nunito-Regular.ttf
in Resources */,
4E605D922AA8B407002FB9A7 /*
Nunito-BlackItalic.ttf in Resources */,
4E3EAE9E2AA12467009F1BE8 /* Nunito-Bold.ttf in
Resources */,
+ 4EE77E7D2C0280E5007C9064 /* GNU_Taler
InfoPlist.xcstrings in Resources */,
4E3EAEA42AA12582009F1BE8 /*
Nunito-BoldItalic.ttf in Resources */,
4E605D902AA8B407002FB9A7 /* Nunito-Black.ttf in
Resources */,
4E3EAEA22AA12582009F1BE8 /* Nunito-Italic.ttf
in Resources */,
@@ -1077,6 +1085,7 @@
4E8C17202A6509BB005B2392 /*
Atkinson-Hyperlegible-Regular-102.otf in Resources */,
4E8C17222A6509BB005B2392 /*
Atkinson-Hyperlegible-Bold-102.otf in Resources */,
4E8C17232A6509BB005B2392 /*
Atkinson-Hyperlegible-BoldItalic-102.otf in Resources */,
+ 4EE77E7F2C0280E5007C9064 /* Taler_Wallet
InfoPlist.xcstrings in Resources */,
4E8C17212A6509BB005B2392 /*
Atkinson-Hyperlegible-Italic-102.otf in Resources */,
4E3EAE9D2AA12467009F1BE8 /* Nunito-Regular.ttf
in Resources */,
4E605D932AA8B407002FB9A7 /*
Nunito-BlackItalic.ttf in Resources */,
@@ -1389,7 +1398,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 0.10.7;
+ CURRENT_PROJECT_VERSION = 0.11.1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1407,7 +1416,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.10.2;
+ MARKETING_VERSION = 0.11.0;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-1";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1431,7 +1440,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 0.10.7;
+ CURRENT_PROJECT_VERSION = 0.11.1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1449,7 +1458,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.10.2;
+ MARKETING_VERSION = 0.11.0;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-1";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1592,7 +1601,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 0.10.7;
+ CURRENT_PROJECT_VERSION = 0.11.1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1610,7 +1619,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.10.2;
+ MARKETING_VERSION = 0.11.0;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-2";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1634,7 +1643,7 @@
CODE_SIGN_ENTITLEMENTS =
"$(TARGET_NAME).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 0.10.7;
+ CURRENT_PROJECT_VERSION = 0.11.1;
DEVELOPMENT_TEAM = GUDDQ9428Y;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -1652,7 +1661,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.10.2;
+ MARKETING_VERSION = 0.11.0;
PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet-2";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/TalerWallet1/Backend/WalletBackendError.swift
b/TalerWallet1/Backend/WalletBackendError.swift
index 0a2c693..f2cfec9 100644
--- a/TalerWallet1/Backend/WalletBackendError.swift
+++ b/TalerWallet1/Backend/WalletBackendError.swift
@@ -32,7 +32,7 @@ struct WalletBackendResponseError: Codable {
/// Numeric error code defined defined in the GANA gnu-taler-error-codes
registry.
var code: Int
- var when: Timestamp
+ var when: Timestamp?
/// English description of the error code.
var hint: String
diff --git a/TalerWallet1/Backend/WalletBackendRequest.swift
b/TalerWallet1/Backend/WalletBackendRequest.swift
index a0d9a75..1319f76 100644
--- a/TalerWallet1/Backend/WalletBackendRequest.swift
+++ b/TalerWallet1/Backend/WalletBackendRequest.swift
@@ -29,6 +29,7 @@ struct ScopeInfo: Codable, Hashable {
case global
case exchange
case auditor
+ case madeUp // => type unknown, currency name taken from amount
}
var type: ScopeInfoType
var noFees: Bool? // only for "global". Regional have this field
per Exchange
diff --git a/TalerWallet1/Backend/WalletCore.swift
b/TalerWallet1/Backend/WalletCore.swift
index cec27c2..28a09a5 100644
--- a/TalerWallet1/Backend/WalletCore.swift
+++ b/TalerWallet1/Backend/WalletCore.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
*/
/**
@@ -168,7 +168,9 @@ extension WalletCore {
}
private func handlePendingProcessed(_ payload: Payload) throws {
- guard let id = payload.id else { throw
WalletBackendError.deserializationError }
+ guard let id = payload.id else {
+ throw WalletBackendError.deserializationError
+ }
let pendingOp = Notification.Name.PendingOperationProcessed.rawValue
if id.hasPrefix("exchange-update:") {
// Bla Bla Bla
@@ -194,16 +196,15 @@ extension WalletCore {
@MainActor private func handleStateTransition(_ jsonData: Data) throws {
do {
let decoded = try JSONDecoder().decode(TransactionTransition.self,
from: jsonData)
+ if let errorInfo = decoded.errorInfo {
+ // reload pending transaction list to add error badge
+ postNotification(.TransactionError, userInfo:
[NOTIFICATIONERROR: WalletBackendError.walletCoreError(errorInfo)])
+ }
guard decoded.newTxState != decoded.oldTxState else {
- // TODO: Same state usually means that an error is transmitted
logger.info("No State change: \(decoded.transactionId,
privacy: .private(mask: .hash))")
return
}
- if decoded.errorInfo == nil {
- postNotification(.Error, userInfo: [NOTIFICATIONERROR:
decoded.errorInfo])
- }
-
let components = decoded.transactionId.components(separatedBy: ":")
if components.count >= 3 { // txn:$txtype:$uid
if let type = TransactionType(rawValue: components[1]) {
@@ -267,14 +268,28 @@ extension WalletCore {
} // switch
} // type
} // 3 components
- } catch { // rethrows
- symLog.log(jsonData) // TODO: .error
- throw WalletBackendError.deserializationError
+ return
+ } catch DecodingError.dataCorrupted(let context) {
+ print(context)
+ } catch DecodingError.keyNotFound(let key, let context) {
+ print("Key '\(key)' not found:", context.debugDescription)
+ print("codingPath:", context.codingPath)
+ } catch DecodingError.valueNotFound(let value, let context) {
+ print("Value '\(value)' not found:", context.debugDescription)
+ print("codingPath:", context.codingPath)
+ } catch DecodingError.typeMismatch(let type, let context) {
+ print("Type '\(type)' mismatch:", context.debugDescription)
+ print("codingPath:", context.codingPath)
+ } catch let error { // rethrows
+ symLog.log(error) // TODO: .error
}
+ throw WalletBackendError.walletCoreError(nil) // TODO: error?
}
@MainActor private func handleNotification(_ anyCodable: AnyCodable?)
throws {
- guard let anyPayload = anyCodable else { throw
WalletBackendError.deserializationError }
+ guard let anyPayload = anyCodable else {
+ throw WalletBackendError.deserializationError
+ }
do {
let jsonData = try JSONEncoder().encode(anyPayload)
let payload = try JSONDecoder().decode(Payload.self, from:
jsonData)
@@ -305,8 +320,8 @@ extension WalletCore {
postNotification(.ProposalDownloaded, userInfo: nil)
case Notification.Name.TaskObservabilityEvent.rawValue,
Notification.Name.RequestObservabilityEvent.rawValue:
- symLog.log(anyPayload)
if isObserving != 0 {
+ symLog.log(anyPayload)
let timestamp = TalerDater.dateString()
if let event = payload.event, let json =
event.toJSON() {
let type = event["type"]?.value as? String
@@ -322,7 +337,7 @@ extension WalletCore {
// "refresh-revealed", "refresh-unwarranted":
// break
default:
-print("\n❗️ WalletCore.swift:251 Notification: ", anyPayload, "\n") //
this is a new notification I haven't seen before
+print("\n❗️ WalletCore.swift:340 Notification: ", anyPayload, "\n") //
this is a new notification I haven't seen before
break
}
} catch let error {
diff --git a/TalerWallet1/Controllers/Controller.swift
b/TalerWallet1/Controllers/Controller.swift
index a3b79ee..c3c551e 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -8,6 +8,7 @@ import SwiftUI
import SymLog
import os.log
import CoreHaptics
+import Network
enum BackendState {
case none
@@ -36,6 +37,7 @@ class Controller: ObservableObject {
@Published var backendState: BackendState = .none // only used for
launch animation
@Published var currencyTicker: Int = 0 // updates
whenever a new currency is added
+ @Published var isConnected: Bool = true
@AppStorage("useHaptics") var useHaptics: Bool = true // extension
mustn't define this, so it must be here
@AppStorage("playSoundsI") var playSoundsI: Int = 1 // extension
mustn't define this, so it must be here
@AppStorage("playSoundsB") var playSoundsB: Bool = false
@@ -45,9 +47,42 @@ class Controller: ObservableObject {
let player = AVQueuePlayer()
let semaphore = AsyncSemaphore(value: 1)
var currencyInfos: [CurrencyInfo]
-
var messageForSheet: String? = nil
+ private let monitor = NWPathMonitor()
+
+ func checkInternetConnection() {
+ monitor.pathUpdateHandler = { path in
+ let status = switch path.status {
+ case .satisfied: "active"
+ case .unsatisfied: "inactive"
+ default: "unknown"
+ }
+ self.logger.log("Internet connection is \(status)")
+ DispatchQueue.main.async {
+ if path.status == .unsatisfied {
+ self.isConnected = false
+ Task.detached {
+ await
WalletModel.shared.hintNetworkAvailabilityT(false)
+ }
+ } else {
+ self.stopCheckingConnection()
+ self.isConnected = true
+ Task.detached {
+ await WalletModel.shared.hintNetworkAvailabilityT(true)
+ }
+ }
+ }
+ }
+ self.logger.log("Start monitoring internet connection")
+ let queue = DispatchQueue(label: "InternetMonitor")
+ monitor.start(queue: queue)
+ }
+ func stopCheckingConnection() {
+ self.logger.log("Stop monitoring internet connection")
+ monitor.cancel()
+ }
+
init() {
// for family in UIFont.familyNames {
// print(family)
@@ -58,6 +93,7 @@ class Controller: ObservableObject {
backendState = .instantiated
currencyTicker = 0
currencyInfos = []
+// checkInternetConnection()
}
// MARK: -
func hasInfo(for currency: String) -> CurrencyInfo? {
diff --git a/TalerWallet1/Controllers/DebugViewC.swift
b/TalerWallet1/Controllers/DebugViewC.swift
index bdf8e55..45c884c 100644
--- a/TalerWallet1/Controllers/DebugViewC.swift
+++ b/TalerWallet1/Controllers/DebugViewC.swift
@@ -135,7 +135,7 @@ struct DebugViewV: View {
.font(.system(size: 11)) // no talerFont
.monospacedDigit()
.id("viewID")
- .accessibilityLabel(Text("View.ID.", comment:
"AccessibilityLabel"))
+ .accessibilityLabel(Text("View.ID.", comment: "VoiceOver"))
.accessibilityValue(viewIDString)
.accessibilityHint(String(localized: "Shows which view you
currently are on."))
Spacer()
@@ -157,21 +157,21 @@ class DebugViewC: ObservableObject {
@Published var viewID: Int = 0
@Published var sheetID: Int = 0
- func announce(this: String) {
- if UIAccessibility.isVoiceOverRunning {
- UIAccessibility.post(notification: .announcement, argument: this)
- }
- }
+// func announce(_ this: String) {
+// if UIAccessibility.isVoiceOverRunning {
+// UIAccessibility.post(notification: .announcement, argument: this)
+// }
+// }
@MainActor func setViewID(_ newID: Int, stack: CallStack) -> Void {
if developerMode {
if viewID == 0 {
logger.log("switching ON, \(newID, privacy: .public)")
viewID = newID // publish ON
-// announce(this: "Current view is: \(newID).")
+// announce("Current view is: \(newID).")
} else if viewID != newID {
logger.log("switching from \(self.viewID, privacy: .public) to
\(newID, privacy: .public)")
-// announce(this: "View switched from \(self.viewID) to
\(newID).")
+// announce("View switched from \(self.viewID) to \(newID).")
viewID = newID // publish new
viewID
} else {
logger.log("\(newID, privacy: .public) stays")
diff --git a/TalerWallet1/Controllers/PublicConstants.swift
b/TalerWallet1/Controllers/PublicConstants.swift
index 9515947..fe00bc2 100644
--- a/TalerWallet1/Controllers/PublicConstants.swift
+++ b/TalerWallet1/Controllers/PublicConstants.swift
@@ -16,6 +16,7 @@ public let SEVENDAYS: UInt = 7 // 3..9
public let THIRTYDAYS: UInt = 30 // 10..30
public let EMPTYSTRING = "" // avoid automatic
translation of empty "" textLiterals in Text()
+public let NONBREAKING = "\u{00A0}"
public let CONFIRM_BANK = "circle.fill" // badge in PendingRow,
TransactionRow and TransactionSummary
public let NEEDS_KYC = "star.fill" // badge in PendingRow,
TransactionRow and TransactionSummary
public let PENDING_INCOMING = "plus.diamond"
@@ -26,7 +27,7 @@ public let DONE_OUTGOING = "minus.circle.fill"
public let HTTPS = "https://"
//public let DEMOBANK = HTTPS + "bAnK.dEmO.tAlEr.nEt" // should be
weird to read, but still work
//public let DEMOEXCHANGE = HTTPS + "eXcHaNgE.dEmO.tAlEr.nEt"
-public let TALER = "taler.net"
+public let TALER = "taler.net/"
public let TALER_NET = HTTPS + TALER
public let DEMO = ".demo." + TALER
public let TEST = ".test." + TALER
@@ -40,8 +41,8 @@ public let TESTSHOP = HTTPS + "shop" + TEST
public let TESTBACKEND = HTTPS + "backend" + TEST
public let TESTEXCHANGE = HTTPS + "exchange" + TEST
-public let ARS_AGE_EXCHANGE = HTTPS + "exchange-age.taler.ar"
-public let ARS_EXP_EXCHANGE = HTTPS + "exchange-expensive.taler.ar"
+public let ARS_AGE_EXCHANGE = HTTPS + "exchange-age.taler.ar/"
+public let ARS_EXP_EXCHANGE = HTTPS + "exchange-expensive.taler.ar/"
public let DEMOCURRENCY = "KUDOS"
public let TESTCURRENCY = "TESTKUDOS"
//public let LONGCURRENCY = "gold-pressed Latinum" // 20
characters, with dash and space
@@ -83,7 +84,9 @@ extension Notification.Name {
static let ProposalDownloaded = Notification.Name("proposal-downloaded")
static let TaskObservabilityEvent =
Notification.Name("task-observability-event")
static let RequestObservabilityEvent =
Notification.Name("request-observability-event")
+
static let Error = Notification.Name("error")
+ static let TransactionError = Notification.Name("txError")
}
/// Notifications for internal synchronization
diff --git a/TalerWallet1/GNU_Taler InfoPlist.xcstrings
b/TalerWallet1/GNU_Taler InfoPlist.xcstrings
new file mode 100644
index 0000000..19764dd
--- /dev/null
+++ b/TalerWallet1/GNU_Taler InfoPlist.xcstrings
@@ -0,0 +1,78 @@
+{
+ "sourceLanguage" : "en",
+ "strings" : {
+ "CFBundleDisplayName" : {
+ "comment" : "Bundle display name",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "GNU Taler"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "GNU Taler"
+ }
+ }
+ }
+ },
+ "CFBundleName" : {
+ "comment" : "Bundle name",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "GNU_Taler"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "GNU_Taler"
+ }
+ }
+ }
+ },
+ "NSCameraUsageDescription" : {
+ "comment" : "Privacy - Camera Usage Description",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Scan QR Codes"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Escanear códigos QR"
+ }
+ }
+ }
+ },
+ "NSHumanReadableCopyright" : {
+ "comment" : "Copyright (human-readable)",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "© Taler-Systems.com"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "© Taler-Systems.com"
+ }
+ }
+ }
+ }
+ },
+ "version" : "1.0"
+}
\ No newline at end of file
diff --git a/TalerWallet1/Helper/CurrencySpecification.swift
b/TalerWallet1/Helper/CurrencySpecification.swift
index 96a32ca..81af806 100644
--- a/TalerWallet1/Helper/CurrencySpecification.swift
+++ b/TalerWallet1/Helper/CurrencySpecification.swift
@@ -41,6 +41,14 @@ extension Amount {
}
}
+ func string(useSymbol: Bool = true) -> String {
+ let controller = Controller.shared
+ if let currencyInfo = controller.info(for: self.currencyStr) {
+ return self.string(currencyInfo, useSymbol: useSymbol)
+ }
+ return self.readableDescription
+ }
+
func inputDigits(_ currencyInfo: CurrencyInfo) -> UInt {
let inputDigits = currencyInfo.specs.fractionalInputDigits
if inputDigits < 0 { return 0 }
@@ -133,7 +141,7 @@ public struct CurrencyInfo {
formatter.setUseSymbol(useSymbol)
let (integer, fraction) = valueTuple
if let integerStr = formatter.string(for: integer) {
- if fraction == 0 { return integerStr } // formatter
already added trailing zeroes
+ if fraction == 0 { return integerStr.nbs() }
// formatter already added trailing zeroes
if let fractionStr = formatter.string(for: fraction) {
if let decimalSeparator = formatter.currencyDecimalSeparator {
if let fractionIndex = fractionStr.endIndex(of:
decimalSeparator) {
@@ -159,7 +167,7 @@ public struct CurrencyInfo {
}
}
// print(resultStr)
- return resultStr
+ return resultStr.nbs()
}
// if we arrive here then fractionStr doesn't have a
decimal separator. Yikes!
}
@@ -181,14 +189,10 @@ public struct CurrencyInfo {
madeUpStr += Locale.current.decimalSeparator ?? "." //
currencyDecimalSeparator
madeUpStr += String(String(fraction).dropFirst()) // remove the
leading 0
// TODO: fractionalNormalDigits, fractionalTrailingZeroDigits
- return madeUpStr
+ return madeUpStr.nbs()
}
}
-public struct CurrencySpecification2: Codable, Sendable {
- let currencySpecification: CurrencySpecification
-}
-
public struct CurrencySpecification: Codable, Sendable {
enum CodingKeys: String, CodingKey {
case name = "name"
diff --git a/TalerWallet1/Helper/LocalizedAlertError.swift
b/TalerWallet1/Helper/LocalizedAlertError.swift
index 513f93d..3fdaaf3 100644
--- a/TalerWallet1/Helper/LocalizedAlertError.swift
+++ b/TalerWallet1/Helper/LocalizedAlertError.swift
@@ -38,7 +38,7 @@ extension View {
@ViewBuilder
func errorAlert(error: Binding<Error?>,
- buttonTitle: LocalizedStringKey = "xloc.generic.ok",
+ buttonTitle: LocalizedStringKey = "OK",
action: (() -> Void)? = nil) -> some View
{
let localizedAlertError = LocalizedAlertError(error:
error.wrappedValue)
diff --git a/TalerWallet1/Helper/TalerStrings.swift
b/TalerWallet1/Helper/TalerStrings.swift
index 10d4257..bdfa561 100644
--- a/TalerWallet1/Helper/TalerStrings.swift
+++ b/TalerWallet1/Helper/TalerStrings.swift
@@ -40,6 +40,16 @@ extension StringProtocol {
}
extension String {
+ func replacingOccurrences(of char1: String.Element, with char2:
String.Element) -> String {
+ String(self.map {
+ $0 == char1 ? char2 : $0
+ })
+ }
+
+ func nbs() -> String {
+ self.replacingOccurrences(of: " ", with: NONBREAKING)
+ }
+
func tabbed(oneLine: Bool) -> String {
let fragments = self.components(separatedBy: "\t")
if fragments.count > 1 {
diff --git a/TalerWallet1/Localizable.xcstrings
b/TalerWallet1/Localizable.xcstrings
index a4bbaaf..24ab462 100644
--- a/TalerWallet1/Localizable.xcstrings
+++ b/TalerWallet1/Localizable.xcstrings
@@ -8,16 +8,29 @@
"state" : "translated",
"value" : "- %@ Gebühr"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "- %@ comisión"
+ }
}
}
},
", canceled" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : ", abgebrochen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : ", cancelado"
+ }
}
}
},
@@ -29,6 +42,12 @@
"state" : "translated",
"value" : ". Benötigt die Bestätigung der Bank"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : ". Necesita confirmación bancaria"
+ }
}
}
},
@@ -40,6 +59,12 @@
"state" : "translated",
"value" : ". Benötigt K Y C"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : ". Necesita K Y C"
+ }
}
}
},
@@ -50,6 +75,12 @@
"state" : "translated",
"value" : "**Alternative:** Wenn ihre Bank bereits Payto
unterstützt, können Sie diesen Paytolink verwenden:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Alternativa:** Si tu banco ya soporta PayTo, puedes
usar este PayTo-Link:"
+ }
}
}
},
@@ -60,6 +91,12 @@
"state" : "translated",
"value" : "**Alternative:** Verwenden SIe diesen PayTo-Link:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Alternativa:** Usar este PayTo-Link:"
+ }
}
}
},
@@ -70,6 +107,12 @@
"state" : "translated",
"value" : "**Schritt 1:** Kopieren Sie diesen Code und setzen ihn
als Verwendungszweck in ihrer Banking-App oder Bank-Webseite ein:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 1:** Copiar este código y pegarlo en el campo
asunto de tu aplicación bancaria:"
+ }
}
}
},
@@ -80,6 +123,12 @@
"state" : "translated",
"value" : "**Schritt 1:** Kopieren Sie diesen Verwendungszweck"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 1:** Copia y pega este asunto:"
+ }
}
}
},
@@ -90,6 +139,12 @@
"state" : "translated",
"value" : "**Schritt 2:** Kopieren Sie Empfänger und Konto in Ihre
Banking-App oder Bank-Webseite:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 2:** Copia y pega el beneficiario y la cuenta en
sus campos correspondientes en tu aplicación bancaria:"
+ }
}
}
},
@@ -100,6 +155,12 @@
"state" : "translated",
"value" : "**Schritt 2:** Kopieren Sie Empfänger und Konto"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 2:** Copia y pega el beneficiario y cuenta:"
+ }
}
}
},
@@ -110,6 +171,12 @@
"state" : "translated",
"value" : "**Schritt 2:** Kopieren Sie Empfänger und IBAN"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 2:** Copia y pega el beneficiario y IBAN:"
+ }
}
}
},
@@ -120,6 +187,12 @@
"state" : "translated",
"value" : "**Schritt 2:** Wenn Sie es noch nicht in Ihrer
Favoritenliste haben, kopieren Sie Empfänger und IBAN in Ihre Banking-App oder
Bank-Webseite (und speichern den Kontakt als Favorit für das nächste Mal):"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 2:** Si todavía no la tienes en tu lista de
favoritos, entonces copia y pega el beneficiario y IBAN en los campos
correspondientes en tu aplicación bancaria (y guardalos en favoritos para la
próxima vez):"
+ }
}
}
},
@@ -130,6 +203,12 @@
"state" : "translated",
"value" : "**Schritt 3:** Schließen Sie die Überweisung von %@ in
Ihrer Banking-App oder Bank-Webseite ab, dann wird diese Abhebung automatisch
durchgeführt. Die Überweisung kann - je nach Bank - bis zu zwei Tage dauern.
Bitte haben Sie etwas Geduld."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 3:** Completa la transferencia por %@ en tu
aplicación bancaria, entonces esta extracción procedera automaticamente.
Dependiendo de tu bank la transferencia puede tardar desde minutos hasta dos
días hábiles, por favor se paciente."
+ }
}
}
},
@@ -140,6 +219,12 @@
"state" : "translated",
"value" : "**Schritt 3:** Schließen Sie die Überweisung von %@ ab."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "**Paso 3:** Transferir %@."
+ }
}
}
},
@@ -156,6 +241,12 @@
"state" : "new",
"value" : "%1$@ %2$@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "%1$@ %2$@"
+ }
}
}
},
@@ -166,6 +257,12 @@
"state" : "translated",
"value" : "%lld Zeichen von 100"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "%lld caracteres de 100"
+ }
}
}
},
@@ -176,6 +273,12 @@
"state" : "translated",
"value" : "Vor %lld Tagen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "hace %lld días"
+ }
}
}
},
@@ -186,6 +289,12 @@
"state" : "translated",
"value" : "Vor %lld Stunden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "hace %lld horas"
+ }
}
}
},
@@ -196,6 +305,12 @@
"state" : "translated",
"value" : "Vor %lld Minuten"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "hace %lld minutos"
+ }
}
}
},
@@ -206,6 +321,12 @@
"state" : "translated",
"value" : "%lld Jahre"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "%lld años"
+ }
}
}
},
@@ -217,6 +338,12 @@
"state" : "translated",
"value" : "%llu Tag"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "%llu Día"
+ }
}
}
},
@@ -228,6 +355,12 @@
"state" : "translated",
"value" : "%llu Tage"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "%llu Días"
+ }
}
}
},
@@ -238,6 +371,12 @@
"state" : "translated",
"value" : "+ %@ Gebühr"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "+ %@ comisión"
+ }
}
}
},
@@ -248,6 +387,12 @@
"state" : "translated",
"value" : "Vor 1 Stunde"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "hace 1 hora"
+ }
}
}
},
@@ -258,6 +403,12 @@
"state" : "translated",
"value" : "Vor 1 Minute"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "hace 1 minuto"
+ }
}
}
},
@@ -269,6 +420,12 @@
"state" : "translated",
"value" : "Einzahlung abbrechen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Detener deposito"
+ }
}
}
},
@@ -280,6 +437,12 @@
"state" : "translated",
"value" : "P2P Zahlung abbrechen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Detener Envío P2P"
+ }
}
}
},
@@ -291,6 +454,12 @@
"state" : "translated",
"value" : "Zahlung abbrechen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Detener Pago"
+ }
}
}
},
@@ -301,6 +470,12 @@
"state" : "translated",
"value" : "Über %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Hace %@"
+ }
}
}
},
@@ -311,6 +486,12 @@
"state" : "translated",
"value" : "Vor ca. 1½ Stunden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Hace 1½ horas"
+ }
}
}
},
@@ -321,6 +502,12 @@
"state" : "translated",
"value" : "Vor ca. 2 Stunden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "HAce 2 horas"
+ }
}
}
},
@@ -331,6 +518,12 @@
"state" : "translated",
"value" : "Vor ca. 1 Stunde"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Hace una hora"
+ }
}
}
},
@@ -341,6 +534,12 @@
"state" : "translated",
"value" : "Akzeptieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Aceptar"
+ }
}
}
},
@@ -351,6 +550,12 @@
"state" : "translated",
"value" : "P2P Zahlungsempfang akzeptieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Aceptar Recepción P2P"
+ }
}
}
},
@@ -362,6 +567,12 @@
"state" : "translated",
"value" : "Nutzungsbedingungen akzeptieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Aceptar Terminos de Servicio"
+ }
}
}
},
@@ -372,16 +583,29 @@
"state" : "translated",
"value" : "Kontoinhaber:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Dueño de la cuenta:"
+ }
}
}
},
"account of the payee" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Konto des Empfängers"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "cuenta del beneficiario"
+ }
}
}
},
@@ -392,6 +616,12 @@
"state" : "translated",
"value" : "Konto"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Cuenta:"
+ }
}
}
},
@@ -403,17 +633,29 @@
"state" : "translated",
"value" : "Hinzufügen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Agregar"
+ }
}
}
},
"Add Payment Service" : {
- "comment" : "accessibilityLabel for the + button",
+ "comment" : "VoiceOver for the + button",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zahlungsdienst hinzufügen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Agregar Servicio de Pagos"
+ }
}
}
},
@@ -424,6 +666,12 @@
"state" : "translated",
"value" : "Adresse des Zahlungsdienstes"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Dirección de Servicio de Pagos"
+ }
}
}
},
@@ -434,6 +682,12 @@
"state" : "translated",
"value" : "Verfügbarer Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto disponible:"
+ }
}
}
},
@@ -444,6 +698,12 @@
"state" : "translated",
"value" : "Auszugebender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a gastar:"
+ }
}
}
},
@@ -454,6 +714,12 @@
"state" : "translated",
"value" : "Abzuhebender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a extraer:"
+ }
}
}
},
@@ -464,6 +730,12 @@
"state" : "translated",
"value" : "Einzuzahlender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a depositar:"
+ }
}
}
},
@@ -474,6 +746,12 @@
"state" : "translated",
"value" : "Zu bezahlender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a pagar:"
+ }
}
}
},
@@ -484,6 +762,12 @@
"state" : "translated",
"value" : "Anzufordernder Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a pedir:"
+ }
}
}
},
@@ -494,6 +778,12 @@
"state" : "translated",
"value" : "Zu sendender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a envíar:"
+ }
}
}
},
@@ -504,6 +794,12 @@
"state" : "translated",
"value" : "Auszugebender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a gastar:"
+ }
}
}
},
@@ -514,6 +810,12 @@
"state" : "translated",
"value" : "Abzuhebender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto a extraer:"
+ }
}
}
},
@@ -524,6 +826,12 @@
"state" : "translated",
"value" : "Betrag zu groß für eine Abhebung!"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto demasiado grande para una única extracción!"
+ }
}
}
},
@@ -534,6 +842,12 @@
"state" : "translated",
"value" : "Betrag zu klein!"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto demasiado pequeño!"
+ }
}
}
},
@@ -544,6 +858,12 @@
"state" : "translated",
"value" : "Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto:"
+ }
}
}
},
@@ -554,6 +874,12 @@
"state" : "translated",
"value" : "App-Version"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Versión App"
+ }
}
}
},
@@ -564,6 +890,12 @@
"state" : "translated",
"value" : "Sind Sie sicher, dass Sie diese Transaktion abbrechen
wollen?"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Seguro que quiere detener esta transacción?"
+ }
}
}
},
@@ -574,6 +906,12 @@
"state" : "translated",
"value" : "Sind Sie sicher, dass Sie diese Transaktion löschen
wollen?"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Seguro que quiere borrar esta transacción?"
+ }
}
}
},
@@ -584,6 +922,12 @@
"state" : "translated",
"value" : "Sind Sie sicher, dass Sie diese Transaktion scheitern
lassen wollen?"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Seguro que quiere fallar esta transacción?"
+ }
}
}
},
@@ -595,6 +939,12 @@
"state" : "translated",
"value" : "Verfügbar:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Disponible:"
+ }
}
}
},
@@ -605,6 +955,12 @@
"state" : "translated",
"value" : "Verfügbar: %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Disponible:\t%@"
+ }
}
}
},
@@ -616,6 +972,12 @@
"state" : "translated",
"value" : "Backup wiederhergestellt"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Resguardo restaurado"
+ }
}
}
},
@@ -627,6 +989,12 @@
"state" : "translated",
"value" : "Saldo:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Balance:"
+ }
}
}
},
@@ -637,6 +1005,12 @@
"state" : "translated",
"value" : "Bank"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Banco"
+ }
}
}
},
@@ -647,6 +1021,12 @@
"state" : "translated",
"value" : "aber Sie haben nur %@ zum Einzahlen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "pero sólo tiene %@ para depositar."
+ }
}
}
},
@@ -657,6 +1037,12 @@
"state" : "translated",
"value" : "aber Sie haben nur %@ zum Versenden."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "pero sólo tiene %@ para enviar."
+ }
}
}
},
@@ -667,6 +1053,12 @@
"state" : "translated",
"value" : "Abbrechen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Caneclar"
+ }
}
}
},
@@ -677,6 +1069,12 @@
"state" : "translated",
"value" : "Link wird überprüft"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Verificando Link"
+ }
}
}
},
@@ -687,6 +1085,12 @@
"state" : "translated",
"value" : "Wählen Sie die Verfallszeit"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Elija un tiempo de expiración"
+ }
}
}
},
@@ -697,6 +1101,12 @@
"state" : "translated",
"value" : "Gewählter Betrag zum Abheben:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Elija un monto a extraer:"
+ }
}
}
},
@@ -708,6 +1118,12 @@
"state" : "translated",
"value" : "Gewählt:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Elegido:"
+ }
}
}
},
@@ -718,6 +1134,12 @@
"state" : "translated",
"value" : "Schließen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Cerrar"
+ }
}
}
},
@@ -728,6 +1150,12 @@
"state" : "translated",
"value" : "Kamera beenden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Cerrando cámara"
+ }
}
}
},
@@ -738,6 +1166,12 @@
"state" : "translated",
"value" : "Später bestätigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Confirmar después"
+ }
}
}
},
@@ -748,6 +1182,12 @@
"state" : "translated",
"value" : "Jetzt bestätigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Confirmar ahora"
+ }
}
}
},
@@ -759,6 +1199,12 @@
"state" : "translated",
"value" : "Zahlung bestätigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Confirmar Pago"
+ }
}
}
},
@@ -769,6 +1215,12 @@
"state" : "translated",
"value" : "Mit der Bank bestätigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Confirmar con Banco"
+ }
}
}
},
@@ -779,6 +1231,12 @@
"state" : "translated",
"value" : "Abhebung bestätigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Confirmar Extracción"
+ }
}
}
},
@@ -789,36 +1247,63 @@
"state" : "translated",
"value" : "Kontaktiere..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Contactando..."
+ }
}
}
},
"Copy the account" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Konto kopieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar la cuenta"
+ }
}
}
},
"Copy the cryptocode" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Cryptocode kopieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar el cryptocode"
+ }
}
}
},
"Copy the error" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Fehler kopieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar el error"
+ }
}
}
},
@@ -829,26 +1314,46 @@
"state" : "translated",
"value" : "Fehler-JSON kopieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar el error JSON"
+ }
}
}
},
"Copy the IBAN" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "IBAN kopieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar el IBAN"
+ }
}
}
},
"Copy the payee" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Empfänger kopieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar el beneficiario"
+ }
}
}
},
@@ -867,6 +1372,12 @@
"state" : "new",
"value" : "Copy"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar"
+ }
}
}
},
@@ -885,26 +1396,62 @@
"state" : "new",
"value" : "Copy"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Copiar"
+ }
}
}
},
"Cryptocode" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Cryptocode"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Cryptocode"
+ }
+ }
+ }
+ },
+ "Custom Amount" : {
+ "comment" : "pay merchant",
+ "localizations" : {
+ "de" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Betrag ändern"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto personalizado"
+ }
}
}
},
- "Customize Order" : {
+ "Custom Summary" : {
"comment" : "pay merchant",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
- "value" : "Auftrag bearbeiten"
+ "value" : "Zweck ändern"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Descripción personalizado"
}
}
}
@@ -916,6 +1463,12 @@
"state" : "translated",
"value" : "Demo: Mit Digitalem Bargeld ausprobieren wie Sie mit
dem Geld der Zukunft bezahlen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Demo: recibir billetes digitales para experimentar como
pagar con el dinero del futuro."
+ }
}
}
},
@@ -927,6 +1480,12 @@
"state" : "translated",
"value" : "Einzahlen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar"
+ }
}
}
},
@@ -938,6 +1497,12 @@
"state" : "translated",
"value" : "%@\teinzahlen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar\t%@"
+ }
}
}
},
@@ -949,6 +1514,12 @@
"state" : "translated",
"value" : "%@ einzahlen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar %@"
+ }
}
}
},
@@ -960,6 +1531,12 @@
"state" : "translated",
"value" : "Einzahlen:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar:"
+ }
}
}
},
@@ -978,6 +1555,12 @@
"state" : "new",
"value" : "Deposit"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar"
+ }
}
}
},
@@ -988,6 +1571,12 @@
"state" : "translated",
"value" : "Interner Deserialisierungsfehler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Error de deserialización"
+ }
}
}
},
@@ -998,6 +1587,12 @@
"state" : "translated",
"value" : "Fertig"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Terminado"
+ }
}
}
},
@@ -1009,6 +1604,12 @@
"state" : "translated",
"value" : "Netto:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Efectivo:"
+ }
}
}
},
@@ -1026,6 +1627,12 @@
"state" : "new",
"value" : "Either provide this payment link"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Proporcione este link de pago"
+ }
}
}
},
@@ -1043,6 +1650,12 @@
"state" : "new",
"value" : "to the payee, or"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "al beneficiario, o"
+ }
}
}
},
@@ -1061,6 +1674,12 @@
"state" : "new",
"value" : "let the payee scan this QR code to receive %@."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "deje que el beneficiario escanee este código QR para
recibir %@."
+ }
}
}
},
@@ -1079,6 +1698,12 @@
"state" : "new",
"value" : "Either"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "También"
+ }
}
}
},
@@ -1096,6 +1721,12 @@
"state" : "new",
"value" : "or scan this"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "o escanee este"
+ }
}
}
},
@@ -1114,6 +1745,12 @@
"state" : "new",
"value" : "to receive %@."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "para reciribr %@."
+ }
}
}
},
@@ -1131,6 +1768,12 @@
"state" : "new",
"value" : "Either provide this payment link"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Proporcione este link the pago"
+ }
}
}
},
@@ -1148,6 +1791,12 @@
"state" : "new",
"value" : "to the payer, or"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "al pagador, o"
+ }
}
}
},
@@ -1166,6 +1815,12 @@
"state" : "new",
"value" : "let the payer scan this QR code to pay %@."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "deje que el pagador escanee este código QR para pagar
%@."
+ }
}
}
},
@@ -1184,6 +1839,12 @@
"state" : "new",
"value" : "Either"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "También"
+ }
}
}
},
@@ -1201,6 +1862,12 @@
"state" : "new",
"value" : "or scan this"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "o escanee este"
+ }
}
}
},
@@ -1219,6 +1886,12 @@
"state" : "new",
"value" : "to pay %@."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "para pagar %@."
+ }
}
}
},
@@ -1229,6 +1902,12 @@
"state" : "translated",
"value" : "aktiviert, wenn Kontoinhaber und IBAN eingegeben sind"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "habilitado cuando el dueño de la cuenta y el IBAN estan
completos"
+ }
}
}
},
@@ -1239,6 +1918,12 @@
"state" : "translated",
"value" : "aktiviert, wenn der Betrag ungleich Null ist, aber
nicht höher als Ihr verfügbarer Betrag"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "habilitado cuando el monto no es cero, pero no mas alto
del monto disponible"
+ }
}
}
},
@@ -1249,6 +1934,12 @@
"state" : "translated",
"value" : "aktiviert, wenn Betreff und Ablaufdatum eingegeben sind"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "habilitado cuando el asunto y la expiración esta
completos"
+ }
}
}
},
@@ -1259,6 +1950,12 @@
"state" : "translated",
"value" : "Verwendungszweck eingeben:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Ingrese asunto:"
+ }
}
}
},
@@ -1269,6 +1966,12 @@
"state" : "translated",
"value" : "Fehler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Error"
+ }
}
}
},
@@ -1279,16 +1982,29 @@
"state" : "translated",
"value" : "Läuft ab in:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Expira en:"
+ }
}
}
},
"Expires: %@" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Läuft ab: %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Expira: %@"
+ }
}
}
},
@@ -1307,6 +2023,12 @@
"state" : "new",
"value" : "Fee:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Comisión:"
+ }
}
}
},
@@ -1325,6 +2047,12 @@
"state" : "new",
"value" : "Fee:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Comisión:"
+ }
}
}
},
@@ -1335,6 +2063,12 @@
"state" : "translated",
"value" : "Für Löschen, Abbrechen und Scheitern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Para botones Borrar, Fallar & Detener"
+ }
}
}
},
@@ -1345,6 +2079,12 @@
"state" : "translated",
"value" : "von %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "desde %@"
+ }
}
}
},
@@ -1355,6 +2095,12 @@
"state" : "translated",
"value" : "Bruttobetrag zu erhalten:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto bruto a recibir:"
+ }
}
}
},
@@ -1365,16 +2111,29 @@
"state" : "translated",
"value" : "Haptik"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Hápticos"
+ }
}
}
},
"IBAN of the payee" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "IBAN des Empfängers"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "IBAN del beneficiario"
+ }
}
}
},
@@ -1385,6 +2144,12 @@
"state" : "translated",
"value" : "IBAN:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "IBAN:"
+ }
}
}
},
@@ -1395,16 +2160,29 @@
"state" : "translated",
"value" : "Wenn diese Wallet einem Kind oder Minderjährigen
gehört, sollte das generierte Elektronic-Cash altersbeschränkt sein."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Si esta billetera pertenece a un niño/a o adolecente,
el dinero electrónico generado deberá ser restringido por edad:"
+ }
}
}
},
"In progress" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "In Verarbeitung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "En progreso"
+ }
}
}
},
@@ -1415,6 +2193,12 @@
"state" : "translated",
"value" : "Initialisierungsfehler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Error de inicialización"
+ }
}
}
},
@@ -1425,6 +2209,12 @@
"state" : "translated",
"value" : "Interner Systemfehler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Código de error interno"
+ }
}
}
},
@@ -1435,6 +2225,12 @@
"state" : "translated",
"value" : "KYC"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "KYC"
+ }
}
}
},
@@ -1446,6 +2242,12 @@
"state" : "translated",
"value" : "Sprache:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Lenguaje:"
+ }
}
}
},
@@ -1463,6 +2265,12 @@
"state" : "new",
"value" : "Demo Bank Website"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Sitio web Banco Demo"
+ }
}
}
},
@@ -1480,6 +2288,12 @@
"state" : "new",
"value" : "Spend test money"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Gastar dinero de prueba"
+ }
}
}
},
@@ -1497,6 +2311,12 @@
"state" : "new",
"value" : "Get demo money"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Obtener dinero de prueba"
+ }
}
}
},
@@ -1507,6 +2327,12 @@
"state" : "translated",
"value" : "Listenstil:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Estilo de Lista:"
+ }
}
}
},
@@ -1517,6 +2343,12 @@
"state" : "translated",
"value" : "Laden..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Cargando…"
+ }
}
}
},
@@ -1526,7 +2358,13 @@
"de" : {
"stringUnit" : {
"state" : "translated",
- "value" : "Verlust:"
+ "value" : "Verlust:"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Perdido:"
}
}
}
@@ -1538,6 +2376,12 @@
"state" : "translated",
"value" : "Hauptmenü"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Menu principal"
+ }
}
}
},
@@ -1556,6 +2400,12 @@
"state" : "new",
"value" : "Aborted"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Detenido"
+ }
}
}
},
@@ -1574,6 +2424,12 @@
"state" : "new",
"value" : "Aborting"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Deteniendo"
+ }
}
}
},
@@ -1592,6 +2448,12 @@
"state" : "new",
"value" : "Deleted"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Borrado"
+ }
}
}
},
@@ -1610,6 +2472,12 @@
"state" : "new",
"value" : "Dialog"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Diálogo"
+ }
}
}
},
@@ -1628,6 +2496,12 @@
"state" : "new",
"value" : "Done"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Terminado"
+ }
}
}
},
@@ -1646,6 +2520,12 @@
"state" : "new",
"value" : "Expired"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Expirado"
+ }
}
}
},
@@ -1664,6 +2544,12 @@
"state" : "new",
"value" : "Failed"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Falló"
+ }
}
}
},
@@ -1682,6 +2568,12 @@
"state" : "new",
"value" : "Pending"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pendiente"
+ }
}
}
},
@@ -1692,6 +2584,12 @@
"state" : "translated",
"value" : "Zahlungsdienste verwalten"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Administrar proveedores de servicio de pago..."
+ }
}
}
},
@@ -1703,6 +2601,12 @@
"state" : "translated",
"value" : "Händler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Comerciante"
+ }
}
}
},
@@ -1713,6 +2617,12 @@
"state" : "translated",
"value" : "Minimalistisch"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Minimalistico"
+ }
}
}
},
@@ -1731,6 +2641,12 @@
"state" : "new",
"value" : "AML required"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Requiere AML"
+ }
}
}
},
@@ -1749,6 +2665,12 @@
"state" : "new",
"value" : "Waiting for bank transfer"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Esperando la transferencia bancaria"
+ }
}
}
},
@@ -1767,23 +2689,11 @@
"state" : "new",
"value" : "KYC required"
}
- }
- }
- },
- "MinorState.mergekyc" : {
- "comment" : "TxMinorState heading",
- "extractionState" : "extracted_with_value",
- "localizations" : {
- "de" : {
- "stringUnit" : {
- "state" : "translated",
- "value" : "KYC benötigt"
- }
},
- "en" : {
+ "es" : {
"stringUnit" : {
- "state" : "new",
- "value" : "KYC required"
+ "state" : "translated",
+ "value" : "Requiere KYC"
}
}
}
@@ -1796,6 +2706,12 @@
"state" : "translated",
"value" : "Geld verloren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Dinero perdido"
+ }
}
}
},
@@ -1806,6 +2722,12 @@
"state" : "translated",
"value" : "Geld verloren:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Dinero perdido:"
+ }
}
}
},
@@ -1816,6 +2738,12 @@
"state" : "translated",
"value" : "Mehr Info über GNU Taler im Allgemeinen..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Mas información acerca de GNU Taler en general..."
+ }
}
}
},
@@ -1826,6 +2754,12 @@
"state" : "translated",
"value" : "Mehr Info über diese App..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Mas información acerca de esta aplicación..."
+ }
}
}
},
@@ -1836,6 +2770,12 @@
"state" : "translated",
"value" : "Vor mehr als einer Woche"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Hace mas de una semana"
+ }
}
}
},
@@ -1854,6 +2794,12 @@
"state" : "new",
"value" : "Deposit"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar"
+ }
}
}
},
@@ -1872,6 +2818,12 @@
"state" : "new",
"value" : "Deposit %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Depositar %@"
+ }
}
}
},
@@ -1890,6 +2842,12 @@
"state" : "new",
"value" : "Request %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedir %@"
+ }
}
}
},
@@ -1908,6 +2866,12 @@
"state" : "new",
"value" : "Request %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedir %@"
+ }
}
}
},
@@ -1926,6 +2890,12 @@
"state" : "new",
"value" : "Send %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Senviar %@"
+ }
}
}
},
@@ -1944,6 +2914,12 @@
"state" : "new",
"value" : "Send %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Enviar %@"
+ }
}
}
},
@@ -1962,6 +2938,12 @@
"state" : "new",
"value" : "Withdraw %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Extraer %@"
+ }
}
}
},
@@ -1980,6 +2962,12 @@
"state" : "new",
"value" : "Withdraw %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Extraer %@"
+ }
}
}
},
@@ -1990,6 +2978,12 @@
"state" : "translated",
"value" : "Nettobetrag erhalten:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto Neto a recirbir:"
+ }
}
}
},
@@ -2001,6 +2995,12 @@
"state" : "translated",
"value" : "Weiter"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Siguiente"
+ }
}
}
},
@@ -2012,6 +3012,12 @@
"state" : "translated",
"value" : "Kein Datum"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Sin fecha"
+ }
}
}
},
@@ -2022,6 +3028,12 @@
"state" : "translated",
"value" : "Keine Gebühr"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Sin comisión de extracción"
+ }
}
}
},
@@ -2032,6 +3044,12 @@
"state" : "translated",
"value" : "Hinweis: Es braucht eine ganze Weile um diesen Betrag
abzuheben. Seien Sie noch geduldiger..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Nota: Tomará algo de tiempo para extraer este monto!
Sea paciente..."
+ }
}
}
},
@@ -2042,6 +3060,12 @@
"state" : "translated",
"value" : "Hinweis: Es braucht eine Weile um diesen Betrag
abzuheben. Seien Sie geduldig..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Nota: Tomará algo de tiempo estraer este monto. Sea
paciente..."
+ }
}
}
},
@@ -2052,6 +3076,12 @@
"state" : "translated",
"value" : "WalleCore observieren"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Observe walletCore"
+ }
}
}
},
@@ -2062,6 +3092,12 @@
"state" : "translated",
"value" : "Erhaltenen Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto obtenido:"
+ }
}
}
},
@@ -2073,6 +3109,28 @@
"state" : "translated",
"value" : "Erhalten:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Obtenido:"
+ }
+ }
+ }
+ },
+ "OK" : {
+ "localizations" : {
+ "de" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "OK"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "OK"
+ }
}
}
},
@@ -2083,6 +3141,12 @@
"state" : "translated",
"value" : "Möglichst wenig Text"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Omitir texto cuando es posible"
+ }
}
}
},
@@ -2093,6 +3157,12 @@
"state" : "translated",
"value" : "on LocalConsole"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "en LocalConsole"
+ }
}
}
},
@@ -2103,6 +3173,12 @@
"state" : "translated",
"value" : "KYC Webseite öffnen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Abrir sitio web KYC"
+ }
}
}
},
@@ -2113,6 +3189,12 @@
"state" : "translated",
"value" : "Händler-Webseite öffnen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Abrir sitio web del comerciante"
+ }
}
}
},
@@ -2123,6 +3205,12 @@
"state" : "translated",
"value" : "Einstellungen öffnen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Abrir Configuración"
+ }
}
}
},
@@ -2133,6 +3221,12 @@
"state" : "translated",
"value" : "Kamera wird geöffnet"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Abrir Camara"
+ }
}
}
},
@@ -2143,6 +3237,12 @@
"state" : "translated",
"value" : "P2P bereit"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "P2P Listo"
+ }
}
}
},
@@ -2153,6 +3253,12 @@
"state" : "translated",
"value" : "P2P erhalten"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "P2P Recibir"
+ }
}
}
},
@@ -2164,6 +3270,12 @@
"state" : "translated",
"value" : "Bezahlt"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagado"
+ }
}
}
},
@@ -2174,6 +3286,12 @@
"state" : "translated",
"value" : "Bezahlter Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto pagado:"
+ }
}
}
},
@@ -2185,6 +3303,12 @@
"state" : "translated",
"value" : "P2P bezahlt"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagado P2P"
+ }
}
}
},
@@ -2196,6 +3320,12 @@
"state" : "translated",
"value" : "Anforderung bezahlt"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedido Pagado"
+ }
}
}
},
@@ -2207,16 +3337,29 @@
"state" : "translated",
"value" : "Bezahlt:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagado:"
+ }
}
}
},
"Pay P2P" : {
+ "comment" : "Nav Title",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "P2P bezahlen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagar P2P"
+ }
}
}
},
@@ -2228,6 +3371,12 @@
"state" : "translated",
"value" : "Pay Peer-Pull"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagar Peer-Pull"
+ }
}
}
},
@@ -2239,6 +3388,12 @@
"state" : "translated",
"value" : "Pay Peer-Push"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagar Peer-Push"
+ }
}
}
},
@@ -2250,6 +3405,12 @@
"state" : "translated",
"value" : "Zahlungsanforderung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedido pagado"
+ }
}
}
},
@@ -2261,16 +3422,29 @@
"state" : "translated",
"value" : "Bezahlen:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pagar:"
+ }
}
}
},
"Payee" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Empfänger"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Beneficiario"
+ }
}
}
},
@@ -2279,7 +3453,13 @@
"de" : {
"stringUnit" : {
"state" : "translated",
- "value" : "Empfänger:"
+ "value" : "Empfänger:"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Beneficiario:"
}
}
}
@@ -2292,6 +3472,12 @@
"state" : "translated",
"value" : "Zahlung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pago"
+ }
}
}
},
@@ -2302,6 +3488,12 @@
"state" : "translated",
"value" : "Zahlungsdienst"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Proveedor de pagos:"
+ }
}
}
},
@@ -2313,6 +3505,12 @@
"state" : "translated",
"value" : "Ausstehend"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pendiente"
+ }
}
}
},
@@ -2323,6 +3521,12 @@
"state" : "translated",
"value" : "Zu erhaltender Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto pendiente a obtener:"
+ }
}
}
},
@@ -2334,6 +3538,12 @@
"state" : "translated",
"value" : "Ausstehend:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pendiente:"
+ }
}
}
},
@@ -2344,6 +3554,12 @@
"state" : "translated",
"value" : "Zahlungs-Töne abspielen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Reproducir Sonidos de Pago"
+ }
}
}
},
@@ -2354,6 +3570,12 @@
"state" : "translated",
"value" : "Bitte erlauben Sie den Zugriff auf die Kamera in den
Systemeinstellungen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Por favor permita el acceso a la cámara desde
configuración."
+ }
}
}
},
@@ -2364,6 +3586,12 @@
"state" : "translated",
"value" : "Bitte geben Sie die URL ein"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Por favor ingrese la URL"
+ }
}
}
},
@@ -2374,6 +3602,12 @@
"state" : "translated",
"value" : "Nettopreis:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Precio (neto):"
+ }
}
}
},
@@ -2385,6 +3619,12 @@
"state" : "translated",
"value" : "Preis:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Precio:"
+ }
}
}
},
@@ -2395,6 +3635,12 @@
"state" : "translated",
"value" : "QR Code"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Código QR"
+ }
}
}
},
@@ -2405,6 +3651,12 @@
"state" : "translated",
"value" : "QR Code und Link können auch aus der Umsatzliste
kopiert/geteilt werden."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "El código QR y el link también pueden ser escaneados o
copiados / compartidos desde Transacciones después."
+ }
}
}
},
@@ -2416,6 +3668,12 @@
"state" : "translated",
"value" : "Erhalten (brutto):"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Recibir (bruto):"
+ }
}
}
},
@@ -2427,6 +3685,12 @@
"state" : "translated",
"value" : "Geld erhalten"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Recibir Dinero"
+ }
}
}
},
@@ -2438,6 +3702,12 @@
"state" : "translated",
"value" : "Erhalten (netto):"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Recibir (neto):"
+ }
}
}
},
@@ -2449,6 +3719,12 @@
"state" : "translated",
"value" : "Geld erhalten"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Dinero recibido"
+ }
}
}
},
@@ -2460,6 +3736,12 @@
"state" : "translated",
"value" : "P2P erhalten"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Recibido P2P"
+ }
}
}
},
@@ -2470,6 +3752,12 @@
"state" : "translated",
"value" : "Aktuellste %lld Umsätze"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "%lld transacciones recientes"
+ }
}
}
},
@@ -2480,6 +3768,12 @@
"state" : "translated",
"value" : "Aktueller Umsatz"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Transacciones recientes"
+ }
}
}
},
@@ -2491,6 +3785,12 @@
"state" : "translated",
"value" : "Recoup"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Compensación"
+ }
}
}
},
@@ -2502,6 +3802,12 @@
"state" : "translated",
"value" : "Recoup:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Compensación:"
+ }
}
}
},
@@ -2513,6 +3819,12 @@
"state" : "translated",
"value" : "Erneuerung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Actualizar"
+ }
}
}
},
@@ -2524,6 +3836,12 @@
"state" : "translated",
"value" : "Erstattung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Devolución"
+ }
}
}
},
@@ -2534,6 +3852,12 @@
"state" : "translated",
"value" : "Erstatteter Betrag:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Monto devuelto:"
+ }
}
}
},
@@ -2545,6 +3869,12 @@
"state" : "translated",
"value" : "Erstattet:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Devuelto:"
+ }
}
}
},
@@ -2555,6 +3885,12 @@
"state" : "translated",
"value" : "Neu laden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Recargar"
+ }
}
}
},
@@ -2566,6 +3902,12 @@
"state" : "translated",
"value" : "%@ anfordern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedir %@"
+ }
}
}
},
@@ -2577,6 +3919,12 @@
"state" : "translated",
"value" : "Geld anfordern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedir dinero"
+ }
}
}
},
@@ -2595,6 +3943,12 @@
"state" : "new",
"value" : "Request\tPayment"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedir\tPago"
+ }
}
}
},
@@ -2613,6 +3967,12 @@
"state" : "new",
"value" : "Request"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pedir"
+ }
}
}
},
@@ -2624,6 +3984,12 @@
"state" : "translated",
"value" : "Angefordertes Geld"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Dinero pedido"
+ }
}
}
},
@@ -2634,6 +4000,12 @@
"state" : "translated",
"value" : "Zurücksetzen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Reset"
+ }
}
}
},
@@ -2644,6 +4016,12 @@
"state" : "translated",
"value" : "Wallet zurücksetzen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Reiniciar Billetera"
+ }
}
}
},
@@ -2654,6 +4032,12 @@
"state" : "translated",
"value" : "Beschränkung:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Restricción:"
+ }
}
}
},
@@ -2664,6 +4048,12 @@
"state" : "translated",
"value" : "Gerade eben"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Ahora mismo"
+ }
}
}
},
@@ -2674,6 +4064,12 @@
"state" : "translated",
"value" : "Sichern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Guardar"
+ }
}
}
},
@@ -2684,6 +4080,12 @@
"state" : "translated",
"value" : "QR Code scannen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Escanear códigos QR"
+ }
}
}
},
@@ -2694,6 +4096,12 @@
"state" : "translated",
"value" : "Um QR Codes zu scannen wird Zugriff auf die Kamera
benötigt"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Escaneando códigos QR requiere acceso a la cámara"
+ }
}
}
},
@@ -2705,6 +4113,12 @@
"state" : "translated",
"value" : "Geplant"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Programado"
+ }
}
}
},
@@ -2715,6 +4129,12 @@
"state" : "translated",
"value" : "Abwärts blättern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Desplazar hacia abajo"
+ }
}
}
},
@@ -2725,6 +4145,12 @@
"state" : "translated",
"value" : "Aufwärts blättern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Desplazar hacia arriba"
+ }
}
}
},
@@ -2735,6 +4161,12 @@
"state" : "translated",
"value" : "Alter auswählen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Seleccione edad"
+ }
}
}
},
@@ -2746,6 +4178,12 @@
"state" : "translated",
"value" : "Jetzt %@ senden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Enviar %@ ahora"
+ }
}
}
},
@@ -2757,6 +4195,12 @@
"state" : "translated",
"value" : "Geld senden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Enviar Dinero"
+ }
}
}
},
@@ -2775,6 +4219,12 @@
"state" : "new",
"value" : "Send\tMoney"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Enviar\tDinero"
+ }
}
}
},
@@ -2793,6 +4243,12 @@
"state" : "new",
"value" : "Send"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Enviar"
+ }
}
}
},
@@ -2804,6 +4260,12 @@
"state" : "translated",
"value" : "Geld gesendet"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Enviar Dinero"
+ }
}
}
},
@@ -2814,6 +4276,12 @@
"state" : "translated",
"value" : "Interner Serialisierungsfehler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Error de serialización"
+ }
}
}
},
@@ -2824,27 +4292,46 @@
"state" : "translated",
"value" : "Teilen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Compartir"
+ }
}
}
},
"Share the PayTo URL" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Die PayTo URL teilen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Compartir la URL PayTo"
+ }
}
}
},
"Sheet.ID." : {
- "comment" : "AccessibilityLabel",
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Blatt.ID."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Sheet.ID."
+ }
}
}
},
@@ -2856,6 +4343,12 @@
"state" : "translated",
"value" : "Kurzwahl"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Atajo"
+ }
}
}
},
@@ -2866,6 +4359,12 @@
"state" : "translated",
"value" : "Logs anzeigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Mostrar logs"
+ }
}
}
},
@@ -2876,6 +4375,12 @@
"state" : "translated",
"value" : "Warnungen anzeigen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Mostrar advertencias"
+ }
}
}
},
@@ -2886,6 +4391,12 @@
"state" : "translated",
"value" : "Zeigt bei welchen Dialog Sie gerade sind"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Mostrar en que vista estás actualmente."
+ }
}
}
},
@@ -2896,6 +4407,12 @@
"state" : "translated",
"value" : "Da die Demobank Taler direkt unterstützt, können Sie
eine Abhebung starten von der"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Como el bank de demo esta integrado con Taler, puede
comenzar una extracción directamente en el"
+ }
}
}
},
@@ -2906,6 +4423,12 @@
"state" : "translated",
"value" : "Ausstehende Umsätze"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Algunas transacciones pendientes"
+ }
}
}
},
@@ -2916,6 +4439,12 @@
"state" : "translated",
"value" : "Standard iOS Zeichensatz"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Fuente iOS Standard"
+ }
}
}
},
@@ -2926,6 +4455,12 @@
"state" : "translated",
"value" : "Status: %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Estado: %@"
+ }
}
}
},
@@ -2936,6 +4471,12 @@
"state" : "translated",
"value" : "Verwendungszweck"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Asunto"
+ }
}
}
},
@@ -2946,16 +4487,29 @@
"state" : "translated",
"value" : "Übersicht"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Resumen"
+ }
}
}
},
"Taler Logo" : {
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Taler Logo"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Logo Taler"
+ }
}
}
},
@@ -2964,7 +4518,13 @@
"de" : {
"stringUnit" : {
"state" : "translated",
- "value" : "Drücken Sie den Button um auf die KYC Webseite zu
gehen."
+ "value" : "Drücken Sie den Button um auf die KYC Webseite zu
gehen."
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Toque el boton para ir la sitio web KYC."
}
}
}
@@ -2976,6 +4536,12 @@
"state" : "translated",
"value" : "Nutzungsbedingungen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Términos de servicio"
+ }
}
}
},
@@ -2986,6 +4552,12 @@
"state" : "translated",
"value" : "Die Bank wartet auf Ihre Freigabe."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "El banco esta esperando su confirmación."
+ }
}
}
},
@@ -2996,6 +4568,12 @@
"state" : "translated",
"value" : "Der Zahlungsdienst wartet auf Ihre Überweisung."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "El Proveedor de Servicio de Pago esta esperando por su
transferencia bancaria."
+ }
}
}
},
@@ -3006,6 +4584,12 @@
"state" : "translated",
"value" : "Es gibt noch keine Zahlungsdienste."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "No hay Servicios de Pago todavía."
+ }
}
}
},
@@ -3016,6 +4600,12 @@
"state" : "translated",
"value" : "Es gibt noch keine Umsätze for %@."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "No hay transacciones para %@."
+ }
}
}
},
@@ -3026,6 +4616,12 @@
"state" : "translated",
"value" : "Es gibt noch kein digitales Geld in Ihrem Wallet."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "No hay dinero digital en tu billetera."
+ }
}
}
},
@@ -3036,6 +4632,12 @@
"state" : "translated",
"value" : "Dies ist obligatorisch, da Ihr Geld sonst nicht in
dieser Wallet ankommt."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Esto es obligatorio, sino su dinero no llegará a la
billetera."
+ }
}
}
},
@@ -3046,6 +4648,12 @@
"state" : "translated",
"value" : "Das kann nicht rückgängig gemacht werden"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Esta operación no puede ser deshecha"
+ }
}
}
},
@@ -3056,6 +4664,12 @@
"state" : "translated",
"value" : "Diese Transaktion ist noch nicht bereit..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Esta transacción no esta lista..."
+ }
}
}
},
@@ -3073,6 +4687,12 @@
"state" : "new",
"value" : "Balances"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Saldos"
+ }
}
}
},
@@ -3090,11 +4710,17 @@
"state" : "new",
"value" : "Payment Services"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Servicios de Pago"
+ }
}
}
},
"TitleIncoming_Full" : {
- "comment" : "`Pending incoming´ in Balances - set exactly 1 \t for line
break",
+ "comment" : "`Pending incoming´ in Balances - set exactly 1 \\t for line
break",
"extractionState" : "extracted_with_value",
"localizations" : {
"de" : {
@@ -3108,6 +4734,12 @@
"state" : "new",
"value" : "Pending\tincoming"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pendiente\tentrante"
+ }
}
}
},
@@ -3126,11 +4758,17 @@
"state" : "new",
"value" : "Incoming"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Entrante"
+ }
}
}
},
"TitleOutgoing_Full" : {
- "comment" : "`Pending outgoing´ in Balances - set exactly 1 \t for line
break",
+ "comment" : "`Pending outgoing´ in Balances - set exactly 1 \\t for line
break",
"extractionState" : "extracted_with_value",
"localizations" : {
"de" : {
@@ -3144,6 +4782,12 @@
"state" : "new",
"value" : "Pending\toutgoing"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pendiente\tsaliente"
+ }
}
}
},
@@ -3162,6 +4806,12 @@
"state" : "new",
"value" : "Outgoing"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Saliente"
+ }
}
}
},
@@ -3179,6 +4829,12 @@
"state" : "new",
"value" : "Settings"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Configuración"
+ }
}
}
},
@@ -3189,6 +4845,12 @@
"state" : "translated",
"value" : "Umsatzliste"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Lista de transacciones"
+ }
}
}
},
@@ -3200,6 +4862,12 @@
"state" : "translated",
"value" : "Umsätze"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Transacciones"
+ }
}
}
},
@@ -3210,6 +4878,12 @@
"state" : "translated",
"value" : "Überweisen Sie %@ an den Zahlungsdienst."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Transferir %@ al Servicio de Pagos."
+ }
}
}
},
@@ -3228,6 +4902,12 @@
"state" : "new",
"value" : "Abort"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Detener"
+ }
}
}
},
@@ -3246,6 +4926,12 @@
"state" : "new",
"value" : "Delete from history"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Borrar del historial"
+ }
}
}
},
@@ -3264,6 +4950,12 @@
"state" : "new",
"value" : "Fail"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Fallar"
+ }
}
}
},
@@ -3282,6 +4974,12 @@
"state" : "new",
"value" : "Retry now"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Reintentar ahora"
+ }
}
}
},
@@ -3300,6 +4998,12 @@
"state" : "new",
"value" : "Abort pending..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Detención pendiente..."
+ }
}
}
},
@@ -3318,6 +5022,12 @@
"state" : "new",
"value" : "Deleted from list"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Borrado de la lista"
+ }
}
}
},
@@ -3336,6 +5046,12 @@
"state" : "new",
"value" : "Failing..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Fallando..."
+ }
}
}
},
@@ -3354,6 +5070,12 @@
"state" : "new",
"value" : "Retrying..."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Reintentando..."
+ }
}
}
},
@@ -3364,6 +5086,12 @@
"state" : "translated",
"value" : "Unbekanntes Kommando"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "comando desconocido"
+ }
}
}
},
@@ -3374,6 +5102,12 @@
"state" : "translated",
"value" : "Unbekannter Fehler"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Error desconocido"
+ }
}
}
},
@@ -3384,6 +5118,12 @@
"state" : "translated",
"value" : "Unbekannte Zahlungsmethode"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "método de pago desconocido"
+ }
}
}
},
@@ -3395,6 +5135,12 @@
"state" : "translated",
"value" : "Unbekannter Zahlungsdienst"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Proveedor de Pagos desconocido"
+ }
}
}
},
@@ -3405,6 +5151,12 @@
"state" : "translated",
"value" : "Unbekannter Zahlungsdienst"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Servicio de Pago Desconocido"
+ }
}
}
},
@@ -3415,6 +5167,12 @@
"state" : "translated",
"value" : "unbeschränkt"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "sin restricción"
+ }
}
}
},
@@ -3425,6 +5183,12 @@
"state" : "translated",
"value" : "Fügen Sie einen Zahlungsdienst hinzu."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Use el botón Agregar para agregar un servicio."
+ }
}
}
},
@@ -3435,6 +5199,12 @@
"state" : "translated",
"value" : "Scannen Sie einen QR-Code um eine Abhebung zu starten
wenn Ihre Bank schon Taler-Abhebungen unterstützt."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Use el botón de escaneo de código QR para comenzar una
extracción si su banco ya soporta sistema Taler."
+ }
}
}
},
@@ -3445,6 +5215,12 @@
"state" : "translated",
"value" : "Mit dem Zahlungsdienst:"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Usando proveedor de servicio de pago:"
+ }
}
}
},
@@ -3455,6 +5231,12 @@
"state" : "translated",
"value" : "via %@"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "vía %@"
+ }
}
}
},
@@ -3465,17 +5247,29 @@
"state" : "translated",
"value" : "Vibrations-Feedback"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Vibración"
+ }
}
}
},
"View.ID." : {
- "comment" : "AccessibilityLabel",
+ "comment" : "VoiceOver",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Seiten-ID."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "View.ID."
+ }
}
}
},
@@ -3486,6 +5280,12 @@
"state" : "translated",
"value" : "Gehe zur taler.net Webseite"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Visite el sitio web taler.net"
+ }
}
}
},
@@ -3496,6 +5296,12 @@
"state" : "translated",
"value" : "WalletCore-Version"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Versión WalletCore"
+ }
}
}
},
@@ -3506,6 +5312,12 @@
"state" : "translated",
"value" : "Wenn eine Transaktion abgeschlossen ist"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Cuando una trasacción termina"
+ }
}
}
},
@@ -3516,6 +5328,12 @@
"state" : "translated",
"value" : "Geht zur Bank-Webseite um diese Abhebung zu bestätigen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá al sitio web del bank para confirmar esta
extracción."
+ }
}
}
},
@@ -3526,6 +5344,12 @@
"state" : "translated",
"value" : "Geht zur Detail-Ansicht."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá a ver el detalle."
+ }
}
}
},
@@ -3536,6 +5360,12 @@
"state" : "translated",
"value" : "Geht zur KYC-Webseite um diese Abhebung zu bestätigen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá al sitio web KYC para confirmar esta extracción"
+ }
}
}
},
@@ -3546,6 +5376,12 @@
"state" : "translated",
"value" : "Geht zur Transaktions-Liste"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá a la lista de transacciones principal."
+ }
}
}
},
@@ -3556,6 +5392,12 @@
"state" : "translated",
"value" : "Geht zu den ausstehenden Transaktionen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá a transacciones pendientes."
+ }
}
}
},
@@ -3566,6 +5408,12 @@
"state" : "translated",
"value" : "Geht zur Demo Shop-Webseite"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá al sitio web del comerciante demo."
+ }
}
}
},
@@ -3576,6 +5424,12 @@
"state" : "translated",
"value" : "Geht zur Händler-Webseite"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Irá al sitio web del comerciante."
+ }
}
}
},
@@ -3586,6 +5440,12 @@
"state" : "translated",
"value" : "Überweisung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Transferencia bancaria"
+ }
}
}
},
@@ -3597,6 +5457,12 @@
"state" : "translated",
"value" : "%@\tabheben"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Extraer\t%@"
+ }
}
}
},
@@ -3608,6 +5474,12 @@
"state" : "translated",
"value" : "Abhebung"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Extracción"
+ }
}
}
},
@@ -3626,11 +5498,14 @@
"state" : "new",
"value" : "Withdraw"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Extraer"
+ }
}
}
- },
- "xloc.generic.ok" : {
-
},
"Yesterday" : {
"localizations" : {
@@ -3639,6 +5514,12 @@
"state" : "translated",
"value" : "Gestern"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Ayer"
+ }
}
}
},
@@ -3649,6 +5530,12 @@
"state" : "translated",
"value" : "Sie können in den Einstellungen manuell einen
Zahlungsdienst hinzufügen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "También puede agregar un servicio de pago manualmente
en Configuración."
+ }
}
}
},
@@ -3659,6 +5546,12 @@
"state" : "translated",
"value" : "Sie können auch im Salden-Tab einen Abheben-QR-Code
scannen um automatisch einen Zahlungsdienst hinzuzufügen."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "También puede escanear el código QR de extracción desde
to banco on la solapa de Banaces para agregar un servicio de pago
automaticamente."
+ }
}
}
},
@@ -3669,6 +5562,12 @@
"state" : "translated",
"value" : "Sie können diese %@ im Demo-Shop ausgeben, oder an eine
andere Wallet senden."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Puede gastar estos %@ en el comercio Demo, o enviarlos
a otra billetera."
+ }
}
}
},
@@ -3679,6 +5578,12 @@
"state" : "translated",
"value" : "Sie haben nicht genug %@."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "No tiene suficiente %@."
+ }
}
}
},
@@ -3690,6 +5595,12 @@
"state" : "translated",
"value" : "Sie müssen zuerst die Nutzungsbedingungen des
Zahlungsdienstes akzeptieren, bevor sie Elektronic-Cash in ihr Wallet bekommen
können."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Debe aceptar los Términos de Servicio del Proveedor de
Servicio de Pago antes de recibir dinero electrónico en su billetera."
+ }
}
}
},
@@ -3700,6 +5611,12 @@
"state" : "translated",
"value" : "Sie müssen zuerst die Nutzungsbedingungen des
Zahlungsdienstes akzeptieren, bevor sie Electronic-Cash in Ihr Wallet abheben
können."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Debe aceptar los Términos de Servicio del Proveedor de
Servicio de Pago antes de que pueda usarlo para extraer dinero electrónico en
su billetera."
+ }
}
}
},
@@ -3710,6 +5627,12 @@
"state" : "translated",
"value" : "Sie müssen zuerst die Nutzungsbedingungen des
Zahlungsdienstes akzeptieren."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Debe aceptar los Términos de Servicio del Servicio de
PAgo antes."
+ }
}
}
},
@@ -3720,6 +5643,12 @@
"state" : "translated",
"value" : "Sie müssen ein KYC-Verfahren durchlaufen"
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Necesita pasar un un procedimiento de KYC"
+ }
}
}
},
@@ -3736,6 +5665,12 @@
"state" : "new",
"value" : "You need to transfer %1$@ from your regular bank
account to the Payment Service Provider to receive %2$@ as electronic cash in
this wallet."
}
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Necesita transferir %1$@ desde una cuenta bancaria
regular al Proveedor de Servicio de Pago para recibir %2$@ en forma de dinero
electrónico."
+ }
}
}
}
diff --git a/TalerWallet1/Model/Model+Exchange.swift
b/TalerWallet1/Model/Model+Exchange.swift
index 717b971..b22432b 100644
--- a/TalerWallet1/Model/Model+Exchange.swift
+++ b/TalerWallet1/Model/Model+Exchange.swift
@@ -146,7 +146,9 @@ fileprivate struct AddExchange:
WalletBackendFormattedRequest {
/// A request to get info about a currency
fileprivate struct GetCurrencySpecification: WalletBackendFormattedRequest {
- typealias Response = CurrencySpecification2
+ struct Response: Codable, Sendable {
+ let currencySpecification: CurrencySpecification
+ }
func operation() -> String { "getCurrencySpecification" }
func args() -> Args { Args(scope: scope) }
diff --git a/TalerWallet1/Model/Model+Payment.swift
b/TalerWallet1/Model/Model+Payment.swift
index 3abb316..019b56c 100644
--- a/TalerWallet1/Model/Model+Payment.swift
+++ b/TalerWallet1/Model/Model+Payment.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 AnyCodable
@@ -163,7 +166,7 @@ struct TemplateParams: Codable {
let summary: String? // Human-readable short summary of
the contract
}
/// A request to get an exchange's payment contract terms.
-fileprivate struct PreparePayForTemplate: WalletBackendFormattedRequest {
+fileprivate struct PreparePayForTemplateRequest: WalletBackendFormattedRequest
{
typealias Response = PreparePayResult
func operation() -> String { "preparePayForTemplate" }
func args() -> Args { Args(talerPayTemplateUri: talerPayTemplateUri,
templateParams: templateParams) }
@@ -176,6 +179,52 @@ fileprivate struct PreparePayForTemplate:
WalletBackendFormattedRequest {
}
}
// MARK: -
+struct TemplateContractDetails: Codable {
+ let summary: String? // Human-readable short summary of
the contract. Fixed if this field exists, editable if nil
+ let currency: String?
+ let amount: Amount? // Total amount payable. Fixed if
this field exists, editable if nil
+ let minimumAge: Int
+ let payDuration: RelativeTime
+
+ enum CodingKeys: String, CodingKey {
+ case summary, currency, amount
+ case minimumAge = "minimum_age"
+ case payDuration = "pay_duration"
+ }
+}
+struct TemplateContractDetailsDefaults: Codable {
+ let summary: String? // Default 'Human-readable short
summary' if editable, or empty if nil.
+ let currency: String?
+ let amount: Amount? // Default amount if editable, or
unspecified if nil.
+}
+struct TalerMerchantTemplateDetails: Codable {
+ let templateContract: TemplateContractDetails
+ let editableDefaults: TemplateContractDetailsDefaults?
+// let requiredCurrency: String?
+ enum CodingKeys: String, CodingKey {
+ case templateContract = "template_contract"
+ case editableDefaults = "editable_defaults"
+// case requiredCurrency = "required_currency"
+ }
+}
+
+/// The result from checkPayForTemplate
+struct WalletTemplateDetails: Codable {
+ let templateDetails: TalerMerchantTemplateDetails
+ let supportedCurrencies: [String]
+}
+/// A request to get an exchange's payment contract terms.
+fileprivate struct CheckPayForTemplate: WalletBackendFormattedRequest {
+ typealias Response = WalletTemplateDetails
+ func operation() -> String { "checkPayForTemplate" }
+ func args() -> Args { Args(talerPayTemplateUri: talerPayTemplateUri) }
+
+ var talerPayTemplateUri: String
+ struct Args: Encodable {
+ var talerPayTemplateUri: String
+ }
+}
+// MARK: -
/// The result from confirmPayForUri
struct ConfirmPayResult: Decodable {
var type: String
@@ -204,18 +253,25 @@ extension WalletModel {
return response
}
@MainActor
+ func checkPayForTemplateM(_ talerPayTemplateUri: String, viewHandles: Bool
= false) // M for MainActor
+ async throws -> WalletTemplateDetails {
+ let request = CheckPayForTemplate(talerPayTemplateUri:
talerPayTemplateUri)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ return response
+ }
+ @MainActor
func preparePayForTemplateM(_ talerPayTemplateUri: String, amount:
Amount?, summary: String?, viewHandles: Bool = false) // M for MainActor
- async throws -> PreparePayResult {
+ async throws -> PreparePayResult {
let templateParams = TemplateParams(amount: amount, summary: summary)
- let request = PreparePayForTemplate(talerPayTemplateUri:
talerPayTemplateUri, templateParams: templateParams)
+ let request = PreparePayForTemplateRequest(talerPayTemplateUri:
talerPayTemplateUri, templateParams: templateParams)
let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
return response
}
@MainActor
func confirmPayM(_ transactionId: String, viewHandles: Bool = false)
// M for MainActor
async throws -> ConfirmPayResult {
- let request = confirmPayForUri(transactionId: transactionId)
- let response = try await sendRequest(request, ASYNCDELAY,
viewHandles: viewHandles)
- return response
+ let request = confirmPayForUri(transactionId: transactionId)
+ let response = try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ return response
}
}
diff --git a/TalerWallet1/Model/Model+Withdraw.swift
b/TalerWallet1/Model/Model+Withdraw.swift
index 7aa2488..95caaa9 100644
--- a/TalerWallet1/Model/Model+Withdraw.swift
+++ b/TalerWallet1/Model/Model+Withdraw.swift
@@ -46,8 +46,9 @@ struct WithdrawalExchangeAccountDetails: Decodable {
// MARK: -
/// The result from getWithdrawalDetailsForUri
struct WithdrawUriInfoResponse: Decodable {
- var amount: Amount
- var defaultExchangeBaseUrl: String?
+ var amount: Amount? // if nil then ask User
+ var currency: String // use this if amount=nil
+ var defaultExchangeBaseUrl: String? // if nil then use
possibleExchanges
var possibleExchanges: [Exchange] // TODO: query these for fees?
}
/// A request to get an exchange's withdrawal details.
diff --git a/TalerWallet1/Model/Transaction.swift
b/TalerWallet1/Model/Transaction.swift
index 956d7ed..ddc1a4d 100644
--- a/TalerWallet1/Model/Transaction.swift
+++ b/TalerWallet1/Model/Transaction.swift
@@ -22,9 +22,9 @@ enum TransactionMinorState: String, Codable {
// Placeholder until D37 is fully implemented
case unknown
case deposit
- case kyc // KycRequired
case aml // AmlRequired
- case mergeKycRequired = "merge-kyc"
+ case kyc // KycRequired
+ case mergeKycRequired = "merge-kyc" // same as KYC but for P2P
case track
case submitPayment = "submit-payment"
case rebindSession = "rebind-session"
@@ -59,9 +59,8 @@ enum TransactionMinorState: String, Codable {
switch self {
case .unknown: return self.rawValue
case .deposit: return self.rawValue
- case .kyc: return String(localized:
"MinorState.kyc", defaultValue: "KYC required", comment: "TxMinorState heading")
+ case .kyc, .mergeKycRequired: return String(localized:
"MinorState.kyc", defaultValue: "KYC required", comment: "TxMinorState heading")
case .aml: return String(localized:
"MinorState.aml", defaultValue: "AML required", comment: "TxMinorState heading")
- case .mergeKycRequired: return String(localized:
"MinorState.mergekyc", defaultValue: "KYC required", comment: "TxMinorState
heading")
case .track: return self.rawValue
case .submitPayment: return self.rawValue
case .rebindSession: return self.rawValue
diff --git a/TalerWallet1/Model/WalletModel.swift
b/TalerWallet1/Model/WalletModel.swift
index 9e48f44..8aaa1e2 100644
--- a/TalerWallet1/Model/WalletModel.swift
+++ b/TalerWallet1/Model/WalletModel.swift
@@ -67,17 +67,26 @@ class WalletModel: ObservableObject {
throw error
}
}
+}
+// MARK: -
+/// A request to tell wallet-core about the network.
+fileprivate struct NetworkAvailabilityRequest: WalletBackendFormattedRequest {
+ struct Response: Decodable {}
+ func operation() -> String { "hintNetworkAvailability" }
+ func args() -> Args { Args(isNetworkAvailable: isNetworkAvailable) }
- func getTransactionByIdT(_ transactionId: String, viewHandles: Bool =
false)
- async throws -> Transaction { // T for any Thread
- // might be called from a background thread itself
- let request = GetTransactionById(transactionId: transactionId)
- return try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ var isNetworkAvailable: Bool
+
+ struct Args: Encodable {
+ var isNetworkAvailable: Bool
}
- /// get the specified transaction from Wallet-Core. No networking involved
- @MainActor func getTransactionByIdM(_ transactionId: String, viewHandles:
Bool = false)
- async throws -> Transaction { // M for MainActor
- return try await getTransactionByIdT(transactionId, viewHandles:
viewHandles) // call GetTransactionById on main thread
+}
+
+extension WalletModel {
+ func hintNetworkAvailabilityT(_ isNetworkAvailable: Bool = false) async {
+ // T for any Thread
+ let request = NetworkAvailabilityRequest(isNetworkAvailable:
isNetworkAvailable)
+ _ = try? await sendRequest(request, 0)
}
}
// MARK: -
@@ -93,6 +102,20 @@ fileprivate struct GetTransactionById:
WalletBackendFormattedRequest {
var transactionId: String
}
}
+
+extension WalletModel {
+ func getTransactionByIdT(_ transactionId: String, viewHandles: Bool =
false)
+ async throws -> Transaction { // T for any Thread
+ // might be called from a background thread itself
+ let request = GetTransactionById(transactionId: transactionId)
+ return try await sendRequest(request, ASYNCDELAY, viewHandles:
viewHandles)
+ }
+ /// get the specified transaction from Wallet-Core. No networking involved
+ @MainActor func getTransactionByIdM(_ transactionId: String, viewHandles:
Bool = false)
+ async throws -> Transaction { // M for MainActor
+ return try await getTransactionByIdT(transactionId, viewHandles:
viewHandles) // call GetTransactionById on main thread
+ }
+}
// MARK: -
/// The info returned from Wallet-core init
struct VersionInfo: Decodable {
@@ -257,7 +280,6 @@ extension WalletModel {
}
}
// MARK: -
-
fileprivate struct DevExperimentRequest: WalletBackendFormattedRequest {
func operation() -> String { "applyDevExperiment" }
func args() -> Args { Args(devExperimentUri: talerUri) }
@@ -278,4 +300,3 @@ extension WalletModel {
_ = try await sendRequest(request, 0, viewHandles: viewHandles)
}
}
-
diff --git a/TalerWallet1/Quickjs/QuickDataTask.swift
b/TalerWallet1/Quickjs/QuickDataTask.swift
index 4334e88..15036f4 100644
--- a/TalerWallet1/Quickjs/QuickDataTask.swift
+++ b/TalerWallet1/Quickjs/QuickDataTask.swift
@@ -134,19 +134,23 @@ class QuickDataTask: NSObject {
let responseInfoPtr =
UnsafeMutablePointer<JSHttpResponseInfo>(&responseInfo)
responseCb(responseCbCls, responseInfoPtr)
}
- } else { // TODO: pass error to walletCore
- 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)
+ } else { // pass error to walletCore
+ Task.detached {
+ var errmsg = "No http response from \(url)"
+ logger.error("⁉️ \(self.requestID, privacy: .public)
\(method, privacy: .public) \(error, privacy: .public) \(errmsg, privacy:
.public)")
+ await
WalletModel.shared.hintNetworkAvailabilityT(false)
+ Controller.shared.checkInternetConnection() //
TODO: pass error to walletCore
+ 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
}
diff --git a/TalerWallet1/Quickjs/quickjs.swift
b/TalerWallet1/Quickjs/quickjs.swift
index 19fe572..a62b63e 100644
--- a/TalerWallet1/Quickjs/quickjs.swift
+++ b/TalerWallet1/Quickjs/quickjs.swift
@@ -52,8 +52,8 @@ public class Quickjs { // acts as singleton, since only
one instance ever e
public weak var messageHandler: QuickjsMessageHandler?
var logger: Logger
- @Atomic(default: 0)
- private var lastRequestID: Int32
+ @Atomic(default: 0)
// boilerPlate around NSLock…
+ private var lastRequestID: Int32
// …to safeguard increments
private var requests: [Int32: QuickDataTask] = [:]
private lazy var urlSession: URLSession = {
@@ -84,7 +84,7 @@ public class Quickjs { // acts as singleton, since only
one instance ever e
func reqCreate(_ request: URLRequest,
_ responseCb: JSHttpResponseCb?,
_ responseCbCls: Optional<UnsafeMutableRawPointer>) -> Int32 {
- let requestID = $lastRequestID.atomicIncrement()
+ let requestID = $lastRequestID.atomicIncrement()
// ensure requestID is unique
let quickDataTask = QuickDataTask(urlSession: urlSession,
request: request,
requestID: requestID,
diff --git a/TalerWallet1/Taler_Wallet InfoPlist.xcstrings
b/TalerWallet1/Taler_Wallet InfoPlist.xcstrings
new file mode 100644
index 0000000..25d82e2
--- /dev/null
+++ b/TalerWallet1/Taler_Wallet InfoPlist.xcstrings
@@ -0,0 +1,78 @@
+{
+ "sourceLanguage" : "en",
+ "strings" : {
+ "CFBundleDisplayName" : {
+ "comment" : "Bundle display name",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Taler Wallet"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Taler Wallet"
+ }
+ }
+ }
+ },
+ "CFBundleName" : {
+ "comment" : "Bundle name",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Taler_Wallet"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Taler_Wallet"
+ }
+ }
+ }
+ },
+ "NSCameraUsageDescription" : {
+ "comment" : "Privacy - Camera Usage Description",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Scan QR Codes"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Escanear códigos QR"
+ }
+ }
+ }
+ },
+ "NSHumanReadableCopyright" : {
+ "comment" : "Copyright (human-readable)",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "© Taler-Systems.com"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "© Taler-Systems.com"
+ }
+ }
+ }
+ }
+ },
+ "version" : "1.0"
+}
\ No newline at end of file
diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift
b/TalerWallet1/Views/Balances/BalancesListView.swift
index 804edf2..2f3e40a 100644
--- a/TalerWallet1/Views/Balances/BalancesListView.swift
+++ b/TalerWallet1/Views/Balances/BalancesListView.swift
@@ -13,6 +13,7 @@ struct BalancesListView: View {
let stack: CallStack
let navTitle: String
@Binding var balances: [Balance]
+// @Binding var shouldReloadPending: Int
@Binding var shouldReloadBalances: Int
@EnvironmentObject private var model: WalletModel
@@ -100,6 +101,7 @@ struct BalancesListView: View {
#endif
Content(symLog: symLog, stack: stack.push(), balances: $balances,
amountToTransfer: $amountToTransfer, summary: $summary,
+// shouldReloadPending: $shouldReloadPending,
shouldReloadBalances: $shouldReloadBalances,
reloadBalances: reloadBalances)
.navigationTitle(navTitle)
@@ -110,7 +112,7 @@ struct BalancesListView: View {
dismissAlertButton },
message: { Text("Please allow camera access in
settings.") })
.sheet(isPresented: $showQRScanner, onDismiss: dismissingSheet) {
- let sheet = AnyView(QRSheet(stack: stack.push()))
+ let sheet = AnyView(QRSheet(stack: stack.push(".sheet")))
Sheet(sheetView: sheet)
} // sheet
.task(id: shouldReloadBalances) {
@@ -130,6 +132,7 @@ extension BalancesListView {
@Binding var balances: [Balance]
@Binding var amountToTransfer: Amount
@Binding var summary: String
+// @Binding var shouldReloadPending: Int
@Binding var shouldReloadBalances: Int
var reloadBalances: (_ stack: CallStack, _ invalidateCache: Bool)
async -> Int?
diff --git a/TalerWallet1/Views/Balances/PendingRowView.swift
b/TalerWallet1/Views/Balances/PendingRowView.swift
index f8411ed..3601e12 100644
--- a/TalerWallet1/Views/Balances/PendingRowView.swift
+++ b/TalerWallet1/Views/Balances/PendingRowView.swift
@@ -18,12 +18,12 @@ struct PendingRowView: View {
let inTitle0 = String(localized: "TitleIncoming_Short", defaultValue:
"Incoming",
comment: "Abbreviation of `Pending incoming´ in
Balances")
let inTitle1 = String(localized: "TitleIncoming_Full", defaultValue:
"Pending\tincoming",
- comment: "`Pending incoming´ in Balances - set
exactly 1 \t for line break")
+ comment: "`Pending incoming´ in Balances - set
exactly 1 \\t for line break")
let outTitle0 = String(localized: "TitleOutgoing_Short", defaultValue:
"Outgoing",
comment: "Abbreviation of `Pending outgoing´ in
Balances")
let outTitle1 = String(localized: "TitleOutgoing_Full", defaultValue:
"Pending\toutgoing",
- comment: "`Pending outgoing´ in Balances - set
exactly 1 \t for line break")
+ comment: "`Pending outgoing´ in Balances - set
exactly 1 \\t for line break")
var body: some View {
let pendingColor = WalletColors().pendingColor(incoming)
diff --git a/TalerWallet1/Views/Banking/DepositAmountV.swift
b/TalerWallet1/Views/Banking/DepositAmountV.swift
index 0884295..8f36830 100644
--- a/TalerWallet1/Views/Banking/DepositAmountV.swift
+++ b/TalerWallet1/Views/Banking/DepositAmountV.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
@@ -44,8 +47,6 @@ struct DepositAmountV: View {
feeAmount = nil
return feeAmount
}
-
- var feeLabel: String { feeStr.count > 0 ? String(localized: "+ \(feeStr)
fee") : EMPTYSTRING }
private func feeIsNotZero() -> Bool? {
if let hasNoFees = exchange?.noFees {
@@ -109,9 +110,9 @@ struct DepositAmountV: View {
title: minimalistic ? String(localized:
"Amount:")
: String(localized:
"Amount to deposit:"),
shortcutAction: nil)
-// .padding(.top)
+
Text(insufficient ? insufficientLabel
- : feeLabel)
+ : feeLabel(feeStr))
.talerFont(.body)
.foregroundColor(insufficient ? .red
: (feeAmount?.isZero ??
true) ? WalletColors().secondary(colorScheme, colorSchemeContrast)
@@ -157,7 +158,7 @@ struct DepositAmountV: View {
}
if insufficient {
- announce(this: "\(amountVoiceOver),
\(insufficientLabel2)")
+ announce("\(amountVoiceOver), \(insufficientLabel2)")
feeStr = EMPTYSTRING
}
}
@@ -167,11 +168,15 @@ struct DepositAmountV: View {
prepareDepositResult = nil
} else if let paytoUri {
if let ppCheck = try? await
model.prepareDepositM(paytoUri, amount: amountToTransfer) {
- prepareDepositResult = ppCheck
- if let feeAmount = fee(ppCheck:
prepareDepositResult) {
+ if let feeAmount = fee(ppCheck: ppCheck) {
feeStr = feeAmount.string(currencyInfo)
- } else { feeStr = EMPTYSTRING }
- announce(this: "\(amountVoiceOver), \(feeLabel)")
+ let feeLabel = feeLabel(feeStr)
+ announce("\(amountVoiceOver), \(feeLabel)")
+ } else {
+ feeStr = EMPTYSTRING
+ announce(amountVoiceOver)
+ }
+ prepareDepositResult = ppCheck
} else {
prepareDepositResult = nil
}
diff --git a/TalerWallet1/Views/Banking/ExchangeListView.swift
b/TalerWallet1/Views/Banking/ExchangeListView.swift
index 6191730..e6c6e45 100644
--- a/TalerWallet1/Views/Banking/ExchangeListView.swift
+++ b/TalerWallet1/Views/Banking/ExchangeListView.swift
@@ -26,14 +26,14 @@ struct ExchangeListView: View {
symLog.log("adding: \(exchange)")
if let _ = try? await model.addExchange(url: exchange) {
symLog.log("added: \(exchange)")
- announce(this: "added: \(exchange)")
+ announce("added: \(exchange)")
}
}
}
var body: some View {
- let accessibilityLabelStr = String(localized: "Add Payment Service",
comment: "accessibilityLabel for the + button")
- let plusButton = PlusButton(accessibilityLabelStr:
accessibilityLabelStr) {
+ let a11yLabelStr = String(localized: "Add Payment Service", comment:
"VoiceOver for the + button")
+ let plusButton = PlusButton(accessibilityLabelStr: a11yLabelStr) {
showAlert = true
}
let addTitleStr = String(localized: "Add Payment Service", comment:
"title of the addExchange alert")
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift
b/TalerWallet1/Views/HelperViews/AmountInputV.swift
index 4ebb3e8..cc6ae64 100644
--- a/TalerWallet1/Views/HelperViews/AmountInputV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountInputV.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
@@ -14,10 +17,10 @@ struct AmountInputV: View {
let amountAvailable: Amount? // TODO:
GetMaxPeerPushAmount
@Binding var amountToTransfer: Amount
let amountLabel: String
- let wantsSummary: Bool // if true we call
SubjectInputV next
+ let summaryIsEditable: Bool // if true we call
SubjectInputV next
@Binding var summary: String
- @Binding var insufficient: Bool
- @Binding var feeAmount: Amount?
+// @Binding var insufficient: Bool
+// @Binding var feeAmount: Amount?
let shortcutAction: ((_ amount: Amount) -> Void)?
let buttonAction: () -> Void
@@ -29,24 +32,22 @@ struct AmountInputV: View {
@State private var preparePayResult: PreparePayResult? = nil
@State private var feeStr: String = EMPTYSTRING
- var feeLabel: String { feeStr.count > 0 ? String(localized: "+ \(feeStr)
fee") : EMPTYSTRING }
+ struct Flags {
+ let insufficient: Bool
+ let disabled: Bool
+ }
- func preparePayForTemplate() async {
- if let url {
- if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary) {
- let amount = ppCheck.amountRaw
- let currency = amount.currencyStr
- let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
- insufficient = ppCheck.status == .insufficientBalance
- feeAmount = templateFee(ppCheck: ppCheck)
- if let feeAmount {
- feeStr = feeAmount.string(currencyInfo)
- } else { feeStr = EMPTYSTRING }
- let amountVoiceOver = amount.string(currencyInfo)
- announce(this: "\(amountVoiceOver), \(feeLabel)")
- preparePayResult = ppCheck
+ func checkAvailable(amount: Amount) -> Flags {
+ if let amountAvailable {
+ do {
+ let insufficient = try amountAvailable > amount
+ let disabled = insufficient || amount.isZero
+ return Flags(insufficient: insufficient, disabled: disabled)
+ } catch {
+ // TODO: error Amounts don't match
}
}
+ return Flags(insufficient: false, disabled: amount.isZero)
}
var body: some View {
@@ -54,58 +55,60 @@ struct AmountInputV: View {
let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
let insufficientLabel = String(localized: "You don't have enough
\(currency).")
let available = amountAvailable?.string(currencyInfo) ?? nil
- let disabled = insufficient || amountToTransfer.isZero
- VStack(alignment: .trailing) {
+ let flags = checkAvailable(amount: amountToTransfer)
+ ScrollView { VStack(alignment: .trailing) {
if let available {
Text("Available:\t\(available)")
.talerFont(.title3)
.padding(.bottom, 2)
- // .accessibility(sortPriority: 3)
+// .accessibility(sortPriority: 3)
}
CurrencyInputView(amount: $amountToTransfer,
available: amountAvailable,
title: amountLabel,
shortcutAction: shortcutAction)
// .accessibility(sortPriority: 2)
- Text(insufficient ? insufficientLabel
- : feeLabel)
- .talerFont(.body)
- .foregroundColor(insufficient ? .red
- : (feeAmount?.isZero ?? true) ?
WalletColors().secondary(colorScheme, colorSchemeContrast)
- : .red)
-// .accessibility(sortPriority: 1)
- .padding(4)
- Group {
- if let url {
- let destination = LazyView {
- PaymentView(stack: stack.push(),
- url: url,
- template: true,
- amountToTransfer: $amountToTransfer,
- summary: $summary)
- }
- NavigationLink(destination: destination) {
- Text("Next")
- }
- .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
- .disabled(disabled)
- } else {
- Button("Next") {
- buttonAction()
- }
- .buttonStyle(TalerButtonStyle(type: .prominent,
disabled: disabled))
- .disabled(disabled)
- }
- }
-// .accessibility(sortPriority: 0)
- .task(id: amountToTransfer.value) {
- symLog.log(".task")
- await preparePayForTemplate()
- }
- }.padding(.horizontal)
- .onAppear() {
- // symLog.log("onAppear")
- DebugViewC.shared.setSheetID(SHEET_PAY_TEMPL_AMOUNT)
+ if flags.insufficient {
+ Text(insufficientLabel)
+ .talerFont(.body)
+ .foregroundColor(.red)
+ .padding(4)
+// } else {
+// Text(feeLabel(feeStr))
+// .talerFont(.body)
+// .foregroundColor((feeAmount?.isZero ?? true) ?
WalletColors().secondary(colorScheme, colorSchemeContrast)
+// : .red)
+// .padding(4)
+// .accessibility(sortPriority: 1)
}
+ Button("Next") { buttonAction() }
+ .buttonStyle(TalerButtonStyle(type: .prominent, disabled:
flags.disabled))
+ .disabled(flags.disabled)
+ }.padding(.horizontal) } // ScrollVStack
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+ .onAppear() {
+// symLog.log("onAppear")
+ DebugViewC.shared.setSheetID(SHEET_PAY_TEMPL_AMOUNT)
+ }
+// .task(id: amountToTransfer.value) {
+// if let url {
+// symLog.log(".task preparePayForTemplate")
+// if let result = await preparePayForTemplate(model: model,
+// url: url,
+// amount:
amountToTransfer,
+// summary:
summaryIsEditable ? summary ?? " "
+//
: nil,
+// announce: announce)
+// { symLog.log("preparePayForTemplate finished")
+// insufficient = result.insufficient
+// feeAmount = result.feeAmount
+// feeStr = result.feeStr
+// preparePayResult = result.ppCheck
+// } else {
+// symLog.log("preparePayForTemplateM failed")
+// }
+// }
+// }
}
}
diff --git a/TalerWallet1/Views/HelperViews/AmountV.swift
b/TalerWallet1/Views/HelperViews/AmountV.swift
index f2bd5be..1e29c64 100644
--- a/TalerWallet1/Views/HelperViews/AmountV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountV.swift
@@ -11,15 +11,8 @@ struct AmountV: View {
@EnvironmentObject private var controller: Controller
- var amountStr: String {
- if let currencyInfo = controller.info(for: amount.currencyStr) {
- return amount.string(currencyInfo)
- }
- return amount.readableDescription
- }
-
var body: some View {
- Text(amountStr)
+ Text(amount.string())
.multilineTextAlignment(.center)
.talerFont(large ? .title : .title2)
// .fontWeight(large ? .medium : .regular) // @available(iOS
16.0, *)
diff --git a/TalerWallet1/Views/HelperViews/LaunchAnimationView.swift
b/TalerWallet1/Views/HelperViews/LaunchAnimationView.swift
index 5a4cf84..4210aaa 100644
--- a/TalerWallet1/Views/HelperViews/LaunchAnimationView.swift
+++ b/TalerWallet1/Views/HelperViews/LaunchAnimationView.swift
@@ -38,7 +38,8 @@ struct RotatingTaler: View {
.scaledToFit()
.frame(width: size, height: size)
.rotationEffect(rotationDirection ? Angle(degrees: 0) :
Angle(degrees: 900))
- .accessibilityLabel(progress ? "In progress" : "Taler Logo")
// decorative logo - with button function
+ .accessibilityLabel(progress ? Text("In progress", comment:
"VoiceOver")
+ : Text("Taler Logo", comment:
"VoiceOver")) // decorative logo - with button function
.onReceive(animationTimer) { timerValue in
if rotationEnabled {
withAnimation(.easeInOut(duration: 1.9)) {
diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
index 44796f2..fa46b83 100644
--- a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
+++ b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
@@ -15,13 +15,6 @@ struct QRCodeDetailView: View {
@EnvironmentObject private var controller: Controller
@AppStorage("minimalistic") var minimalistic: Bool = false
- var amountStr: String {
- if let currencyInfo = controller.info(for: amount.currencyStr) {
- return amount.string(currencyInfo)
- }
- return amount.readableDescription
- }
-
var body: some View {
if talerURI.count > 10 {
Section {
@@ -58,6 +51,7 @@ struct QRCodeDetailView: View {
.accessibilityLabel("QR Code")
.listRowSeparator(.hidden)
+ let amountStr = amount.string()
let scanMini = incoming ? String(localized: "Either (payer)
Mini 3",
defaultValue: "to pay
\(amountStr).", comment: "e.g. '5,3 €'")
: String(localized: "Either (payee)
Mini 3",
diff --git a/TalerWallet1/Views/HelperViews/SubjectInputV.swift
b/TalerWallet1/Views/HelperViews/SubjectInputV.swift
index df64493..5357ba2 100644
--- a/TalerWallet1/Views/HelperViews/SubjectInputV.swift
+++ b/TalerWallet1/Views/HelperViews/SubjectInputV.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
@@ -15,8 +18,8 @@ struct SubjectInputV<TargetView: View>: View {
@Binding var amountToTransfer: Amount
let amountLabel: String
@Binding var summary: String
- @Binding var insufficient: Bool
- @Binding var feeAmount: Amount?
+// @Binding var insufficient: Bool
+// @Binding var feeAmount: Amount?
let feeIsNotZero: Bool? // nil = no fees at all, false = no
fee for this tx
let currencyInfo: CurrencyInfo
@@ -30,37 +33,21 @@ struct SubjectInputV<TargetView: View>: View {
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
@AppStorage("minimalistic") var minimalistic: Bool = false
+ let navTitle = String(localized: "Custom Summary", comment:"pay merchant")
+
@State private var preparePayResult: PreparePayResult? = nil
- @State private var feeStr: String = EMPTYSTRING
@FocusState private var isFocused: Bool
- var feeLabel: String { feeStr.count > 0 ? String(localized: "+ \(feeStr)
fee") : EMPTYSTRING }
-
- func preparePayForTemplate() async {
- if let url {
- if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary) {
- let amount = ppCheck.amountRaw
- let currency = amount.currencyStr
- let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
- insufficient = ppCheck.status == .insufficientBalance
- feeAmount = templateFee(ppCheck: ppCheck)
- if let feeAmount {
- feeStr = feeAmount.string(currencyInfo)
- } else { feeStr = EMPTYSTRING }
- let amountVoiceOver = amount.string(currencyInfo)
- announce(this: "\(amountVoiceOver), \(feeLabel)")
- preparePayResult = ppCheck
- }
- }
- }
-
var body: some View {
let currency = amountToTransfer.currencyStr
- let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
- let insufficientLabel = String(localized: "You don't have enough
\(currency).")
+// let feeStr = feeAmount?.string(currencyInfo) ?? EMPTYSTRING
+// let insufficientLabel = String(localized: "You don't have enough
\(currency).")
+// let feeLabel = insufficient ? insufficientLabel
+// : feeLabel(feeStr)
let available = amountAvailable?.string(currencyInfo) ?? nil
- let disabled = insufficient || summary.count == 0
- VStack(alignment: .leading) {
+// let disabled = insufficient || summary.count == 0
+ let disabled = summary.count == 0
+ ScrollView { VStack(alignment: .leading) {
if let available {
Text("Available:\t\(available)")
.talerFont(.title3)
@@ -97,22 +84,31 @@ struct SubjectInputV<TargetView: View>: View {
}
}
}
-
- let subLabel = insufficient ? insufficientLabel
- : feeLabel
- Text(subLabel)
+ HStack {
+ Text(amountToTransfer.string(currencyInfo))
+ // TODO: hasFees?
+// Text(feeLabel)
+ }
.talerFont(.body)
- .foregroundColor(insufficient ? .red
- : (feeAmount?.isZero ?? true) ?
WalletColors().secondary(colorScheme, colorSchemeContrast)
- : .red)
- // .accessibility(sortPriority: 1)
+// .foregroundColor(insufficient ? .red :
WalletColors().secondary(colorScheme, colorSchemeContrast))
+ .foregroundColor(WalletColors().secondary(colorScheme,
colorSchemeContrast))
+// .accessibility(sortPriority: 1)
.padding(4)
+// if insufficient {
+// Text(insufficientLabel)
+// .talerFont(.body)
+// .foregroundColor(.red)
+// .padding(4)
+// }
NavigationLink("Next", destination: targetView)
.buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
// .accessibility(sortPriority: 0)
- }.padding(.horizontal)
+ }.padding(.horizontal) } // ScrollVStack
+ .navigationTitle(navTitle)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
.onAppear() {
// symLog.log("onAppear")
DebugViewC.shared.setSheetID(SHEET_PAY_TEMPL_SUBJECT)
diff --git a/TalerWallet1/Views/HelperViews/View+fitsSideBySide.swift
b/TalerWallet1/Views/HelperViews/View+fitsSideBySide.swift
index baecf5a..cbfd0c5 100644
--- a/TalerWallet1/Views/HelperViews/View+fitsSideBySide.swift
+++ b/TalerWallet1/Views/HelperViews/View+fitsSideBySide.swift
@@ -7,7 +7,7 @@ import UIKit
extension View {
@MainActor
- public func announce(this: String) {
+ public func announce(_ this: String) {
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .announcement, argument: this)
}
diff --git a/TalerWallet1/Views/Main/MainView.swift
b/TalerWallet1/Views/Main/MainView.swift
index 3c3bced..d70b292 100644
--- a/TalerWallet1/Views/Main/MainView.swift
+++ b/TalerWallet1/Views/Main/MainView.swift
@@ -121,6 +121,7 @@ extension MainView {
@EnvironmentObject private var viewState2: ViewState2 //
popToRootView()
@State private var shouldReloadBalances = 0
+ @State private var shouldReloadPending = 0
@State private var balances: [Balance] = []
@State private var selectedTab: Tab = .balances
@State private var showKycAlert: Bool = false
@@ -193,6 +194,7 @@ extension MainView {
BalancesListView(stack: stack.push(balancesTitle),
navTitle: balancesTitle,
balances: $balances,
+// shouldReloadPending: $shouldReloadPending,
shouldReloadBalances: $shouldReloadBalances)
}.id(viewState.rootViewId) // any change to
rootViewId triggers popToRootView behaviour
.navigationViewStyle(.stack)
@@ -255,14 +257,19 @@ extension MainView {
shouldReloadBalances += 1
}
.onNotification(.TransactionExpired) { notification in
- // reload balances on receiving BalanceChange notification ...
+ // reload balances on receiving TransactionExpired
notification ...
logger.info(".onNotification(.TransactionExpired) ==> reload")
shouldReloadBalances += 1
+ shouldReloadPending += 1
}
.onNotification(.TransactionDone) {
shouldReloadBalances += 1
+ shouldReloadPending += 1
selectedTab = .balances
}
+ .onNotification(.TransactionError) { notification in
+ shouldReloadPending += 1
+ }
.onNotification(.Error) { notification in
if let error = notification.userInfo?[NOTIFICATIONERROR] as?
Error {
model.setError(error)
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift
b/TalerWallet1/Views/Peer2peer/SendAmount.swift
index ab2dac3..af727a0 100644
--- a/TalerWallet1/Views/Peer2peer/SendAmount.swift
+++ b/TalerWallet1/Views/Peer2peer/SendAmount.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
@@ -43,8 +46,6 @@ struct SendAmount: View {
feeAmount = nil
return feeAmount
}
-
- var feeLabel: String { feeStr.count > 0 ? String(localized: "+ \(feeStr)
fee") : EMPTYSTRING }
private func shortcutAction(_ shortcut: Amount) {
amountShortcut = shortcut
@@ -82,11 +83,11 @@ struct SendAmount: View {
let inputDestination = LazyView {
P2PSubjectV(stack: stack.push(),
- feeLabel: feeLabel,
+ feeLabel: feeLabel(feeStr),
feeIsNotZero: feeIsNotZero(),
currencyInfo: currencyInfo,
amountToSend: true,
- amountToTransfer: $amountToTransfer,
+ amountToTransfer: $amountToTransfer, // from the textedit
summary: $summary,
expireDays: $expireDays)
}
@@ -96,20 +97,22 @@ struct SendAmount: View {
feeIsNotZero: feeIsNotZero(),
currencyInfo: currencyInfo,
amountToSend: true,
- amountToTransfer: $amountShortcut,
+ amountToTransfer: $amountShortcut, // from the tapped
shortcut button
summary: $summary,
expireDays: $expireDays)
}
ScrollView {
+ let amountLabel = minimalistic ? String(localized: "Amount:")
+ : String(localized: "Amount to
send:")
+
AmountInputV(stack: stack.push(), url: nil,
amountAvailable: amountAvailable,
amountToTransfer: $amountToTransfer,
- amountLabel: minimalistic ? String(localized: "Amount:")
- : String(localized: "Amount to
send:"),
- wantsSummary: true,
+ amountLabel: amountLabel,
+ summaryIsEditable: true,
summary: $summary,
- insufficient: $insufficient,
- feeAmount: $feeAmount,
+// insufficient: $insufficient,
+// feeAmount: $feeAmount,
shortcutAction: shortcutAction,
buttonAction: buttonAction)
.background(NavigationLink(destination: shortcutDestination,
isActive: $shortcutSelected)
@@ -144,18 +147,22 @@ struct SendAmount: View {
}
if insufficient {
- announce(this: "\(amountVoiceOver), \(insufficientLabel2)")
+ announce("\(amountVoiceOver), \(insufficientLabel2)")
} else if amountToTransfer.isZero {
feeStr = EMPTYSTRING
} else {
if let ppCheck = try? await
model.checkPeerPushDebitM(amountToTransfer) {
- peerPushCheck = ppCheck
// TODO: set from exchange
// agePicker.setAges(ages: peerPushCheck?.ageRestrictionOptions)
- if let feeAmount = fee(ppCheck: peerPushCheck) {
+ if let feeAmount = fee(ppCheck: ppCheck) {
feeStr = feeAmount.string(currencyInfo)
- } else { feeStr = EMPTYSTRING }
- announce(this: "\(amountVoiceOver), \(feeLabel)")
+ let feeLabel = feeLabel(feeStr)
+ announce("\(amountVoiceOver), \(feeLabel)")
+ } else {
+ feeStr = EMPTYSTRING
+ announce(amountVoiceOver)
+ }
+ peerPushCheck = ppCheck
} else {
peerPushCheck = nil
}
diff --git a/TalerWallet1/Views/Settings/AboutView.swift
b/TalerWallet1/Views/Settings/AboutView.swift
index 2a4965a..a01271e 100644
--- a/TalerWallet1/Views/Settings/AboutView.swift
+++ b/TalerWallet1/Views/Settings/AboutView.swift
@@ -35,10 +35,9 @@ struct AboutView: View {
let walletCore = WalletCore.shared
Group {
List {
- RotatingTaler(size: 100, progress: false,
- rotationEnabled: $rotationEnabled)
- .frame(maxWidth: .infinity, alignment: .center)
-// .accessibilityLabel("Progress indicator")
+ RotatingTaler(size: 100, progress: false, rotationEnabled:
$rotationEnabled)
+ // has its own accessibilityLabel
+ .frame(maxWidth: .infinity, alignment: .center)
.onTapGesture(count: 1) { rotationEnabled.toggle() }
SettingsItem(name: String(localized: "Visit the taler.net
website"), id1: "web",
description: minimalistic ? nil :
String(localized: "More info about GNU Taler in general...")) { }
diff --git a/TalerWallet1/Views/Settings/SettingsView.swift
b/TalerWallet1/Views/Settings/SettingsView.swift
index 3c456a2..86ad303 100644
--- a/TalerWallet1/Views/Settings/SettingsView.swift
+++ b/TalerWallet1/Views/Settings/SettingsView.swift
@@ -154,12 +154,12 @@ struct SettingsView: View {
}
#if DEBUG
if showDevelopItems {
- Text(verbatim: "https://bank.taler.grothoff.org/")
- Text(verbatim: "https://bank.regio-taler.fdold.eu/")
- Text(verbatim: "https://bank.head.taler.net/")
- Text(verbatim: "https://bank.test.taler.net/")
- Text(verbatim: "https://bank.demo.taler.net/")
- Text(verbatim: "https://bank.taler.ar/")
+ let banks = ["taler.grothoff.org",
"regio-taler.fdold.eu", "taler.ar",
+ "head.taler.net", "demo.taler.net",
"test.taler.net"]
+ ForEach(banks, id: \.self) { bank in
+ let urlStr = "https://bank." + bank
+ Link(bank, destination: URL(string: urlStr)!)
+ }
}
#endif
if showDevelopItems { // show or hide the following items
diff --git a/TalerWallet1/Views/Sheets/ErrorSheet.swift
b/TalerWallet1/Views/Sheets/ErrorSheet.swift
index 2953d2d..49ecdff 100644
--- a/TalerWallet1/Views/Sheets/ErrorSheet.swift
+++ b/TalerWallet1/Views/Sheets/ErrorSheet.swift
@@ -9,8 +9,8 @@ import SwiftUI
import taler_swift
enum ErrorData {
-case message(title: String, message: String)
-case error(Error)
+ case message(title: String, message: String)
+ case error(Error)
}
struct ErrorSheet: View {
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
index fed0b41..9d945e1 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift
@@ -11,7 +11,7 @@ import SymLog
struct P2pPayURIView: View {
private let symLog = SymLogV(0)
let stack: CallStack
- let navTitle = String(localized: "Pay P2P")
+ let navTitle = String(localized: "Pay P2P", comment: "Nav Title")
// the scanned URL
let url: URL
@@ -41,16 +41,16 @@ struct P2pPayURIView: View {
large: false, pending: false, incoming:
false,
baseURL: nil,
noFees: nil, // TODO: check baseURL
for fees
- status: nil,
+ txStateLcl: nil,
summary:
peerPullDebitResponse.contractTerms.summary,
merchant: nil)
let expiration =
peerPullDebitResponse.contractTerms.purse_expiration
let (dateString, date) = TalerDater.dateString(from:
expiration)
- let accessibilityDate = TalerDater.accessibilityDate(date)
?? dateString
- let accessibilityLabel = String(localized: "Expires:
\(accessibilityDate)")
+ let a11yDate = TalerDater.accessibilityDate(date) ??
dateString
+ let a11yLabel = String(localized: "Expires: \(a11yDate)",
comment: "VoiceOver")
Text("Expires: \(dateString)")
.talerFont(.body)
- .accessibilityLabel(accessibilityLabel)
+ .accessibilityLabel(a11yLabel)
.foregroundColor(WalletColors().secondary(colorScheme,
colorSchemeContrast))
}
.listStyle(myListStyle.style).anyView
diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
index 09235bc..d28413b 100644
--- a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
+++ b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift
@@ -50,16 +50,16 @@ struct P2pReceiveURIView: View {
large: false, pending: false, incoming:
true,
baseURL: nil,
noFees: nil, // TODO: check baseURL
for fees
- status: nil,
+ txStateLcl: nil,
summary:
peerPushCreditResponse.contractTerms.summary,
merchant: nil)
let expiration =
peerPushCreditResponse.contractTerms.purse_expiration
let (dateString, date) = TalerDater.dateString(from:
expiration)
- let accessibilityDate = TalerDater.accessibilityDate(date)
?? dateString
- let accessibilityLabel = String(localized: "Expires:
\(accessibilityDate)")
+ let a11yDate = TalerDater.accessibilityDate(date) ??
dateString
+ let a11yLabel = String(localized: "Expires: \(a11yDate)",
comment: "VoiceOver")
Text("Expires: \(dateString)")
.talerFont(.body)
- .accessibilityLabel(accessibilityLabel)
+ .accessibilityLabel(a11yLabel)
.foregroundColor(WalletColors().secondary(colorScheme,
colorSchemeContrast))
}
.listStyle(myListStyle.style).anyView
diff --git a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
index 6eaa555..ec5a3b2 100644
--- a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
@@ -1,26 +1,17 @@
/*
- * 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
-func templateFee(ppCheck: PreparePayResult?) -> Amount? {
- do {
- if let ppCheck {
- // Outgoing: fee = effective - raw
- if let effective = ppCheck.amountEffective {
- let fee = try effective - ppCheck.amountRaw
- return fee
- }
- }
- } catch {}
- return nil
-}
-
-// Will be called either by the user scanning a QR code or tapping the
provided link,
-// both from the shop's website. We show the payment details
+// Will be called either by the user scanning a pay-template QR code or
tapping the provided link,
+// both from the shop's website or even from a printed QR code.
+// We check whether amount and/or summary is editable, and finally go to
PaymentView
struct PayTemplateV: View {
private let symLog = SymLogV(0)
let stack: CallStack
@@ -33,22 +24,23 @@ struct PayTemplateV: View {
@AppStorage("minimalistic") var minimalistic: Bool = false
@AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
- let navTitle = String(localized: "Customize Order", comment:"pay merchant")
+ let navTitle = String(localized: "Custom Amount", comment:"pay merchant")
- @State private var insufficient = false
- @State private var preparePayResult: PreparePayResult? = nil
- @State private var currencyName: String? = nil
+// @State private var insufficient = false
+// @State private var preparePayResult: PreparePayResult? = nil
+ @State private var templateContract: TemplateContractDetails? = nil
+ @State private var currencyName = EMPTYSTRING
+ @State private var amountIsEditable = false
@State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING)
// Update currency when used
@State private var amountShortcut = Amount.zero(currency: EMPTYSTRING)
// Update currency when used
@State private var shortcutSelected = false
@State private var buttonSelected1 = false
@State private var buttonSelected2 = false
+ @State private var summaryIsEditable = false
@State private var summary: String = EMPTYSTRING // templateParam
- @State private var wantsSummary: Bool = false
- @State private var feeAmount: Amount? = nil
- @State private var feeStr: String = EMPTYSTRING
- var feeLabel: String { feeStr.count > 0 ? String(localized: "+ \(feeStr)
fee") : EMPTYSTRING }
+// @State private var feeAmount: Amount? = nil
+// @State private var feeStr: String = EMPTYSTRING
private func shortcutAction(_ shortcut: Amount) {
amountShortcut = shortcut
@@ -73,46 +65,13 @@ struct PayTemplateV: View {
}
}
- func queryURL() -> Bool {
- if let queryParameters = url.queryParameters {
- if let amountStr = queryParameters["amount"] {
- currencyName = amountStr
- amountToTransfer = Amount.zero(currency: amountStr)
- }
- if let summaryStr = queryParameters["summary"] {
- summary = summaryStr
- wantsSummary = true
- }
- return true
- }
- return false
- }
-
- func preparePayForTemplate() async {
- if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amountToTransfer,
summary: summary) {
- let amount = ppCheck.amountRaw
- let currency = amount.currencyStr
- let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
- insufficient = ppCheck.status == .insufficientBalance
- feeAmount = templateFee(ppCheck: ppCheck)
- if let feeAmount {
- feeStr = feeAmount.string(currencyInfo)
- } else { feeStr = EMPTYSTRING }
- let amountVoiceOver = amount.string(currencyInfo)
- announce(this: "\(amountVoiceOver), \(feeLabel)")
- preparePayResult = ppCheck
- } else {
- symLog.log("preparePayForTemplateM failed")
- }
- }
-
var body: some View {
- if let preparePayResult {
- let effective = preparePayResult.amountEffective
- let baseURL = preparePayResult.contractTerms.exchanges.first?.url
- let raw = preparePayResult.amountRaw
- let currency = raw.currencyStr
- let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
+ if let templateContract { // preparePayResult
+// let effective = preparePayResult.amountEffective
+// let baseURL = preparePayResult.contractTerms.exchanges.first?.url
+// let raw = preparePayResult.amountRaw
+// let currency = raw.currencyStr
+ let currencyInfo = controller.info(for: currencyName,
controller.currencyTicker)
let amountLabel = minimalistic ? String(localized: "Amount:")
: String(localized: "Amount to
pay:")
let finalDestinationI = LazyView {
@@ -120,53 +79,58 @@ struct PayTemplateV: View {
url: url,
template: true,
amountToTransfer: $amountToTransfer,
- summary: $summary)
- }
+ summary: $summary,
+ amountIsEditable: amountIsEditable,
+ summaryIsEditable: summaryIsEditable)
+ } // final destination with amountToTransfer, after user input of
amount
+ let finalDestinationS = LazyView {
+ PaymentView(stack: stack.push(),
+ url: url,
+ template: true,
+ amountToTransfer: $amountShortcut,
+ summary: $summary,
+ amountIsEditable: amountIsEditable,
+ summaryIsEditable: summaryIsEditable)
+ } // final destination with amountShortcut, when user tapped a
shortcut
+
let inputDestination = LazyView {
SubjectInputV(stack: stack.push(), url: url,
amountAvailable: nil,
amountToTransfer: $amountToTransfer,
amountLabel: amountLabel,
summary: $summary,
- insufficient: $insufficient,
- feeAmount: $feeAmount,
- feeIsNotZero: true, // feeIsNotZero(),
+// insufficient: $insufficient,
+// feeAmount: $feeAmount,
+ feeIsNotZero: true, // TODO: feeIsNotZero()
currencyInfo: currencyInfo,
targetView: finalDestinationI)
- }
- let finalDestinationS = LazyView {
- PaymentView(stack: stack.push(),
- url: url,
- template: true,
- amountToTransfer: $amountShortcut,
- summary: $summary)
- }
+ } // destination to subject input
let shortcutDestination = LazyView {
SubjectInputV(stack: stack.push(), url: url,
amountAvailable: nil,
amountToTransfer: $amountShortcut,
amountLabel: amountLabel,
summary: $summary,
- insufficient: $insufficient,
- feeAmount: $feeAmount,
- feeIsNotZero: true, // feeIsNotZero(),
+// insufficient: $insufficient,
+// feeAmount: $feeAmount,
+ feeIsNotZero: true, // TODO: feeIsNotZero()
currencyInfo: currencyInfo,
targetView: finalDestinationS)
- }
+ }// destination to subject input, when user tapped an amount
shortcut
Group {
- if let currencyName { // template included a currency name =>
let the user input an amount
+ if amountIsEditable { // template contract amount is not
fixed => let the user input an amount first
let amountInput = AmountInputV(stack: stack.push(), url: url,
amountAvailable: nil,
amountToTransfer: $amountToTransfer,
amountLabel: amountLabel,
- wantsSummary: wantsSummary,
+ summaryIsEditable: summaryIsEditable,
summary: $summary,
- insufficient: $insufficient,
- feeAmount: $feeAmount,
+// insufficient: $insufficient,
+// feeAmount: $feeAmount,
shortcutAction: shortcutAction,
buttonAction: buttonAction1)
ScrollView {
- if wantsSummary {
+ if summaryIsEditable { // after amount input,
amountInput
.background(NavigationLink(destination:
shortcutDestination, isActive: $shortcutSelected)
{ EmptyView() }.frame(width:
0).opacity(0).hidden())
@@ -180,32 +144,64 @@ struct PayTemplateV: View {
.background(NavigationLink(destination:
finalDestinationI, isActive: $buttonSelected1)
{ EmptyView() }.frame(width:
0).opacity(0).hidden())
}
- } // ScrollVStack
- } else if wantsSummary { // check summary
+ }
+ } else if summaryIsEditable { // template contract summary is
not fixed => let the user input a summary
ScrollView {
inputDestination
.background(NavigationLink(destination:
finalDestinationI, isActive: $buttonSelected2)
{ EmptyView() }.frame(width:
0).opacity(0).hidden()
)
}
- } else {
+ } else { // both template contract amount
and summary are fixed => directly show the payment
PaymentView(stack: stack.push(),
url: url,
template: true,
amountToTransfer: $amountToTransfer,
- summary: $summary)
+ summary: $summary,
+ amountIsEditable: amountIsEditable,
+ summaryIsEditable: summaryIsEditable)
}
- }.onAppear() {
+ }.navigationTitle(navTitle)
+ .frame(maxWidth: .infinity, alignment: .leading)
+
.background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
+ .onAppear() {
symLog.log("onAppear")
DebugViewC.shared.setSheetID(SHEET_PAY_TEMPLATE)
- }.navigationTitle(navTitle)
+ }
} else {
LoadingView(scopeInfo: nil, message: url.host)
.task {
- symLog.log("LoadingView.task preparePayForTemplate")
- let hasParams = queryURL()
- await preparePayForTemplate()
- symLog.log("preparePayForTemplate finished")
+ if let details = try? await
model.checkPayForTemplateM(url.absoluteString) {
+ let supportedCurrency0 = details.supportedCurrencies[0]
+ let contract =
details.templateDetails.templateContract // specifies fixed amount/summary
+ amountIsEditable = contract.amount == nil
+ summaryIsEditable = contract.summary == nil
+ let defaults =
details.templateDetails.editableDefaults // might be nil, or its fields
might be nil
+ let prepCurrency = contract.currency ??
defaults?.currency ?? supportedCurrency0
+ let zeroAmount = Amount(currency: prepCurrency, cent:
0)
+ let prepAmount = contract.amount ?? defaults?.amount
// might be nil
+ let prepSummary = contract.summary ??
defaults?.summary // might be nil
+// symLog.log("LoadingView.task preparePayForTemplate")
+// if let result = await preparePayForTemplate(model:
model,
+// url:
url,
+// amount:
amountIsEditable ? prepAmount ?? zeroAmount
+//
: nil,
+// summary:
summaryIsEditable ? prepSummary ?? " "
+//
: nil,
+// announce:
announce)
+// { symLog.log("preparePayForTemplate finished")
+ amountToTransfer = prepAmount ?? zeroAmount
+ currencyName = prepCurrency
+ summary = prepSummary ?? EMPTYSTRING
+ templateContract = contract
+// insufficient = result.insufficient
+// feeAmount = result.feeAmount
+// feeStr = result.feeStr
+// preparePayResult = result.ppCheck
+// } else {
+// symLog.log("preparePayForTemplateM failed")
+// }
+ }
}
}
}
diff --git a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
index dd3581f..8dfcc08 100644
--- a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
+++ b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
@@ -1,11 +1,69 @@
/*
- * 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
+typealias Announce = (_ this: String) -> ()
+
+func feeLabel(_ feeString: String) -> String {
+ feeString.count > 0 ? String(localized: "+ \(feeString) fee")
+ : EMPTYSTRING
+}
+
+func templateFee(ppCheck: PreparePayResult?) -> Amount? {
+ do {
+ if let ppCheck {
+ // Outgoing: fee = effective - raw
+ if let effective = ppCheck.amountEffective {
+ let fee = try effective - ppCheck.amountRaw
+ return fee
+ }
+ }
+ } catch {}
+ return nil
+}
+
+struct PayForTemplateResult {
+ let ppCheck: PreparePayResult
+ let insufficient: Bool
+ let feeAmount: Amount?
+ let feeStr: String
+}
+
+func preparePayForTemplate(model: WalletModel,
+ url: URL,
+ amount: Amount?,
+ summary: String?,
+ announce: Announce)
+ async -> PayForTemplateResult? {
+ if let ppCheck = try? await
model.preparePayForTemplateM(url.absoluteString, amount: amount, summary:
summary) {
+ let controller = Controller.shared
+ let amountRaw = ppCheck.amountRaw
+ let currency = amountRaw.currencyStr
+ let currencyInfo = controller.info(for: currency,
controller.currencyTicker)
+ let amountVoiceOver = amountRaw.string(currencyInfo)
+ let insufficient = ppCheck.status == .insufficientBalance
+ if let feeAmount = templateFee(ppCheck: ppCheck) {
+ let feeStr = feeAmount.string(currencyInfo)
+ let feeLabel = feeLabel(feeStr)
+ announce("\(amountVoiceOver), \(feeLabel)")
+ return PayForTemplateResult(ppCheck: ppCheck, insufficient:
insufficient,
+ feeAmount: feeAmount, feeStr: feeStr)
+ }
+ announce(amountVoiceOver)
+ return PayForTemplateResult(ppCheck: ppCheck, insufficient:
insufficient,
+ feeAmount: nil, feeStr: EMPTYSTRING)
+ }
+ return nil
+}
+
+// MARK: -
// Will be called either by the user scanning a QR code or tapping the
provided link,
// both from the shop's website. We show the payment details in a sheet.
struct PaymentView: View {
@@ -18,6 +76,8 @@ struct PaymentView: View {
let template: Bool
@Binding var amountToTransfer: Amount
@Binding var summary: String
+ let amountIsEditable: Bool //
+ let summaryIsEditable: Bool //
@EnvironmentObject private var model: WalletModel
@EnvironmentObject private var controller: Controller
@@ -34,6 +94,7 @@ struct PaymentView: View {
// TODO: show balanceDetails.balanceAvailable
let baseURL =
preparePayResult.contractTerms.exchanges.first?.url
let raw = preparePayResult.amountRaw
+ let status = preparePayResult.status
let currency = raw.currencyStr
let topTitle = String(localized: "Amount to pay:")
let topAbbrev = String(localized: "Pay:", comment: "mini")
@@ -50,7 +111,7 @@ struct PaymentView: View {
large: false, pending: false, incoming:
false,
baseURL: baseURL,
noFees: nil, // TODO: check baseURL
for fees
- status: nil,
+ txStateLcl: nil,
summary: terms.summary,
merchant: terms.merchant.name)
// TODO: payment: popup with all possible exchanges, check
fees
@@ -67,7 +128,7 @@ struct PaymentView: View {
large: false, pending: false, incoming:
false,
baseURL: baseURL,
noFees: nil, // TODO: check baseURL
for fees
- status: nil,
+ txStateLcl: nil,
summary: terms.summary,
merchant: terms.merchant.name)
} else {
@@ -102,8 +163,8 @@ struct PaymentView: View {
symLog.log(".task")
if template {
if let result = try? await
model.preparePayForTemplateM(url.absoluteString,
- amount:
amountToTransfer,
-
summary: summary) {
+ amount:
amountIsEditable ? amountToTransfer : nil,
+ summary:
summaryIsEditable ? summary : nil) {
preparePayResult = result
}
} else {
@@ -170,9 +231,10 @@ struct PaymentURIView_Previews: PreviewProvider {
// @State private var amount: Amount? = nil // templateParam
// @State private var summary: String? = nil // templateParam
- PaymentView(stack: CallStack("Preview"),
- url: url, template: false, amountToTransfer: nil, summary:
nil,
- preparePayResult: details)
+ PaymentView(stack: CallStack("Preview"), url: url,
+ template: false, amountToTransfer: nil, summary: nil,
+ amountIsEditable: false, summaryIsEditable: false,
+ preparePayResult: details)
}
}
#endif
diff --git a/TalerWallet1/Views/Sheets/QRSheet.swift
b/TalerWallet1/Views/Sheets/QRSheet.swift
index d775deb..8445157 100644
--- a/TalerWallet1/Views/Sheets/QRSheet.swift
+++ b/TalerWallet1/Views/Sheets/QRSheet.swift
@@ -12,12 +12,24 @@ struct QRSheet: View {
let stack: CallStack
@State private var scannedCode: String?
+ func codeToURL(_ code: String) -> URL? {
+ if let scannedURL = URL(string: code) {
+ return scannedURL
+ }
+ if let encodedScan = code.addingPercentEncoding(withAllowedCharacters:
.urlQueryAllowed) {
+ if let encodedURL = URL(string: encodedScan) {
+ return encodedURL
+ }
+ }
+ return nil
+ }
+
var body: some View {
Group {
if scannedCode != nil {
// let _ = print(scannedCode as Any) // TODO: logging
- if let scannedURL = URL(string: scannedCode!) {
+ if let scannedURL = codeToURL(scannedCode!) {
let scheme = scannedURL.scheme
if scheme?.lowercased() == "taler" {
URLSheet(stack: stack.push(), urlToOpen: scannedURL)
diff --git a/TalerWallet1/Views/Sheets/Sheet.swift
b/TalerWallet1/Views/Sheets/Sheet.swift
index 6aa796e..7b3cae5 100644
--- a/TalerWallet1/Views/Sheets/Sheet.swift
+++ b/TalerWallet1/Views/Sheets/Sheet.swift
@@ -58,7 +58,7 @@ struct Sheet: View {
.monospacedDigit()
.edgesIgnoringSafeArea(.top)
.id("sheetID")
- .accessibilityLabel(Text("Sheet.ID.", comment:
"AccessibilityLabel"))
+ .accessibilityLabel(Text("Sheet.ID.", comment: "VoiceOver"))
.accessibilityValue(idString)
}
.onDisappear {
diff --git a/TalerWallet1/Views/Sheets/URLSheet.swift
b/TalerWallet1/Views/Sheets/URLSheet.swift
index ea0e809..9cb70f1 100644
--- a/TalerWallet1/Views/Sheets/URLSheet.swift
+++ b/TalerWallet1/Views/Sheets/URLSheet.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
@@ -32,7 +35,8 @@ struct URLSheet: View {
WithdrawExchangeV(stack: stack.push(), url: urlToOpen)
// TODO: just check the ToS
case .pay:
PaymentView(stack: stack.push(), url: urlToOpen,
- template: false, amountToTransfer:
$amountToTransfer, summary: $summary)
+ template: false, amountToTransfer:
$amountToTransfer, summary: $summary,
+ amountIsEditable: false, summaryIsEditable: false)
case .payPull:
P2pPayURIView(stack: stack.push(), url: urlToOpen)
case .payPush:
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
index 35840d1..4d3bd51 100644
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -56,7 +56,7 @@ struct WithdrawURIView: View {
large: false, pending: false, incoming:
true,
baseURL: exchange.exchangeBaseUrl,
noFees: exchange.noFees,
- status: nil, //
common.txState.major.localizedState
+ txStateLcl: nil, //
common.txState.major.localizedState
summary: nil,
merchant: nil)
let someCoins = SomeCoins(details: withdrawalAmountDetails)
@@ -95,18 +95,21 @@ struct WithdrawURIView: View {
.task {
symLog.log(".task")
if let withdrawUriInfo = try? await
model.getWithdrawalDetailsForUriM(url.absoluteString) {
- let amount = withdrawUriInfo.amount
- let baseUrl = withdrawUriInfo.defaultExchangeBaseUrl
- ??
withdrawUriInfo.possibleExchanges.first?.exchangeBaseUrl
- if let baseUrl {
- exchange = try? await model.getExchangeByUrl(url: baseUrl)
- if let details = try? await
model.getWithdrawalDetailsForAmountM(baseUrl, amount: amount) {
- withdrawalAmountDetails = details
+ if let amount = withdrawUriInfo.amount {
+ let baseUrl = withdrawUriInfo.defaultExchangeBaseUrl
+ ?? withdrawUriInfo.possibleExchanges.first?.exchangeBaseUrl
+ if let baseUrl {
+ exchange = try? await model.getExchangeByUrl(url:
baseUrl)
+ if let details = try? await
model.getWithdrawalDetailsForAmountM(baseUrl, amount: amount) {
+ withdrawalAmountDetails = details
+ }
+ // agePicker.setAges(ages:
details?.ageRestrictionOptions)
+ } else { // TODO: error
+ symLog.log("no exchangeBaseUrl or no exchange")
+ withdrawalAmountDetails = nil
}
- // agePicker.setAges(ages:
details?.ageRestrictionOptions)
- } else { // TODO: error
- symLog.log("no exchangeBaseUrl or no exchange")
- withdrawalAmountDetails = nil
+ } else {
+ // TODO: amount = nil ==> show amount input
}
}
}
diff --git a/TalerWallet1/Views/Transactions/ManualDetailsV.swift
b/TalerWallet1/Views/Transactions/ManualDetailsV.swift
index ea25e11..f007ec2 100644
--- a/TalerWallet1/Views/Transactions/ManualDetailsV.swift
+++ b/TalerWallet1/Views/Transactions/ManualDetailsV.swift
@@ -159,14 +159,26 @@ struct ManualDetailsV: View {
}
}
+ func amountString(_ amount: Amount, specs: CurrencySpecification?, scope:
ScopeInfo? = nil) -> String {
+ if let specs {
+ let myScope = scope ?? ScopeInfo(type: .madeUp, currency:
amount.currencyStr)
+ let currencyInfo = CurrencyInfo(scope: myScope, specs: specs,
+ formatter:
CurrencyFormatter.formatter(scope: myScope,
+
specs: specs))
+ return amount.string(currencyInfo)
+ }
+ return amount.string()
+ }
+
var body: some View {
if let accountDetails = details.exchangeCreditAccountDetails {
let validDetails = validDetails(accountDetails)
if validDetails.count > 0 {
let account = validDetails[accountID]
if let amount = account.transferAmount {
- let amountStr = amount.readableDescription // TODO:
formatter?
- let obtainStr = common.amountRaw.readableDescription
+ let specs = account.currencySpecification
+ let amountStr = amountString(amount, specs: specs)
+ let obtainStr = common.amountRaw.string()
if !minimalistic {
Text("The Payment Service Provider is waiting for your
wire-transfer.")
.bold()
@@ -183,7 +195,6 @@ struct ManualDetailsV: View {
.listRowSeparator(.hidden)
}
} else if let amount = account.transferAmount {
- let amountStr = amount.readableDescription
if let bankName = account.bankLabel {
Text(bankName + ": " + amountStr)
} else {
@@ -193,10 +204,10 @@ struct ManualDetailsV: View {
let payto = account.paytoUri
let payURL = URL(string: payto)
if let queryParameters = payURL?.queryParameters {
- let amountStr = queryParameters["amount"] ??
EMPTYSTRING
- let receiverStr = queryParameters["receiver-name"] ??
EMPTYSTRING
- let senderStr = queryParameters["sender-name"] ??
EMPTYSTRING
- let messageStr = queryParameters["message"] ??
EMPTYSTRING
+ let receiverStr = (queryParameters["receiver-name"] ??
EMPTYSTRING).replacingOccurrences(of: "+", with: " ")
+// let amountStr = queryParameters["amount"] ??
EMPTYSTRING
+// let messageStr = queryParameters["message"] ??
EMPTYSTRING
+// let senderStr = queryParameters["sender-name"] ??
EMPTYSTRING
let iban = payURL?.iban
let xTaler = payURL?.xTaler ??
@@ -205,10 +216,10 @@ struct ManualDetailsV: View {
let cryptocode = HStack {
Text(details.reservePub)
.monospacedDigit()
- .accessibilityLabel("Cryptocode")
+ .accessibilityLabel(Text("Cryptocode",
comment: "VoiceOver"))
.frame(maxWidth: .infinity, alignment:
.leading)
CopyButton(textToCopy: details.reservePub,
vertical: true)
- .accessibilityLabel("Copy the cryptocode")
+ .accessibilityLabel(Text("Copy the
cryptocode", comment: "VoiceOver"))
.disabled(false)
} .padding(.leading)
let payeeCode = HStack {
@@ -220,9 +231,9 @@ struct ManualDetailsV: View {
.padding(.leading)
} .frame(maxWidth: .infinity, alignment:
.leading)
.accessibilityElement(children: .combine)
- .accessibilityLabel("Payee")
+ .accessibilityLabel(Text("Payee", comment:
"VoiceOver"))
CopyButton(textToCopy: receiverStr, vertical: true)
- .accessibilityLabel("Copy the payee")
+ .accessibilityLabel(Text("Copy the payee",
comment: "VoiceOver"))
.disabled(false)
} .padding(.top, -8)
let ibanCode = HStack {
@@ -234,9 +245,9 @@ struct ManualDetailsV: View {
.padding(.leading)
} .frame(maxWidth: .infinity, alignment:
.leading)
.accessibilityElement(children: .combine)
- .accessibilityLabel("IBAN of the payee")
+ .accessibilityLabel(Text("IBAN of the payee",
comment: "VoiceOver"))
CopyButton(textToCopy: iban ?? EMPTYSTRING,
vertical: true)
- .accessibilityLabel("Copy the IBAN")
+ .accessibilityLabel(Text("Copy the IBAN",
comment: "VoiceOver"))
.disabled(false)
} .padding(.top, -8)
let xTalerCode = HStack {
@@ -248,9 +259,9 @@ struct ManualDetailsV: View {
.padding(.leading)
} .frame(maxWidth: .infinity, alignment:
.leading)
.accessibilityElement(children: .combine)
- .accessibilityLabel("account of the payee")
+ .accessibilityLabel(Text("account of the
payee", comment: "VoiceOver"))
CopyButton(textToCopy: xTaler, vertical: true)
- .accessibilityLabel("Copy the account")
+ .accessibilityLabel(Text("Copy the account",
comment: "VoiceOver"))
.disabled(false)
} .padding(.top, -8)
@@ -305,7 +316,7 @@ struct ManualDetailsV: View {
// Spacer()
ShareButton(textToShare: payto)
.frame(maxWidth: .infinity, alignment:
.center)
- .accessibilityLabel("Share the PayTo URL")
+ .accessibilityLabel(Text("Share the PayTo
URL", comment: "VoiceOver"))
.disabled(false)
// Spacer()
} .listRowSeparator(.automatic)
diff --git a/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
b/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
index c5945df..8951a92 100644
--- a/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
+++ b/TalerWallet1/Views/Transactions/ThreeAmountsV.swift
@@ -18,6 +18,12 @@ struct ThreeAmountsSheet: View {
let summary: String?
let merchant: String?
+#if DEBUG
+ @AppStorage("developerMode") var developerMode: Bool = true
+#else
+ @AppStorage("developerMode") var developerMode: Bool = false
+#endif
+
var body: some View {
let raw = common.amountRaw
let effective = common.amountEffective
@@ -35,6 +41,9 @@ struct ThreeAmountsSheet: View {
: String(localized:
"Obtained:", comment: "mini") )
: (pending ? String(localized:
"Pay:", comment: "mini")
: String(localized:
"Paid:", comment: "mini") )
+ let majorLcl = common.txState.major.localizedState
+ let txStateLcl = developerMode && pending ?
(common.txState.minor?.localizedState ?? majorLcl)
+ : majorLcl
ThreeAmountsV(stack: stack.push(),
topTitle: topTitle, topAbbrev: topAbbrev,
topAmount: raw, fee: fee,
@@ -44,7 +53,7 @@ struct ThreeAmountsSheet: View {
large: large, pending: pending, incoming: incoming,
baseURL: baseURL,
noFees: noFees,
- status: common.txState.major.localizedState,
+ txStateLcl: txStateLcl,
summary: summary,
merchant: merchant)
}
@@ -64,7 +73,7 @@ struct ThreeAmountsV: View {
let incoming: Bool
let baseURL: String?
let noFees: Bool? // true if exchange charges no
fees at all
- let status: String?
+ let txStateLcl: String? // localizedState
let summary: String?
let merchant: String?
diff --git a/TalerWallet1/Views/Transactions/TransactionRowView.swift
b/TalerWallet1/Views/Transactions/TransactionRowView.swift
index 61e878d..df40764 100644
--- a/TalerWallet1/Views/Transactions/TransactionRowView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionRowView.swift
@@ -90,7 +90,7 @@ struct TransactionRowView: View {
.talerFont(.headline)
// .fontWeight(.medium) iOS 16
.padding(.bottom, -2.0)
- .accessibilityLabel(doneOrPending ? topString : topString +
String(localized: ", canceled"))
+ .accessibilityLabel(doneOrPending ? topString : topString +
String(localized: ", canceled", comment: "VoiceOver"))
let centerBottom = Text(dateString)
.foregroundColor(textColor)
.talerFont(.callout)
diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
index 12f6314..f9a6bd7 100644
--- a/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
+++ b/TalerWallet1/Views/Transactions/TransactionSummaryV.swift
@@ -100,7 +100,7 @@ struct TransactionSummaryV: View {
let pending = transaction.isPending
let locale = TalerDater.shared.locale
let (dateString, date) = TalerDater.dateString(from: common.timestamp)
- let accessibilityDate = TalerDater.accessibilityDate(date) ??
dateString
+ let a11yDate = TalerDater.accessibilityDate(date) ?? dateString
let navTitle2 = transaction.isDone ? transaction.localizedTypePast
: transaction.localizedType
VStack {
@@ -117,7 +117,7 @@ struct TransactionSummaryV: View {
} // Suspend + Resume buttons
Text(dateString)
.talerFont(.body)
- .accessibilityLabel(accessibilityDate)
+ .accessibilityLabel(a11yDate)
.foregroundColor(WalletColors().secondary(colorScheme,
colorSchemeContrast))
.listRowSeparator(.hidden)
VStack(alignment: .trailing) {
@@ -296,10 +296,9 @@ struct TransactionSummaryV: View {
let title = EMPTYSTRING
Text(title)
.talerFont(.body)
- RotatingTaler(size: 100, progress: true,
- rotationEnabled: $rotationEnabled)
+ RotatingTaler(size: 100, progress: true,
rotationEnabled: $rotationEnabled)
.frame(maxWidth: .infinity, alignment: .center)
-// .accessibilityLabel("Progress indicator")
+ // has its own accessibilityLabel
case .withdrawal(let withdrawalTransaction): Group {
let details = withdrawalTransaction.details
if pending {
@@ -373,7 +372,7 @@ struct TransactionSummaryV: View {
let stackStr = error.stack ?? EMPTYSTRING
let errorStr = error.hint + "\n" + stackStr
CopyButton(textToCopy: errorStr, vertical:
true)
- .accessibilityLabel("Copy the error")
+ .accessibilityLabel(Text("Copy the
error", comment: "VoiceOver"))
.disabled(false)
}
}
@@ -384,11 +383,11 @@ struct TransactionSummaryV: View {
if !transaction.isDone {
let expiration = details.info.expiration
let (dateString, date) =
TalerDater.dateString(from: expiration)
- let accessibilityDate =
TalerDater.accessibilityDate(date) ?? dateString
- let accessibilityLabel = String(localized:
"Expires: \(accessibilityDate)")
+ let a11yDate = TalerDater.accessibilityDate(date)
?? dateString
+ let a11yLabel = String(localized: "Expires:
\(a11yDate)", comment: "VoiceOver")
Text("Expires: \(dateString)")
.talerFont(.body)
- .accessibilityLabel(accessibilityLabel)
+ .accessibilityLabel(a11yLabel)
.foregroundColor(WalletColors().secondary(colorScheme, colorSchemeContrast))
}
// TODO: isSendCoins should show QR only while not yet
expired - either set timer or wallet-core should do so and send a
state-changed notification
diff --git a/TestFlight/WhatToTest.en-US.txt b/TestFlight/WhatToTest.en-US.txt
index 15e49fd..8ae3c01 100644
--- a/TestFlight/WhatToTest.en-US.txt
+++ b/TestFlight/WhatToTest.en-US.txt
@@ -1,3 +1,15 @@
+Version 0.11.0 (wallet-core 0.11.1)
+
+• Spanish localization
+- Pay-Templates overhauled
+
+
+Version 0.10.3 (wallet-core 0.10.8)
+
+- Error handling
+- Bugfixes
+
+
Version 0.10.2 (wallet-core 0.10.7)
- Improve German localization
diff --git a/taler-swift/Sources/taler-swift/Amount.swift
b/taler-swift/Sources/taler-swift/Amount.swift
index 9866301..768fd36 100644
--- a/taler-swift/Sources/taler-swift/Amount.swift
+++ b/taler-swift/Sources/taler-swift/Amount.swift
@@ -182,9 +182,10 @@ public final class Amount: Codable, Hashable, @unchecked
Sendable, CustomStringC
"\(currency):\(valueStr)"
}
- /// The string representation of the amount, formatted as
"`integer`.`fraction` `currency`" (with space).
+ /// The string representation of the amount, formatted as
"`integer`.`fraction` `currency`" (with non-breaking space).
public var readableDescription: String {
- "\(valueStr) \(currency)"
+ let NONBREAKING = "\u{00A0}"
+ return valueStr + NONBREAKING + currency
}
/// Whether the value is valid. An amount is valid if and only if the
currency is not empty and the value is less than the maximum allowed value.
diff --git a/taler-swift/Sources/taler-swift/Time.swift
b/taler-swift/Sources/taler-swift/Time.swift
index 98f0e27..084ad09 100644
--- a/taler-swift/Sources/taler-swift/Time.swift
+++ b/taler-swift/Sources/taler-swift/Time.swift
@@ -16,6 +16,51 @@ enum TimestampError: Error {
case invalidUInt64Value
}
+public enum RelativeTime: Codable, Hashable, Sendable {
+ // Duration in microseconds or "forever"
+ // to represent an infinite duration. Numeric
+ // values are capped at 2^53 - 1 inclusive.
+ case microseconds(UInt64)
+ case forever
+
+ enum CodingKeys: String, CodingKey {
+ case d_us = "d_us"
+ }
+
+ public init(from decoder: Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+ do {
+ self = RelativeTime.microseconds(try container.decode(UInt64.self,
forKey: .d_us))
+ } catch { // rethrows or never
+ let stringValue = try container.decode(String.self, forKey: .d_us)
+ if stringValue == "forever" {
+ self = RelativeTime.forever
+ } else {
+ throw TimestampError.invalidStringRepresentation
+ }
+ }
+ }
+ public func hash(into hasher: inout Hasher) {
+ switch self {
+ case .microseconds(let d_us):
+ hasher.combine(d_us)
+ case .forever:
+ hasher.combine("forever")
+ }
+ }
+ public func encode(to encoder: Encoder) throws {
+ var value = encoder.container(keyedBy: CodingKeys.self)
+ switch self {
+ case .microseconds(let d_us):
+ try value.encode(d_us, forKey: .d_us)
+ case .forever:
+ try value.encode("forever", forKey: .d_us)
+ }
+ }
+}
+
+
+
/// A point in time, represented by milliseconds from January 1, 1970..
public enum Timestamp: Codable, Hashable, Sendable {
case milliseconds(UInt64)
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] branch master updated (18d895c -> c4761b4),
gnunet <=
- [taler-taler-ios] 04/29: cleanup, gnunet, 2024/05/28
- [taler-taler-ios] 03/29: checkInternetConnection, gnunet, 2024/05/28
- [taler-taler-ios] 07/29: crash fix 8780, gnunet, 2024/05/28
- [taler-taler-ios] 05/29: CurrencyFormatter for manual withdrawals, gnunet, 2024/05/28
- [taler-taler-ios] 02/29: currencyInfo instead of readableDescription, gnunet, 2024/05/28
- [taler-taler-ios] 06/29: non-breaking space, gnunet, 2024/05/28
- [taler-taler-ios] 01/29: Bank links, gnunet, 2024/05/28
- [taler-taler-ios] 13/29: addingPercentEncoding, gnunet, 2024/05/28
- [taler-taler-ios] 24/29: Logging, gnunet, 2024/05/28
- [taler-taler-ios] 29/29: Bump version to 0.11.0 (0.11.1), gnunet, 2024/05/28