[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] 199/204: A11y as tupel
From: |
gnunet |
Subject: |
[taler-taler-ios] 199/204: A11y as tupel |
Date: |
Thu, 05 Dec 2024 23:52:47 +0100 |
This is an automated email from the git hooks/post-receive script.
marc-stibane pushed a commit to branch master
in repository taler-ios.
commit 64e8fc4e3d9b5271d657db3e367365e61dbbf9da
Author: Marc Stibane <marc@taler.net>
AuthorDate: Thu Dec 5 23:01:20 2024 +0100
A11y as tupel
---
TalerWallet1/Helper/CurrencySpecification.swift | 41 ++++---
.../Views/Actions/Banking/DepositAmountView.swift | 2 +-
.../Views/Actions/Banking/QuiteSomeCoins.swift | 20 ++--
.../Views/Actions/Peer2peer/P2PSubjectV.swift | 125 +++++++++++----------
.../Views/Actions/Peer2peer/RequestPayment.swift | 24 ++--
.../Views/Actions/Peer2peer/SendAmountView.swift | 16 +--
TalerWallet1/Views/HelperViews/AmountInputV.swift | 8 +-
TalerWallet1/Views/HelperViews/AmountV.swift | 36 +++---
TalerWallet1/Views/HelperViews/CurrencyField.swift | 4 +-
.../Views/HelperViews/CurrencyInputView.swift | 8 +-
.../Views/HelperViews/QRCodeDetailView.swift | 43 ++++---
TalerWallet1/Views/HelperViews/ScopePicker.swift | 53 +++++----
.../WithdrawBankIntegrated/WithdrawURIView.swift | 7 +-
.../Views/Transactions/ManualDetailsV.swift | 17 ++-
.../Views/Transactions/ManualDetailsWireV.swift | 43 +++++--
15 files changed, 262 insertions(+), 185 deletions(-)
diff --git a/TalerWallet1/Helper/CurrencySpecification.swift
b/TalerWallet1/Helper/CurrencySpecification.swift
index 57a1347..6472a61 100644
--- a/TalerWallet1/Helper/CurrencySpecification.swift
+++ b/TalerWallet1/Helper/CurrencySpecification.swift
@@ -38,30 +38,41 @@ extension Locale {
extension Amount {
func formatted(_ currencyInfo: CurrencyInfo?, isNegative: Bool,
- useISO: Bool = false, a11y: String? = nil
- ) -> String {
+ useISO: Bool = false, a11yDecSep: String? = nil
+ ) -> (String, String) {
if let currencyInfo {
- return currencyInfo.string(for: valueAsFloatTuple, isNegative:
isNegative, currency: currencyStr,
- useISO: useISO, a11y: a11y)
+ let a11y = currencyInfo.string(for: valueAsFloatTuple,
+ isNegative: isNegative,
+ currency: currencyStr,
+ useISO: true,
+ a11yDecSep: a11yDecSep)
+ let strg = currencyInfo.string(for: valueAsFloatTuple,
+ isNegative: isNegative,
+ currency: currencyStr,
+ useISO: useISO,
+ a11yDecSep: nil)
+ return (strg, a11y)
} else {
- return valueStr
+ return (valueStr, valueStr)
}
}
// this is the function to use
- func formatted(_ scope: ScopeInfo?, isNegative: Bool, useISO: Bool =
false, a11y: String? = nil) -> String {
+ func formatted(_ scope: ScopeInfo?, isNegative: Bool,
+ useISO: Bool = false, a11yDecSep: String? = nil
+ ) -> (String, String) {
let controller = Controller.shared
if let scope {
if let currencyInfo = controller.info(for: scope) {
- return self.formatted(currencyInfo, isNegative: isNegative,
useISO: useISO, a11y: a11y)
+ return self.formatted(currencyInfo, isNegative: isNegative,
useISO: useISO, a11yDecSep: a11yDecSep)
}
}
- return self.readableDescription
+ return (self.readableDescription, self.readableDescription)
}
- func formatted(specs: CurrencySpecification?, isNegative: Bool, scope:
ScopeInfo? = nil,
- useISO: Bool = false
- ) -> String {
+ func formatted(specs: CurrencySpecification?, isNegative: Bool,
+ scope: ScopeInfo? = nil, useISO: Bool = false
+ ) -> (String, String) {
if let specs {
let formatter = CurrencyFormatter.formatter(currency: currencyStr,
specs: specs)
let currencyInfo = CurrencyInfo(specs: specs, formatter: formatter)
@@ -69,7 +80,7 @@ extension Amount {
} else if let scope {
return formatted(scope, isNegative: isNegative, useISO: useISO)
}
- return self.readableDescription
+ return (self.readableDescription, self.readableDescription)
}
func inputDigits(_ currencyInfo: CurrencyInfo) -> UInt {
@@ -193,7 +204,7 @@ public struct CurrencyInfo: Sendable {
// TODO: use valueAsDecimalTuple instead of valueAsFloatTuple
func string(for valueTuple: (Double, Double), isNegative: Bool, currency:
String,
- useISO: Bool = false, a11y: String? = nil) -> String {
+ useISO: Bool = false, a11yDecSep: String? = nil) ->
String {
formatter.setUseISO(useISO)
let (integer, fraction) = valueTuple
if let integerStr = formatter.string(for: isNegative ? -integer :
integer) {
@@ -227,8 +238,8 @@ public struct CurrencyInfo: Sendable {
}
}
// print(resultStr)
- if let a11y {
- resultStr = resultStr.replacingOccurrences(of:
decimalSeparator, with: a11y)
+ if let a11yDecSep {
+ resultStr = resultStr.replacingOccurrences(of:
decimalSeparator, with: a11yDecSep)
}
return currencyString(resultStr, useISO: useISO)
}
diff --git a/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
b/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
index af5a5c6..ce4e8ff 100644
--- a/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
+++ b/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift
@@ -84,7 +84,7 @@ struct DepositAmountView: View {
private func buttonTitle(_ amount: Amount) -> String {
if let balance {
let amountWithCurrency = amount.formatted(balance.scopeInfo,
isNegative: false, useISO: true)
- return DepositAmountView.navTitle(amountWithCurrency, true)
+ return DepositAmountView.navTitle(amountWithCurrency.0, true)
}
return DepositAmountView.navTitle() // should never happen
}
diff --git a/TalerWallet1/Views/Actions/Banking/QuiteSomeCoins.swift
b/TalerWallet1/Views/Actions/Banking/QuiteSomeCoins.swift
index c0bd243..5a09f24 100644
--- a/TalerWallet1/Views/Actions/Banking/QuiteSomeCoins.swift
+++ b/TalerWallet1/Views/Actions/Banking/QuiteSomeCoins.swift
@@ -18,13 +18,18 @@ struct CoinData {
var tooMany: Bool { numCoins > 999 }
let fee: Amount?
- func feeLabel(_ scope: ScopeInfo?, feeZero: String?, isNegative: Bool =
false) -> String {
- return if let fee {
- fee.isZero ? feeZero ?? EMPTYSTRING // String(localized: "No
withdrawal fee")
- : isNegative ? String(localized: "- \(fee.formatted(scope,
isNegative: false)) fee")
- : String(localized: "+ \(fee.formatted(scope,
isNegative: false)) fee")
+ func feeLabel(_ scope: ScopeInfo?, feeZero: String?, isNegative: Bool =
false) -> (String, String) {
+ if let fee {
+ let formatted = fee.formatted(scope, isNegative: false)
+ let feeLabel = fee.isZero ? feeZero ?? EMPTYSTRING //
String(localized: "No withdrawal fee")
+ : isNegative ? String(localized: "- \(formatted.0)
fee")
+ : String(localized: "+ \(formatted.0)
fee")
+ let feeA11Y = fee.isZero ? feeZero ?? EMPTYSTRING //
String(localized: "No withdrawal fee")
+ : isNegative ? String(localized: "- \(formatted.1)
fee")
+ : String(localized: "+ \(formatted.1)
fee")
+ return (feeLabel, feeA11Y)
} else {
- EMPTYSTRING
+ return (EMPTYSTRING, EMPTYSTRING)
}
}
}
@@ -76,7 +81,8 @@ struct QuiteSomeCoins: View {
let feeLabel = coinData.feeLabel(scope,
feeZero: String(localized: "No fee"),
isNegative: feeIsNegative)
- Text(feeLabel)
+ Text(feeLabel.0)
+ .accessibilityLabel(feeLabel.1)
.foregroundColor(.primary)
.talerFont(.body)
}
diff --git a/TalerWallet1/Views/Actions/Peer2peer/P2PSubjectV.swift
b/TalerWallet1/Views/Actions/Peer2peer/P2PSubjectV.swift
index 930fb2a..0c2f598 100644
--- a/TalerWallet1/Views/Actions/Peer2peer/P2PSubjectV.swift
+++ b/TalerWallet1/Views/Actions/Peer2peer/P2PSubjectV.swift
@@ -22,7 +22,7 @@ struct P2PSubjectV: View {
private let symLog = SymLogV(0)
let stack: CallStack
let scope: ScopeInfo
- let feeLabel: String?
+ let feeLabel: (String, String)?
let feeIsNotZero: Bool? // nil = no fees at all, false = no
fee for this tx
let outgoing: Bool
@Binding var amountToTransfer: Amount
@@ -34,25 +34,37 @@ struct P2PSubjectV: View {
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
@AppStorage("minimalistic") var minimalistic: Bool = false
- @State private var myFeeLabel: String = EMPTYSTRING
+ @State private var myFeeLabel: (String, String) = (EMPTYSTRING,
EMPTYSTRING)
@State private var transactionStarted: Bool = false
@FocusState private var isFocused: Bool
- private func buttonTitle(_ amount: Amount) -> String {
+ private func sendTitle(_ amountWithCurrency: String) -> String {
+ String(localized: "Send \(amountWithCurrency) now",
+ comment: "amount with currency")
+ }
+ private func requTitle(_ amountWithCurrency: String) -> String {
+ String(localized: "Request \(amountWithCurrency)",
+ comment: "amount with currency")
+ }
+
+ private func buttonTitle(_ amount: Amount) -> (String, String) {
let amountWithCurrency = amount.formatted(scope, isNegative: false,
useISO: true)
- return outgoing ? String(localized: "Send \(amountWithCurrency) now",
- comment: "amount with currency")
- : String(localized: "Request \(amountWithCurrency)",
- comment: "amount with currency")
+ return outgoing ? (sendTitle(amountWithCurrency.0),
sendTitle(amountWithCurrency.1))
+ : (requTitle(amountWithCurrency.0),
requTitle(amountWithCurrency.1))
+ }
+
+ private var placeHolder: String {
+ return outgoing ? String(localized: "Sent with GNU TALER")
+ : String(localized: "Requested with GNU TALER")
}
private func subjectTitle(_ amount: Amount) -> String {
let amountStr = amount.formatted(scope, isNegative: false)
return outgoing ? String(localized: "NavTitle_Send_AmountStr",
- defaultValue: "Send \(amountStr)",
+ defaultValue: "Send \(amountStr.0)",
comment: "NavTitle: Send 'amountStr'")
: String(localized: "NavTitle_Request_AmountStr",
- defaultValue: "Request \(amountStr)",
+ defaultValue: "Request \(amountStr.0)",
comment: "NavTitle: Request 'amountStr'")
}
@@ -62,8 +74,9 @@ struct P2PSubjectV: View {
if let ppCheck = try? await
model.checkPeerPushDebit(amountToTransfer, scope: scope) {
if let feeAmount = p2pFee(ppCheck: ppCheck) {
let feeStr = feeAmount.formatted(scope, isNegative: false)
- myFeeLabel = String(localized: "+ \(feeStr) fee")
- } else { myFeeLabel = EMPTYSTRING }
+ myFeeLabel = (String(localized: "+ \(feeStr.0) fee"),
+ String(localized: "+ \(feeStr.1) fee"))
+ } else { myFeeLabel = (EMPTYSTRING, EMPTYSTRING) }
} else {
print("❗️ checkPeerPushDebitM failed")
@@ -79,78 +92,68 @@ struct P2PSubjectV: View {
ScrollView { VStack (alignment: .leading, spacing: 6) {
if let feeIsNotZero { // don't show fee if nil
let label = feeLabel ?? myFeeLabel
- if label.count > 0 {
- Text(label)
+ if label.0.count > 0 {
+ Text(label.0)
+ .accessibilityLabel(label.1)
.frame(maxWidth: .infinity, alignment: .trailing)
.foregroundColor(WalletColors().secondary(colorScheme,
colorSchemeContrast))
.talerFont(.body)
}
}
- if !minimalistic {
- Text("Enter subject:") // Purpose
- .talerFont(.title3)
- .accessibilityAddTraits(.isHeader)
- .accessibilityRemoveTraits(.isStaticText)
- .padding(.top)
+ let enterSubject = String(localized: "Enter subject")
+ let enterColon = String("\(enterSubject):")
+ if !minimalistic {
+ Text(enterSubject) // Purpose
+ .talerFont(.title3)
+ .accessibilityHidden(true)
+ .padding(.top)
+ }
+ Group { if #available(iOS 16.0, *) {
+ TextField(placeHolder, text: $summary, axis: .vertical)
+ } else {
+ TextField(placeHolder, text: $summary)
+ } }
+ .talerFont(.title2)
+ .accessibilityLabel(enterColon)
+ .submitLabel(.next)
+ .focused($isFocused)
+ .onChange(of: summary) { newValue in
+ guard isFocused else { return }
+ guard newValue.contains("\n") else { return }
+ isFocused = false
+ summary = newValue.replacingOccurrences(of: LINEFEED,
with: EMPTYSTRING)
}
- Group { if #available(iOS 16.0, *) {
- TextField(minimalistic ? "Subject" : EMPTYSTRING, text:
$summary, axis: .vertical)
- .submitLabel(.next)
- .focused($isFocused)
- .onChange(of: summary) { newValue in
- guard isFocused else { return }
- guard newValue.contains(LINEFEED) else { return }
- isFocused = false
- summary = newValue.replacing(LINEFEED, with:
EMPTYSTRING)
- }
- } else {
- TextField("Subject", text: $summary)
- .submitLabel(.next)
- .focused($isFocused)
- .onChange(of: summary) { newValue in
- guard isFocused else { return }
- guard newValue.contains("\n") else { return }
- isFocused = false
- summary = newValue.replacingOccurrences(of:
LINEFEED, with: EMPTYSTRING)
- }
- } } // Group for iOS16+ & iOS15
- .talerFont(.title2)
- .foregroundColor(WalletColors().fieldForeground) //
text color
- .background(WalletColors().fieldBackground)
- .textFieldStyle(.roundedBorder)
- .onAppear {
- if !UIAccessibility.isVoiceOverRunning {
- symLog.log("dispatching kbd...")
- DispatchQueue.main.asyncAfter(deadline: .now() +
0.7) {
- isFocused = true // make first
responder - raise keybord
- symLog.log("...kbd isFocused")
- }
- }
- }
- Text(verbatim: "\(summary.count)/100")
// maximum 100 characters
- .frame(maxWidth: .infinity, alignment: .trailing)
- .talerFont(.body)
- .accessibilityValue(String(localized: "\(summary.count)
characters of 100"))
+ .foregroundColor(WalletColors().fieldForeground) // text
color
+ .background(WalletColors().fieldBackground)
+ .textFieldStyle(.roundedBorder)
+ Text(verbatim: "\(summary.count)/100") //
maximum 100 characters
+ .frame(maxWidth: .infinity, alignment: .trailing)
+ .talerFont(.body)
+ .accessibilityLabel(EMPTYSTRING)
+ .accessibilityValue(String(localized: "\(summary.count)
characters of 100"))
// TODO: compute max Expiration day from peerPushCheck to
disable 30 (and even 7)
SelectDays(selected: $expireDays, maxExpiration: THIRTYDAYS,
outgoing: outgoing)
.disabled(false)
.padding(.bottom)
- let disabled = (expireDays == 0) || (summary.count < 1) //
TODO: check amountAvailable
+ let disabled = (expireDays == 0) // || (summary.count < 1)
// TODO: check amountAvailable
let destination = P2PReadyV(stack: stack.push(),
scope: scope,
- summary: summary,
+ summary: summary.count > 0 ? summary :
placeHolder,
expireDays: expireDays,
outgoing: outgoing,
amountToTransfer: amountToTransfer,
transactionStarted: $transactionStarted)
NavigationLink(destination: destination) {
- Text(buttonTitle(amountToTransfer))
+ let buttonTitle = buttonTitle(amountToTransfer)
+ Text(buttonTitle.0)
+ .accessibilityLabel(buttonTitle.1)
}
.buttonStyle(TalerButtonStyle(type: .prominent, disabled:
disabled))
.disabled(disabled)
- .accessibilityHint(disabled ? String(localized: "enabled when
subject and expiration are set") : EMPTYSTRING)
+ .accessibilityHint(disabled ? String(localized: "enabled when
subject and expiration are set", comment: "VoiceOver")
+ : EMPTYSTRING)
}.padding(.horizontal) } // ScrollVStack
// .scrollBounceBehavior(.basedOnSize) needs iOS 16.4
.navigationTitle(subjectTitle(amountToTransfer))
diff --git a/TalerWallet1/Views/Actions/Peer2peer/RequestPayment.swift
b/TalerWallet1/Views/Actions/Peer2peer/RequestPayment.swift
index 0fbdea5..a0e4f50 100644
--- a/TalerWallet1/Views/Actions/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Actions/Peer2peer/RequestPayment.swift
@@ -36,7 +36,7 @@ struct RequestPayment: View {
}
private func navTitle(_ currency: String, _ condition: Bool = false) ->
String {
- condition ? String(localized: "NavTitle_Request_Currency)",
+ condition ? String(localized: "NavTitle_Request_Currency",
defaultValue: "Request \(currency)",
comment: "NavTitle: Request 'currency'")
: String(localized: "NavTitle_Request",
@@ -118,7 +118,7 @@ struct RequestPaymentContent: View {
@State private var peerPullCheck: CheckPeerPullCreditResponse? = nil
@State private var expireDays: UInt = 0
// @State private var feeAmount: Amount? = nil
- @State private var feeStr: String = EMPTYSTRING
+ @State private var feeString = (EMPTYSTRING, EMPTYSTRING)
@State private var buttonSelected = false
@State private var shortcutSelected = false
@State private var amountShortcut = Amount.zero(currency: EMPTYSTRING)
// Update currency when used
@@ -131,9 +131,9 @@ struct RequestPaymentContent: View {
}
private func buttonAction() { buttonSelected = true }
- private func feeLabel(_ feeString: String) -> String {
- feeString.count > 0 ? String(localized: "- \(feeString) fee")
- : EMPTYSTRING
+ private func feeLabel(_ feeStr: String) -> String {
+ feeStr.count > 0 ? String(localized: "- \(feeStr) fee")
+ : EMPTYSTRING
}
private func fee(raw: Amount, effective: Amount) -> Amount? {
@@ -169,16 +169,16 @@ struct RequestPaymentContent: View {
let raw = ppCheck.amountRaw
let effective = ppCheck.amountEffective
if let fee = fee(raw: raw, effective: effective) {
- feeStr = fee.formatted(balance.scopeInfo, isNegative: true)
- symLog.log("Fee = \(feeStr)")
-
+ feeString = fee.formatted(balance.scopeInfo, isNegative:
false)
+ symLog.log("Fee = \(feeString.0)")
+
peerPullCheck = ppCheck
- let feeLabel = feeLabel(feeStr)
+ let feeLabel = (feeLabel(feeString.0),
feeLabel(feeString.1))
// announce("\(amountVoiceOver), \(feeLabel)")
return ComputeFeeResult(insufficient: false,
- feeAmount: fee,
- feeStr: feeLabel,
- numCoins: ppCheck.numCoins)
+ feeAmount: fee,
+ feeStr: feeLabel,
// TODO: feeLabelA11y
+ numCoins: ppCheck.numCoins)
} else {
peerPullCheck = nil
}
diff --git a/TalerWallet1/Views/Actions/Peer2peer/SendAmountView.swift
b/TalerWallet1/Views/Actions/Peer2peer/SendAmountView.swift
index 897e0b1..e6b3d60 100644
--- a/TalerWallet1/Views/Actions/Peer2peer/SendAmountView.swift
+++ b/TalerWallet1/Views/Actions/Peer2peer/SendAmountView.swift
@@ -27,7 +27,7 @@ struct SendAmountView: View {
@State private var expireDays = SEVENDAYS
@State private var insufficient = false
// @State private var feeAmount: Amount? = nil
- @State private var feeStr: String = EMPTYSTRING
+ @State private var feeString = (EMPTYSTRING, EMPTYSTRING)
@State private var buttonSelected = false
@State private var shortcutSelected = false
@State private var amountShortcut = Amount.zero(currency: EMPTYSTRING)
// Update currency when used
@@ -48,9 +48,9 @@ struct SendAmountView: View {
comment: "NavTitle: Send")
}
- private func feeLabel(_ feeString: String) -> String {
- feeString.count > 0 ? String(localized: "+ \(feeString) fee")
- : EMPTYSTRING
+ private func feeLabel(_ feeStr: String) -> String {
+ feeStr.count > 0 ? String(localized: "+ \(feeStr) fee")
+ : EMPTYSTRING
}
private func fee(raw: Amount, effective: Amount) -> Amount? {
@@ -85,12 +85,12 @@ struct SendAmountView: View {
let raw = ppCheck.amountRaw
let effective = ppCheck.amountEffective
if let fee = fee(raw: raw, effective: effective) {
- feeStr = fee.formatted(balance.scopeInfo, isNegative:
false)
- symLog.log("Fee = \(feeStr)")
+ feeString = fee.formatted(balance.scopeInfo, isNegative:
false)
+ symLog.log("Fee = \(feeString.0)")
let insufficient = (try? effective > amountAvailable) ??
true
peerPushCheck = ppCheck
- let feeLabel = feeLabel(feeStr)
+ let feeLabel = (feeLabel(feeString.0),
feeLabel(feeString.1))
// announce("\(amountVoiceOver), \(feeLabel)")
return ComputeFeeResult(insufficient: insufficient,
feeAmount: fee,
@@ -142,7 +142,7 @@ struct SendAmountView: View {
let inputDestination = P2PSubjectV(stack: stack.push(),
scope: balance.scopeInfo,
- feeLabel: feeLabel(feeStr),
+ feeLabel:
(feeLabel(feeString.0), feeLabel(feeString.1)),
feeIsNotZero: feeIsNotZero(),
outgoing: true,
amountToTransfer: $amountToTransfer,
// from the textedit
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift
b/TalerWallet1/Views/HelperViews/AmountInputV.swift
index 6465ddc..d011457 100644
--- a/TalerWallet1/Views/HelperViews/AmountInputV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountInputV.swift
@@ -12,19 +12,19 @@ import SymLog
struct ComputeFeeResult {
let insufficient: Bool
let feeAmount: Amount?
- let feeStr: String
+ let feeStr: (String, String)
let numCoins: Int?
static func zero() -> ComputeFeeResult {
ComputeFeeResult(insufficient: false,
feeAmount: nil,
- feeStr: EMPTYSTRING,
+ feeStr: (EMPTYSTRING, EMPTYSTRING),
numCoins: 0)
}
static func insufficient() -> ComputeFeeResult {
ComputeFeeResult(insufficient: true,
feeAmount: nil,
- feeStr: EMPTYSTRING,
+ feeStr: (EMPTYSTRING, EMPTYSTRING),
numCoins: -1)
}
}
@@ -52,7 +52,7 @@ struct AmountInputV: View {
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
@State private var feeAmount: Amount? = nil
- @State private var feeStr: String = EMPTYSTRING
+ @State private var feeStr = (EMPTYSTRING, EMPTYSTRING)
@State private var numCoins: Int?
struct Flags {
diff --git a/TalerWallet1/Views/HelperViews/AmountV.swift
b/TalerWallet1/Views/HelperViews/AmountV.swift
index eaceca7..e87e353 100644
--- a/TalerWallet1/Views/HelperViews/AmountV.swift
+++ b/TalerWallet1/Views/HelperViews/AmountV.swift
@@ -16,7 +16,7 @@ struct AmountV: View {
let useISO: Bool
let strikethrough: Bool
let large: Bool // set to false for QR or IBAN
- let a11y: String?
+ let a11yDecSep: String?
@EnvironmentObject private var controller: Controller
@@ -35,30 +35,36 @@ struct AmountV: View {
}
}
- private func amountStr(_ currencyInfo : CurrencyInfo?) -> String {
+ private func amountStr(_ currencyInfo : CurrencyInfo?) -> (String, String)
{
let dontShow = (isNegative == nil)
let showSign: Bool = isNegative ?? false
- let amountFormatted: String
+ let readable = amount.readableDescription
+ let amountFormatted: (String, String)
if let currencyInfo {
amountFormatted = amount.formatted(currencyInfo, isNegative: false,
- useISO: useISO, a11y: a11y)
+ useISO: useISO, a11yDecSep:
a11yDecSep)
} else {
- amountFormatted = amount.readableDescription
+ amountFormatted = (readable, readable)
}
- let amountStr = dontShow ? amountFormatted
- : showSign ? "- \(amountFormatted)"
- : "+ \(amountFormatted)"
- return amountStr
+ let amountStr = dontShow ? amountFormatted.0
+ : showSign ? "- \(amountFormatted.0)"
+ : "+ \(amountFormatted.0)"
+ let amountA11y = dontShow ? amountFormatted.1
+ : showSign ? "- \(amountFormatted.1)"
+ : "+ \(amountFormatted.1)"
+
+ return (amountStr, amountA11y)
}
var body: some View {
- Text(amountStr(currencyInfo))
+ let amountTuple = amountStr(currencyInfo)
+ Text(amountTuple.0)
.strikethrough(strikethrough, color: WalletColors().attention)
.multilineTextAlignment(.center)
.talerFont(large ? .title : .title2)
// .fontWeight(large ? .medium : .regular) // @available(iOS
16.0, *)
.monospacedDigit()
- .accessibilityLabel(amount.readableDescription) // TODO:
locale.leadingCurrencySymbol
+ .accessibilityLabel(amountTuple.1) // TODO:
locale.leadingCurrencySymbol
.task(id: controller.currencyTicker) { await
currencyTickerChanged() }
// .onLongPressGesture(minimumDuration: 0.3) {
// showValue = true
@@ -78,7 +84,7 @@ extension AmountV {
self.useISO = false
self.strikethrough = false
self.large = false
- self.a11y = nil
+ self.a11yDecSep = nil
}
init(_ scope: ScopeInfo?, _ amount: Amount, isNegative: Bool?) {
self.stack = nil
@@ -88,7 +94,7 @@ extension AmountV {
self.useISO = false
self.strikethrough = false
self.large = false
- self.a11y = nil
+ self.a11yDecSep = nil
}
init(_ scope: ScopeInfo?, _ amount: Amount, isNegative: Bool?,
strikethrough: Bool) {
self.stack = nil
@@ -98,7 +104,7 @@ extension AmountV {
self.useISO = false
self.strikethrough = strikethrough
self.large = false
- self.a11y = nil
+ self.a11yDecSep = nil
}
init(stack: CallStack?, scope: ScopeInfo?, amount: Amount, isNegative:
Bool?,
strikethrough: Bool, large: Bool = false) {
@@ -109,7 +115,7 @@ extension AmountV {
self.useISO = false
self.strikethrough = strikethrough
self.large = false
- self.a11y = nil
+ self.a11yDecSep = nil
}
}
// MARK: -
diff --git a/TalerWallet1/Views/HelperViews/CurrencyField.swift
b/TalerWallet1/Views/HelperViews/CurrencyField.swift
index 04de5bd..14b97de 100644
--- a/TalerWallet1/Views/HelperViews/CurrencyField.swift
+++ b/TalerWallet1/Views/HelperViews/CurrencyField.swift
@@ -63,7 +63,9 @@ struct CurrencyField: View {
ZStack {
// Text view to display the formatted currency
// Set as priority so CurrencyInputField size doesn't affect parent
- let text = Text(amount.formatted(currencyInfo, isNegative: false))
+ let formatted = amount.formatted(currencyInfo, isNegative: false)
+ let text = Text(formatted.0)
+ .accessibilityLabel(formatted.1)
.layoutPriority(1)
// make the textfield use the whole width for tapping inside to
become active
.frame(maxWidth: .infinity, alignment: .trailing)
diff --git a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
index 698c874..48853d5 100644
--- a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
+++ b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
@@ -48,15 +48,16 @@ struct ShortcutButton: View {
let shortie = Amount(currency: currency, cent: UInt64(shortcut))
// TODO: adapt for ¥
let title = shortie.formatted(scope, isNegative: false)
let shortcutLabel = String(localized: "Shortcut", comment: "VoiceOver:
$50,$25,$10,$5 shortcut buttons")
+ let a11yLabel = "\(shortcutLabel) \(title.1)"
Button(action: { action(shortcut, currencyField)} ) {
- Text(title)
+ Text(title.0)
.lineLimit(1)
.talerFont(.callout)
}
// .frame(maxWidth: .infinity)
.disabled(isDisabled(shortie: shortie))
.buttonStyle(.bordered)
- .accessibilityLabel("\(shortcutLabel) \(title)")
+ .accessibilityLabel(a11yLabel)
}
}
// MARK: -
@@ -128,7 +129,8 @@ struct CurrencyInputView: View {
return title
}
if let available {
- return availableString(available.formatted(scope, isNegative:
false))
+ let formatted = available.formatted(scope, isNegative: false)
+ return availableString(formatted.0)
}
return nil
}
diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
index 39dceb5..3a936b3 100644
--- a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
+++ b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
@@ -25,17 +25,35 @@ struct QRCodeDetailView: View {
currencyInfo = controller.info(for: scope)
}
- private func amountStr(_ currencyInfo : CurrencyInfo?) -> String {
- let amountFormatted: String
+ private func amountStr(_ currencyInfo : CurrencyInfo?) -> (String, String)
{
+ let amountFormatted: (String, String)
+ let readable = amount.readableDescription
if let currencyInfo {
amountFormatted = amount.formatted(currencyInfo, isNegative: false,
- useISO: false, a11y: nil)
+ useISO: false, a11yDecSep: nil)
} else {
- amountFormatted = amount.readableDescription
+ amountFormatted = (readable, readable)
}
return amountFormatted
}
+ private func requesting(_ amountS: String) -> String {
+ minimalistic ? String(localized: "(payer) 1 mini",
+ defaultValue: "Requesting \(amountS)",
+ comment: "e.g. '5,3 €'")
+ : String(localized: "(payer) 1",
+ defaultValue: "To receive \(amountS), have the
payer scan this QR code to complete the payment.",
+ comment: "e.g. '5,3 €'")
+ }
+ private func sending(_ amountS: String) -> String {
+ minimalistic ? String(localized: "(payee) 1 mini",
+ defaultValue: "Sending \(amountS)",
+ comment: "e.g. '$ 7.41'")
+ : String(localized: "(payee) 1",
+ defaultValue: "To send \(amountS), let the payee
scan this QR code to accept/receive the payment.",
+ comment: "e.g. '$ 7.41'")
+ }
+
var body: some View {
if talerURI.count > 10 {
Section {
@@ -56,19 +74,10 @@ struct QRCodeDetailView: View {
.accessibilityLabel("QR Code")
.listRowSeparator(.hidden)
let amountStr = amountStr(currencyInfo)
- let scanLong = incoming ? (minimalistic ? String(localized:
"(payer) 1 mini",
- defaultValue:
"Requesting \(amountStr)",
- comment:
"e.g. '5,3 €'")
- : String(localized:
"(payer) 1",
- defaultValue:
"To receive \(amountStr), have the payer scan this QR code.",
- comment:
"e.g. '5,3 €'"))
- : (minimalistic ? String(localized:
"(payee) 1 mini",
- defaultValue:
"Sending \(amountStr)",
- comment:
"e.g. '$ 7.41'")
- : String(localized:
"(payee) 1",
- defaultValue:
"Sending \(amountStr) - let the payee scan this QR code to receive the
payment.",
- comment:
"e.g. '$ 7.41'"))
- Text(scanLong)
+ let scanLong = incoming ? (requesting(amountStr.0),
requesting(amountStr.1))
+ : (sending(amountStr.0),
sending(amountStr.1))
+ Text(scanLong.0)
+ .accessibilityLabel(scanLong.1)
.multilineTextAlignment(.leading)
.talerFont(.title3)
.listRowSeparator(.hidden)
diff --git a/TalerWallet1/Views/HelperViews/ScopePicker.swift
b/TalerWallet1/Views/HelperViews/ScopePicker.swift
index f67fed9..39e150a 100644
--- a/TalerWallet1/Views/HelperViews/ScopePicker.swift
+++ b/TalerWallet1/Views/HelperViews/ScopePicker.swift
@@ -8,7 +8,7 @@
import SwiftUI
import taler_swift
-fileprivate func formattedAmount(_ balance: Balance, _ currencyInfo:
CurrencyInfo) -> String {
+fileprivate func formattedAmount(_ balance: Balance, _ currencyInfo:
CurrencyInfo) -> (String, String) {
let amount = balance.available
return amount.formatted(currencyInfo, isNegative: false, useISO: false)
}
@@ -17,8 +17,11 @@ fileprivate func urlOrCurrency(_ balance: Balance) -> String
{
balance.scopeInfo.url?.trimURL ?? balance.scopeInfo.currency
}
-fileprivate func pickerRow(_ balance: Balance, _ currencyInfo: CurrencyInfo)
-> String {
- String("\(urlOrCurrency(balance)):\t\(formattedAmount(balance,
currencyInfo).nbs)")
+fileprivate func pickerRow(_ balance: Balance, _ currencyInfo: CurrencyInfo)
-> (String, String) {
+ let formatted = formattedAmount(balance, currencyInfo)
+ let urlOrCurrency = urlOrCurrency(balance)
+ return (String("\(urlOrCurrency):\t\(formatted.0.nbs)"),
+ String("\(urlOrCurrency): \(formatted.1)"))
}
struct ScopePicker: View {
@@ -40,12 +43,14 @@ struct ScopePicker: View {
let balance = controller.balances[selected]
let currencyInfo = controller.info(for: balance.scopeInfo,
controller.currencyTicker)
let available = balance.available
- let availableA11y = available.formatted(currencyInfo, isNegative:
false, useISO: true, a11y: ".")
+ let availableA11y = available.formatted(currencyInfo, isNegative:
false,
+ useISO: true, a11yDecSep:
".")
let url = balance.scopeInfo.url?.trimURL ?? EMPTYSTRING
// let a11yLabel = url + ", " + availableA11y
+ let choose = String(localized: "Choose the payment service.",
comment: "VoiceOver")
+ let disabled = (count == 1)
HStack(alignment: .firstTextBaseline) {
- let disabled = (count == 1)
Text("via", comment: "ScopePicker")
.accessibilityHidden(true)
.foregroundColor(disabled ? .secondary : .primary)
@@ -59,7 +64,9 @@ struct ScopePicker: View {
ForEach(0..<controller.balances.count, id: \.self) {
index in
let balance = controller.balances[index]
let currencyInfo = controller.info(for:
balance.scopeInfo, controller.currencyTicker)
- Text(pickerRow(balance, currencyInfo))
+ let pickerRow = pickerRow(balance, currencyInfo)
+ Text(pickerRow.0)
+ .accessibilityLabel(pickerRow.1)
.tag(index)
// .selectionDisabled(balance.available.isZero)
needs iOS 17
}
@@ -74,7 +81,7 @@ struct ScopePicker: View {
}
.talerFont(.picker)
// .accessibilityLabel(a11yLabel)
- .accessibilityHint(String(localized: "Choose the payment
service.", comment: "a11y"))
+ .accessibilityHint(disabled ? EMPTYSTRING : choose)
.task() {
withAnimation { selected = value }
}
@@ -108,12 +115,14 @@ struct ScopeDropDown: View {
func dropDownRow(_ balance: Balance, _ currencyInfo: CurrencyInfo, _
first: Bool = false) -> some View {
let urlOrCurrency = urlOrCurrency(balance)
let text = Text(urlOrCurrency)
- let amount = Text(formattedAmount(balance, currencyInfo).nbs)
- let a11yAmount = balance.available.readableDescription
+ let formatted = formattedAmount(balance, currencyInfo)
+ let amount = Text(formatted.0.nbs)
if first {
+ let a11yLabel = String(localized: "via \(urlOrCurrency)", comment:
"VoiceOver")
text
- .accessibilityLabel("via \(urlOrCurrency)")
+ .accessibilityLabel(a11yLabel)
} else {
+ let a11yLabel = "\(urlOrCurrency), \(formatted.1)"
let hLayout = HStack(alignment: .firstTextBaseline) {
text
Spacer()
@@ -132,7 +141,7 @@ struct ScopeDropDown: View {
vLayout
}
.accessibilityElement(children: .combine)
- .accessibilityLabel("\(urlOrCurrency), \(a11yAmount)")
+ .accessibilityLabel(a11yLabel)
}
}
@@ -161,7 +170,7 @@ struct ScopeDropDown: View {
chevron.foregroundColor(.clear)
.accessibilityHidden(true)
}
- }) // .accessibilityElement(children: .combine)
+ })
.disabled(rowDisabled)
.padding(.horizontal, radius / 2)
.frame(maxWidth: .infinity, alignment: .leading)
@@ -172,21 +181,25 @@ struct ScopeDropDown: View {
let balance = controller.balances[selection]
let currencyInfo = controller.info(for: balance.scopeInfo,
controller.currencyTicker)
let noAmount = !showDropdown
- Button(action: buttonAction) {
- HStack(alignment: .firstTextBaseline) {
+ Group {
+ if disabled {
dropDownRow(balance, currencyInfo, noAmount)
- .accessibilityAddTraits(.isSelected)
- Spacer()
- if !disabled {
- chevron.rotationEffect(.degrees((showDropdown ?
-180 : 0)))
- .accessibilityHidden(true)
+ } else {
+ Button(action: buttonAction) {
+ HStack(alignment: .firstTextBaseline) {
+ dropDownRow(balance, currencyInfo, noAmount)
+ .accessibilityAddTraits(.isSelected)
+ Spacer()
+ chevron.rotationEffect(.degrees((showDropdown
? -180 : 0)))
+ .accessibilityHidden(true)
+ }
}
}
}
.padding(.vertical, 4)
.padding(.horizontal, radius / 2)
.frame(maxWidth: .infinity, alignment: .leading)
-// .border(.red)
+// .border(.red)
if (showDropdown) {
if #available(iOS 17.0, *) {
// let toomany = controller.balances.count >
maxItemDisplayed
diff --git
a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
index 3af6b79..24d39d3 100755
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -73,8 +73,8 @@ struct WithdrawURIView: View {
baseUrl:
exchange.exchangeBaseUrl,
scope:
nil) { // TODO: scope
let fee = try? details.amountRaw - details.amountEffective
- let feeStr = fee?.formatted(currencyInfo, isNegative: true) ??
"nix"
- symLog.log("Fee = \(feeStr)")
+ let feeStr = fee?.formatted(currencyInfo, isNegative: true) ??
("0", "0")
+ symLog.log("Fee = \(feeStr.0)")
let insufficient = if let amountAvailable {
(try? details.amountRaw < amountAvailable) ?? true
} else {
@@ -82,7 +82,8 @@ struct WithdrawURIView: View {
}
withdrawalDetails = details
return ComputeFeeResult(insufficient: insufficient, feeAmount:
fee,
- feeStr: feeLabel(feeStr), numCoins:
details.numCoins)
+ feeStr: (feeLabel(feeStr.0),
feeLabel(feeStr.1)),
+ numCoins: details.numCoins)
}
} else {
symLog.log("No exchange!")
diff --git a/TalerWallet1/Views/Transactions/ManualDetailsV.swift
b/TalerWallet1/Views/Transactions/ManualDetailsV.swift
index ca00912..ae5ddd8 100644
--- a/TalerWallet1/Views/Transactions/ManualDetailsV.swift
+++ b/TalerWallet1/Views/Transactions/ManualDetailsV.swift
@@ -38,12 +38,14 @@ struct SegmentControl: View {
let detail = accountDetails[index]
let specs = detail.currencySpecification
let amount = detail.transferAmount
- let amountStr = amount?.formatted(specs: specs,
isNegative: false, useISO: false) ?? EMPTYSTRING
+ let formatted = amount?.formatted(specs: specs,
isNegative: false, useISO: false)
+ ?? (EMPTYSTRING, EMPTYSTRING)
let bankName = detail.bankLabel
- let a11yLabel = bankName != nil ? (bankName! + SPACE +
amountStr) : amountStr
+ let a11yLabel = bankName != nil ? (bankName! + SPACE +
formatted.1)
+ : formatted.1
// let _ = print(amountStr)
VStack(spacing: 6) {
- Text(amountStr)
+ Text(formatted.0)
.talerFont(.title3)
if let bankName {
Text(bankName)
@@ -94,10 +96,12 @@ struct AccountPicker: View {
isNegative: false, useISO:
false)
// let _ = print(amountStr)
if let bankName = detail.bankLabel {
- Text(bankName + ": " + amountStr)
+ Text(bankName + ": " + amountStr.0)
+ .accessibilityLabel(bankName + ": " +
amountStr.1)
.tag(index)
} else {
- Text(amountStr)
+ Text(amountStr.0)
+ .accessibilityLabel(amountStr.1)
.tag(index)
}
}
@@ -177,7 +181,8 @@ struct ManualDetailsV: View {
}
} else if let amount = account.transferAmount {
if let bankName = account.bankLabel {
- Text(bankName + ": " + amountStr)
+ Text(bankName + ": " + amountStr.0)
+ .accessibilityLabel(bankName + ": " +
amountStr.1)
// } else {
// Text(amountStr)
}
diff --git a/TalerWallet1/Views/Transactions/ManualDetailsWireV.swift
b/TalerWallet1/Views/Transactions/ManualDetailsWireV.swift
index 21f3511..ae3469e 100644
--- a/TalerWallet1/Views/Transactions/ManualDetailsWireV.swift
+++ b/TalerWallet1/Views/Transactions/ManualDetailsWireV.swift
@@ -10,20 +10,30 @@ import OrderedCollections
import taler_swift
struct TransferRestrictionsV: View {
- let amountStr: String
- let obtainStr: String
+ let amountStr: (String, String)
+ let obtainStr: (String, String)
let restrictions: [AccountRestriction]?
@AppStorage("minimalistic") var minimalistic: Bool = false
@State private var selectedLanguage = Locale.preferredLanguageCode
+ private func transferMini(_ amountS: String) -> String {
+ let amountNBS = amountS.nbs
+ return String(localized: "Transfer \(amountNBS) to the payment
service.")
+ }
+ private func transferMaxi(_ amountS: String, _ obtainS: String) -> String {
+ let amountNBS = amountS.nbs
+ let obtainNBS = obtainS.nbs
+ return String(localized: "You need to transfer \(amountNBS) from your
regular bank account to the payment service to receive \(obtainNBS) as
electronic cash in this wallet.")
+ }
+
var body: some View {
VStack(alignment: .leading) {
- let amountNBS = amountStr.nbs
- let obtainNBS = obtainStr.nbs
- Text(minimalistic ? "Transfer \(amountNBS) to the payment service."
- : "You need to transfer \(amountNBS) from your regular bank
account to the payment service to receive \(obtainNBS) as electronic cash in
this wallet.")
+ Text(minimalistic ? transferMini(amountStr.0)
+ : transferMaxi(amountStr.0, obtainStr.0))
+ .accessibilityLabel(minimalistic ? transferMini(amountStr.1)
+ : transferMaxi(amountStr.1,
obtainStr.1))
.talerFont(.body)
.multilineTextAlignment(.leading)
if let restrictions {
@@ -53,13 +63,19 @@ struct ManualDetailsWireV: View {
let iban: String?
let xTaler: String
let amountValue: String // string representation of the value,
formatted as "`integer`.`fraction`"
- let amountStr: String
- let obtainStr: String
+ let amountStr: (String, String)
+ let obtainStr: (String, String)
let account: WithdrawalExchangeAccountDetails
@AppStorage("minimalistic") var minimalistic: Bool = false
let navTitle = String(localized: "Wire transfer", comment: "ViewTitle of
wire-transfer instructions")
+ private func step3(_ amountS: String) -> String {
+ let amountNBS = amountS.nbs
+ return minimalistic ? String(localized: "Transfer \(amountNBS).")
+ : String(localized: "Finish the wire transfer of
\(amountNBS) in your banking app or website, then this withdrawal will proceed
automatically. Depending on your bank the transfer can take from minutes to two
working days, please be patient.")
+ }
+
var body: some View {
List {
let cryptocode = HStack {
@@ -103,7 +119,8 @@ struct ManualDetailsWireV: View {
VStack(alignment: .leading) {
Text("Amount:")
.talerFont(.subheadline)
- Text(amountStr)
+ Text(amountStr.0)
+ .accessibilityLabel(amountStr.1)
.monospacedDigit()
.padding(.leading)
} .frame(maxWidth: .infinity, alignment: .leading)
@@ -146,9 +163,11 @@ struct ManualDetailsWireV: View {
.talerFont(.body)
.multilineTextAlignment(.leading)
.padding(.top)
- let amountNBS = amountStr.nbs
- let step3 = Text(minimalistic ? "**Step 3:** Transfer
\(amountNBS)."
- : "**Step 3:** Finish the wire transfer of
\(amountNBS) in your banking app or website, then this withdrawal will proceed
automatically. Depending on your bank the transfer can take from minutes to two
working days, please be patient.")
+ let step3A11y = step3(amountStr.1)
+ let step3Str = step3(amountStr.0)
+ let step3Head = String(localized: "**Step 3:**")
+ let step3 = Text(step3Head + step3Str)
+ .accessibilityLabel(step3Head + step3A11y)
.talerFont(.body)
.multilineTextAlignment(.leading)
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] 167/204: badge + a11y, (continued)
- [taler-taler-ios] 167/204: badge + a11y, gnunet, 2024/12/05
- [taler-taler-ios] 166/204: BankListView, gnunet, 2024/12/05
- [taler-taler-ios] 185/204: A11y textfield label, gnunet, 2024/12/05
- [taler-taler-ios] 187/204: A11y, gnunet, 2024/12/05
- [taler-taler-ios] 186/204: bounce, gnunet, 2024/12/05
- [taler-taler-ios] 204/204: Bump version to 0.14.0 (0.13.14), gnunet, 2024/12/05
- [taler-taler-ios] 197/204: L10n, gnunet, 2024/12/05
- [taler-taler-ios] 201/204: pop-to-root on second tap, gnunet, 2024/12/05
- [taler-taler-ios] 200/204: reloadTransactions, gnunet, 2024/12/05
- [taler-taler-ios] 202/204: bank accounts - w.i.p., gnunet, 2024/12/05
- [taler-taler-ios] 199/204: A11y as tupel,
gnunet <=
- [taler-taler-ios] 203/204: German localization, gnunet, 2024/12/05