commit 467f10e6570b141af7ccda2da18a5120f48842e1
parent aa1996a6cfde4faf88877407aa4092b3d18784bc
Author: Marc Stibane <marc@taler.net>
Date: Fri, 26 Jun 2026 08:36:52 +0200
improve V1 and V0
Diffstat:
6 files changed, 68 insertions(+), 28 deletions(-)
diff --git a/TalerWallet1/Model/Model+Payment.swift b/TalerWallet1/Model/Model+Payment.swift
@@ -190,9 +190,7 @@ struct MerchantContractTerms: Codable {
let defaultMoneyPot: Int?
-// deprecated let wireFeeAmortization: Int? // Share of the wire fee that must be settled with one payment
-// let maxWireFee: Amount? // Maximum wire fee that the merchant agrees to pay for
-// let auditors: [Auditor]?
+// deprecated let auditors: [Auditor]?
// ContractTermsV1
let choices: [ContractChoice]?
@@ -232,8 +230,6 @@ struct MerchantContractTerms: Codable {
case minimumAge = "minimum_age"
case defaultMoneyPot = "default_money_pot"
-// case wireFeeAmortization = "wire_fee_amortization"
-// case maxWireFee = "max_wire_fee"
// case auditors
case choices
case tokenFamilies = "token_families"
diff --git a/TalerWallet1/Resources/Localizable.xcstrings b/TalerWallet1/Resources/Localizable.xcstrings
@@ -10049,6 +10049,7 @@
},
"No description" : {
"comment" : "contractChoice.description",
+ "extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
diff --git a/TalerWallet1/Views/Sheets/Payment/ChoicesView.swift b/TalerWallet1/Views/Sheets/Payment/ChoicesView.swift
@@ -13,6 +13,7 @@ typealias ChoiceTriple = (ChoiceSelectionDetail, ContractChoice, Int)
struct ChoicesView: View, Sendable {
let stack: CallStack
let choiceTriple: [ChoiceTriple]
+ let showHeader: Bool
let automaticIndex: Int?
@Binding var selectedChoice: Int
@@ -31,7 +32,7 @@ struct ChoicesView: View, Sendable {
.foregroundColor(Color.clear)
}
}
- func description(_ contractChoice: ContractChoice) -> String {
+ func description(_ contractChoice: ContractChoice) -> String? {
if let i18nDict = contractChoice.descriptionI18n {
if !i18nDict.isEmpty {
for code in Locale.preferredLanguageCodes {
@@ -44,7 +45,7 @@ struct ChoicesView: View, Sendable {
if let desc = contractChoice.description {
return desc
}
- return String(localized: "No description", comment: "contractChoice.description")
+ return nil
}
var body: some View {
@@ -60,8 +61,7 @@ struct ChoicesView: View, Sendable {
/// If it only contains tokens, and insufficient, then hide it. Most probably there is a money payment option to acquire those tokens, which is advertisement enough.
/// Tokens only, paymentPossible. If automaticIndex, then also hide it (and auto-pay it). Otherwise show it, so the user can select it.
if (!amount.isZero || isPaymentPossible) && !payAutomatic {
- let description = description(contractChoice)
- Section(header: Text(description)) {
+ Section {
let amountV = HStack {
Spacer()
AmountV(stack: stack.push(),
@@ -84,7 +84,11 @@ struct ChoicesView: View, Sendable {
} else {
amountV
}
- }
+ } header: {
+ if showHeader {
+ if let description = description(contractChoice) {
+ Text(description)
+ } } }
}
}
}
diff --git a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift
@@ -311,8 +311,6 @@ struct PaymentURIView_Previews: PreviewProvider {
publicReorderURL: "publicReorderURL",
fulfillmentMessage: nil,
fulfillmentMessageI18n: nil,
- wireFeeAmortization: 0,
- maxWireFee: Amount(currency: LONGCURRENCY, cent: 20),
minimumAge: nil
// extra: extra,
// auditors: []
diff --git a/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift b/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift
@@ -29,14 +29,14 @@ struct ThreeAmountsSheet: View { // should be in a separate file
#endif
var body: some View {
- let raw = common.amountRaw
- let effective = common.amountEffective
- let fee = common.fee()
let incoming = common.isIncoming
let pending = common.isPending || common.isFinalizing
let dialog = common.isDialog
let isDone = common.isDone
- let incomplete = !(isDone || pending)
+ let incomplete = !(isDone || pending || dialog)
+ let raw = common.amountRaw
+ let effective: Amount? = incomplete ? nil : common.amountEffective
+ let fee: Amount? = incomplete ? nil : common.fee()
let defaultBottomTitle = incoming ? (pending ? String(localized: "Pending amount to obtain:")
: String(localized: "Obtained amount:") )
@@ -59,7 +59,7 @@ struct ThreeAmountsSheet: View { // should be in a separate file
feeIsNegative: feeIsNegative,
bottomTitle: bottomTitle ?? defaultBottomTitle,
bottomAbbrev: bottomAbbrev ?? defaultBottomAbbrev,
- bottomAmount: incomplete ? nil : effective,
+ bottomAmount: effective,
large: large,
pendingDialog: pending || dialog,
isDone: isDone,
@@ -196,7 +196,7 @@ struct ThreeAmountsSection: View {
color: labelColor,
large: false)
.padding(.bottom, 4)
- if hasNoFees == false {
+ if hasNoFees == false { // otherwise raw==effective
if let fee {
let title = minimalistic ? String(localized: "Exchange fee (short):", defaultValue: "Fee:", comment: "short version")
: String(localized: "Exchange fee (long):", defaultValue: "Fee:", comment: "long version")
diff --git a/TalerWallet1/Views/Transactions/TransactionSummaryList.swift b/TalerWallet1/Views/Transactions/TransactionSummaryList.swift
@@ -28,21 +28,47 @@ extension TalerTransaction { // for Dummys
struct MerchantHeader: View {
let terms: MerchantContractTerms?
+ func summary(_ terms: MerchantContractTerms) -> String {
+ if let i18nDict = terms.summaryI18n {
+ if !i18nDict.isEmpty {
+ for code in Locale.preferredLanguageCodes {
+ if let descI18n = i18nDict[code] {
+ return descI18n
+ }
+ }
+ }
+ }
+ return terms.summary
+ }
+
var body: some View {
if let terms {
Section {
- Text(terms.summary)
+ Text(summary(terms))
.talerFont(.title3)
} header: {
HStack {
Spacer()
VStack(alignment: .center) {
+ if let imageBase64 = terms.merchant.logo {
+ if let url = NSURL(string: imageBase64) {
+ if let data = NSData(contentsOf: url as URL) {
+ if let uiImage = UIImage(data: data as Data) {
+ Image(uiImage: uiImage)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(maxHeight: 60)
+ }
+ }
+ }
+ } else {
#if TALER_NIGHTLY
- let imageName = if #available(iOS 17.0, *) { MERCHANT17 } else { MERCHANT14 }
- Image(systemName: imageName)
- .resizable()
- .frame(width: 44, height: 44)
+ let imageName = if #available(iOS 17.0, *) { MERCHANT17 } else { MERCHANT14 }
+ Image(systemName: imageName)
+ .resizable()
+ .frame(width: 44, height: 44)
#endif
+ }
let merchant = terms.merchant.name
Text(merchant)
.talerFont(.title3)
@@ -70,11 +96,25 @@ struct PaymentTransactionView: View {
// @State var isLoadingChoices: Bool? = nil
@MainActor
- func choiceTriple() -> [ChoiceTriple]? {
+ func choiceTriple() -> ([ChoiceTriple], Bool)? {
if let choicesForPayment {
- if let ctChoices = choicesForPayment.contractTerms.choices {
- let combined = Array(zip(choicesForPayment.choices, ctChoices, ctChoices.indices))
- return combined
+ let choices = choicesForPayment.choices
+ let terms = choicesForPayment.contractTerms
+ if let ctChoices = terms.choices {
+ let combined = Array(zip(choices, ctChoices, ctChoices.indices))
+ return (combined, true)
+ } else if let amount = terms.amount { // V0
+ let maxFee = terms.maxFee ?? Amount.zero(currency: amount.currencyStr)
+ let ctChoice = ContractChoice(amount: amount,
+ maxFee: maxFee,
+ description: terms.summary,
+ descriptionI18n: terms.summaryI18n,
+ inputs: [],
+ outputs: [])
+ let combined = Array(zip(choices, [ctChoice], [0]))
+ return (combined, false)
+ } else {
+ symLog.log(" ❗️Yikes, neither choices nor amount in contractTerms!\n\(stack)")
}
}
return nil
@@ -121,11 +161,12 @@ struct PaymentTransactionView: View {
if common.isDialog { // show payment confirmation dialog
MerchantHeader(terms: details.contractTerms)
- if let choices = choiceTriple() {
+ if let (choices, showHeader) = choiceTriple() {
let hasAutomatic = choicesForPayment?.automaticExecution ?? false
let automaticIndex = hasAutomatic ? choicesForPayment?.automaticExecutableIndex : nil
ChoicesView(stack: stack.push(),
choiceTriple: choices,
+ showHeader: showHeader,
automaticIndex: automaticIndex,
selectedChoice: $selectedChoice)
.onChange(of: selectedChoice) { newValue in