taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit 12c22a6d530641e19efb67ea719fd9b49170b6d5
parent 6e6f68033a8e428798d6f9e7e46354166862e3e9
Author: Marc Stibane <marc@taler.net>
Date:   Sat, 20 Jul 2024 19:07:29 +0200

ThreeAmountsSection

Diffstat:
MTalerWallet.xcodeproj/project.pbxproj | 12++++++------
MTalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift | 26+++++++++++++-------------
MTalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift | 26+++++++++++++-------------
MTalerWallet1/Views/Sheets/Payment/PaymentView.swift | 56++++++++++++++++++++++++++++++--------------------------
MTalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift | 26+++++++++++++-------------
ATalerWallet1/Views/Transactions/ThreeAmountsSection.swift | 189+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DTalerWallet1/Views/Transactions/ThreeAmountsV.swift | 185-------------------------------------------------------------------------------
7 files changed, 264 insertions(+), 256 deletions(-)

diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj @@ -101,7 +101,7 @@ 4E3EAE642A990778009F1BE8 /* LaunchAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB095432989CBFE0043A8A1 /* LaunchAnimationView.swift */; }; 4E3EAE682A990778009F1BE8 /* WalletModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB095112989CBB00043A8A1 /* WalletModel.swift */; }; 4E3EAE692A990778009F1BE8 /* URLSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB095332989CBFE0043A8A1 /* URLSheet.swift */; }; - 4E3EAE6A2A990778009F1BE8 /* ThreeAmountsV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift */; }; + 4E3EAE6A2A990778009F1BE8 /* ThreeAmountsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmountsSection.swift */; }; 4E3EAE6B2A990778009F1BE8 /* Model+Withdraw.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0953D2989CBFE0043A8A1 /* Model+Withdraw.swift */; }; 4E3EAE6C2A990778009F1BE8 /* ExchangeSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */; }; 4E3EAE6D2A990778009F1BE8 /* P2PSubjectV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E7940DD29FC307C00A9AEA1 /* P2PSubjectV.swift */; }; @@ -253,7 +253,7 @@ 4EC90C782A1B528B0071DC58 /* ExchangeSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */; }; 4ECB62802A0BA6DF004ABBB7 /* Model+P2P.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */; }; 4ECB62822A0BB01D004ABBB7 /* SelectDays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */; }; - 4ED2F94B2A278F5100453B40 /* ThreeAmountsV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift */; }; + 4ED2F94B2A278F5100453B40 /* ThreeAmountsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmountsSection.swift */; }; 4ED80E882B8F5FB8008BD576 /* CStringArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED80E872B8F5FB8008BD576 /* CStringArray.swift */; }; 4ED80E892B8F5FB8008BD576 /* CStringArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED80E872B8F5FB8008BD576 /* CStringArray.swift */; }; 4ED80E8B2B8F60E7008BD576 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED80E8A2B8F60E7008BD576 /* Atomic.swift */; }; @@ -465,7 +465,7 @@ 4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExchangeSectionView.swift; sourceTree = "<group>"; }; 4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Model+P2P.swift"; sourceTree = "<group>"; }; 4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectDays.swift; sourceTree = "<group>"; }; - 4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreeAmountsV.swift; sourceTree = "<group>"; }; + 4ED2F94A2A278F5100453B40 /* ThreeAmountsSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreeAmountsSection.swift; sourceTree = "<group>"; }; 4ED80E872B8F5FB8008BD576 /* CStringArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CStringArray.swift; sourceTree = "<group>"; }; 4ED80E8A2B8F60E7008BD576 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; }; 4ED80E8D2B8F6212008BD576 /* QuickDataTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickDataTask.swift; sourceTree = "<group>"; }; @@ -785,7 +785,7 @@ 4E6EF56D2B669C7000AF252A /* TransactionDetailV.swift */, 4E87C8722A31CB7F001C6406 /* TransactionsEmptyView.swift */, 4E6EDD842A3615BE0031D520 /* ManualDetailsV.swift */, - 4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift */, + 4ED2F94A2A278F5100453B40 /* ThreeAmountsSection.swift */, ); path = Transactions; sourceTree = "<group>"; @@ -1262,7 +1262,7 @@ E37AA62A2AF197E5003850CF /* Model+Refund.swift in Sources */, 4E3EAE682A990778009F1BE8 /* WalletModel.swift in Sources */, 4E3EAE692A990778009F1BE8 /* URLSheet.swift in Sources */, - 4E3EAE6A2A990778009F1BE8 /* ThreeAmountsV.swift in Sources */, + 4E3EAE6A2A990778009F1BE8 /* ThreeAmountsSection.swift in Sources */, 4E3EAE6B2A990778009F1BE8 /* Model+Withdraw.swift in Sources */, 4ED80E882B8F5FB8008BD576 /* CStringArray.swift in Sources */, 4E3EAE6C2A990778009F1BE8 /* ExchangeSectionView.swift in Sources */, @@ -1389,7 +1389,7 @@ E37AA62B2AF197E5003850CF /* Model+Refund.swift in Sources */, 4EB095162989CBB00043A8A1 /* WalletModel.swift in Sources */, 4EB0955A2989CBFE0043A8A1 /* URLSheet.swift in Sources */, - 4ED2F94B2A278F5100453B40 /* ThreeAmountsV.swift in Sources */, + 4ED2F94B2A278F5100453B40 /* ThreeAmountsSection.swift in Sources */, 4EB095622989CBFE0043A8A1 /* Model+Withdraw.swift in Sources */, 4ED80E892B8F5FB8008BD576 /* CStringArray.swift in Sources */, 4EC90C782A1B528B0071DC58 /* ExchangeSectionView.swift in Sources */, diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pPayURIView.swift @@ -31,19 +31,19 @@ struct P2pPayURIView: View { let effective = peerPullDebitResponse.amountEffective let currency = raw.currencyStr let fee = try! Amount.diff(raw, effective) - ThreeAmountsV(stack: stack.push(), - topTitle: String(localized: "Amount to pay:"), - topAbbrev: String(localized: "Pay:", comment: "mini"), - topAmount: raw, fee: fee, - bottomTitle: String(localized: "Amount to be spent:"), - bottomAbbrev: String(localized: "Effective:", comment: "mini"), - bottomAmount: effective, - large: false, pending: false, incoming: false, - baseURL: nil, - noFees: nil, // TODO: check baseURL for fees - txStateLcl: nil, - summary: peerPullDebitResponse.contractTerms.summary, - merchant: nil) + ThreeAmountsSection(stack: stack.push(), + topTitle: String(localized: "Amount to pay:"), + topAbbrev: String(localized: "Pay:", comment: "mini"), + topAmount: raw, fee: fee, + bottomTitle: String(localized: "Amount to be spent:"), + bottomAbbrev: String(localized: "Effective:", comment: "mini"), + bottomAmount: effective, + large: false, pending: false, incoming: false, + baseURL: nil, + noFees: nil, // TODO: check baseURL for fees + txStateLcl: nil, + summary: peerPullDebitResponse.contractTerms.summary, + merchant: nil) let expiration = peerPullDebitResponse.contractTerms.purse_expiration let (dateString, date) = TalerDater.dateString(from: expiration) let a11yDate = TalerDater.accessibilityDate(date) ?? dateString diff --git a/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift b/TalerWallet1/Views/Sheets/P2P_Sheets/P2pReceiveURIView.swift @@ -41,19 +41,19 @@ struct P2pReceiveURIView: View { let effective = peerPushCreditResponse.amountEffective let currency = raw.currencyStr let fee = try! Amount.diff(raw, effective) - ThreeAmountsV(stack: stack.push(), - topTitle: String(localized: "Gross Amount to receive:"), - topAbbrev: String(localized: "Receive gross:", comment: "mini"), - topAmount: raw, fee: fee, - bottomTitle: String(localized: "Net Amount to receive:"), - bottomAbbrev: String(localized: "Receive net:", comment: "mini"), - bottomAmount: effective, - large: false, pending: false, incoming: true, - baseURL: nil, - noFees: nil, // TODO: check baseURL for fees - txStateLcl: nil, - summary: peerPushCreditResponse.contractTerms.summary, - merchant: nil) + ThreeAmountsSection(stack: stack.push(), + topTitle: String(localized: "Gross Amount to receive:"), + topAbbrev: String(localized: "Receive gross:", comment: "mini"), + topAmount: raw, fee: fee, + bottomTitle: String(localized: "Net Amount to receive:"), + bottomAbbrev: String(localized: "Receive net:", comment: "mini"), + bottomAmount: effective, + large: false, pending: false, incoming: true, + baseURL: nil, + noFees: nil, // TODO: check baseURL for fees + txStateLcl: nil, + summary: peerPushCreditResponse.contractTerms.summary, + merchant: nil) let expiration = peerPushCreditResponse.contractTerms.purse_expiration let (dateString, date) = TalerDater.dateString(from: expiration) let a11yDate = TalerDater.accessibilityDate(date) ?? dateString diff --git a/TalerWallet1/Views/Sheets/Payment/PaymentView.swift b/TalerWallet1/Views/Sheets/Payment/PaymentView.swift @@ -102,36 +102,40 @@ struct PaymentView: View { if let effective { // TODO: already paid let fee = try! Amount.diff(raw, effective) // TODO: different currencies - ThreeAmountsV(stack: stack.push(), - topTitle: topTitle, - topAbbrev: topAbbrev, - topAmount: raw, fee: fee, - bottomTitle: String(localized: "Amount to spend:"), - bottomAbbrev: String(localized: "Effective:", comment: "mini"), - bottomAmount: effective, - large: false, pending: false, incoming: false, - baseURL: baseURL, - noFees: nil, // TODO: check baseURL for fees - txStateLcl: nil, - summary: terms.summary, - merchant: terms.merchant.name) + ThreeAmountsSection(stack: stack.push(), + topTitle: topTitle, + topAbbrev: topAbbrev, + topAmount: raw, fee: fee, + bottomTitle: String(localized: "Amount to spend:"), + bottomAbbrev: String(localized: "Effective:", comment: "mini"), + bottomAmount: effective, + large: false, + pending: false, + incoming: false, + baseURL: baseURL, + noFees: nil, // TODO: check baseURL for fees + txStateLcl: nil, + summary: terms.summary, + merchant: terms.merchant.name) // TODO: payment: popup with all possible exchanges, check fees } else if let balanceDetails = preparePayResult.balanceDetails { // Insufficient Text("You don't have enough \(currency).") .talerFont(.headline) - ThreeAmountsV(stack: stack.push(), - topTitle: topTitle, - topAbbrev: topAbbrev, - topAmount: raw, fee: nil, - bottomTitle: String(localized: "Amount available:"), - bottomAbbrev: String(localized: "Available:", comment: "mini"), - bottomAmount: balanceDetails.balanceAvailable, - large: false, pending: false, incoming: false, - baseURL: baseURL, - noFees: nil, // TODO: check baseURL for fees - txStateLcl: nil, - summary: terms.summary, - merchant: terms.merchant.name) + ThreeAmountsSection(stack: stack.push(), + topTitle: topTitle, + topAbbrev: topAbbrev, + topAmount: raw, fee: nil, + bottomTitle: String(localized: "Amount available:"), + bottomAbbrev: String(localized: "Available:", comment: "mini"), + bottomAmount: balanceDetails.balanceAvailable, + large: false, + pending: false, + incoming: false, + baseURL: baseURL, + noFees: nil, // TODO: check baseURL for fees + txStateLcl: nil, + summary: terms.summary, + merchant: terms.merchant.name) } else { // TODO: Error - neither effective nor balanceDetails Text("Error") diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift @@ -54,19 +54,19 @@ struct WithdrawAcceptView: View { let outColor = WalletColors().transactionColor(false) let inColor = WalletColors().transactionColor(true) - ThreeAmountsV(stack: stack.push(), - topTitle: String(localized: "Chosen amount to withdraw:"), - topAbbrev: String(localized: "Chosen:", comment: "mini"), - topAmount: raw, fee: fee, - bottomTitle: String(localized: "Amount to be withdrawn:"), - bottomAbbrev: String(localized: "Effective:", comment: "mini"), - bottomAmount: effective, - large: false, pending: false, incoming: true, - baseURL: exchange.exchangeBaseUrl, - noFees: exchange.noFees, - txStateLcl: nil, // common.txState.major.localizedState - summary: nil, - merchant: nil) + ThreeAmountsSection(stack: stack.push(), + topTitle: String(localized: "Chosen amount to withdraw:"), + topAbbrev: String(localized: "Chosen:", comment: "mini"), + topAmount: raw, fee: fee, + bottomTitle: String(localized: "Amount to be withdrawn:"), + bottomAbbrev: String(localized: "Effective:", comment: "mini"), + bottomAmount: effective, + large: false, pending: false, incoming: true, + baseURL: exchange.exchangeBaseUrl, + noFees: exchange.noFees, + txStateLcl: nil, // common.txState.major.localizedState + summary: nil, + merchant: nil) let coinData = CoinData(details: withdrawalAmountDetails) QuiteSomeCoins(currencyInfo: currencyInfo, currency: currency, diff --git a/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift b/TalerWallet1/Views/Transactions/ThreeAmountsSection.swift @@ -0,0 +1,189 @@ +/* + * This file is part of GNU Taler, ©2022-24 Taler Systems S.A. + * See LICENSE.md + */ +/** + * @author Marc Stibane + */ +import SwiftUI +import taler_swift + +struct ThreeAmountsSheet: View { + let stack: CallStack + var common: TransactionCommon + var topAbbrev: String + var topTitle: String + var bottomTitle: String? + var bottomAbbrev: String? + let baseURL: String? + let noFees: Bool? // true if exchange charges no fees at all + let large: Bool // set to false for QR or IBAN + 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 + let fee = common.fee() + let incoming = common.incoming() + let pending = common.isPending + let isDone = common.isDone + let incomplete = !(isDone || pending) + + let defaultBottomTitle = incoming ? (pending ? String(localized: "Pending amount to obtain:") + : String(localized: "Obtained amount:") ) + : (pending ? String(localized: "Amount to pay:") + : String(localized: "Paid amount:") ) + let defaultBottomAbbrev = incoming ? (pending ? String(localized: "Pending:", comment: "mini") + : 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 + ThreeAmountsSection(stack: stack.push(), + topTitle: topTitle, + topAbbrev: topAbbrev, + topAmount: raw, + fee: fee, + bottomTitle: bottomTitle ?? defaultBottomTitle, + bottomAbbrev: bottomAbbrev ?? defaultBottomAbbrev, + bottomAmount: incomplete ? nil : effective, + large: large, + pending: pending, + incoming: incoming, + baseURL: baseURL, + noFees: noFees, + txStateLcl: txStateLcl, + summary: summary, + merchant: merchant) + } +} +// MARK: - +struct ThreeAmountsSection: View { + let stack: CallStack + var topTitle: String + var topAbbrev: String + var topAmount: Amount + var fee: Amount? // nil = don't show fee line, zero = no fee for this tx + var bottomTitle: String + var bottomAbbrev: String + var bottomAmount: Amount? // nil = incomplete (aborted, timed out) + let large: Bool + let pending: Bool + let incoming: Bool + let baseURL: String? + let noFees: Bool? // true if exchange charges no fees at all + let txStateLcl: String? // localizedState + let summary: String? + let merchant: String? + + @Environment(\.colorScheme) private var colorScheme + @Environment(\.colorSchemeContrast) private var colorSchemeContrast + @AppStorage("minimalistic") var minimalistic: Bool = false + + var body: some View { + let labelColor = WalletColors().labelColor + let foreColor = pending ? WalletColors().pendingColor(incoming) + : WalletColors().transactionColor(incoming) + let hasNoFees = noFees ?? false + Section { + if let summary { + Text(summary) + .talerFont(.title3) + .lineLimit(4) + .padding(.bottom) + } + if let merchant { + Text(merchant) + .talerFont(.title3) + .lineLimit(4) + .padding(.bottom) + } + AmountRowV(stack: stack.push(), + title: minimalistic ? topAbbrev : topTitle, + amount: topAmount, + isNegative: !incoming, + color: labelColor, + large: false) + .padding(.bottom, 4) + if hasNoFees == false { + 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") + AmountRowV(stack: stack.push(), + title: title, + amount: fee, + isNegative: !incoming, + color: labelColor, + large: false) + .padding(.bottom, 4) + } + if let bottomAmount { + AmountRowV(stack: stack.push(), + title: minimalistic ? bottomAbbrev : bottomTitle, + amount: bottomAmount, + isNegative: !incoming, + color: foreColor, + large: large) + } + } + if let baseURL { + VStack(alignment: .leading) { + // TODO: "Issued by" for withdrawals + Text(minimalistic ? "Payment provider:" : "Using payment service provider:") + .multilineTextAlignment(.leading) + .talerFont(.body) + Text(baseURL.trimURL()) + .frame(maxWidth: .infinity, alignment: .trailing) + .multilineTextAlignment(.center) + .talerFont(large ? .title3 : .body) +// .fontWeight(large ? .medium : .regular) // @available(iOS 16.0, *) + .foregroundColor(labelColor) + } + .padding(.top, 4) + .frame(maxWidth: .infinity, alignment: .leading) + .listRowSeparator(.hidden) + .accessibilityElement(children: .combine) + } + } header: { + if !minimalistic { + Text("Summary") + .talerFont(.title3) + .foregroundColor(WalletColors().secondary(colorScheme, colorSchemeContrast)) + } + } + } +} +// MARK: - +struct ThreeAmounts_Previews: PreviewProvider { + static var previews: some View { + let common = TransactionCommon(type: .withdrawal, + txState: TransactionState(major: .done), + amountEffective: Amount(currency: LONGCURRENCY, cent: 10), + amountRaw: Amount(currency: LONGCURRENCY, cent: 20), + transactionId: "someTxID", + timestamp: Timestamp(from: 1_666_666_000_000), + txActions: []) + Group { + List { + ThreeAmountsSheet(stack: CallStack("Preview"), + common: common, topAbbrev: "Withdrawal", + topTitle: "Withdrawal", baseURL: DEMOEXCHANGE, noFees: false, + large: 1==0, summary: nil, merchant: nil) + .safeAreaInset(edge: .bottom) { + Button(String(localized: "Accept"), action: {}) + .buttonStyle(TalerButtonStyle(type: .prominent)) + .padding(.horizontal) + .disabled(true) + } + } + } + } +} diff --git a/TalerWallet1/Views/Transactions/ThreeAmountsV.swift b/TalerWallet1/Views/Transactions/ThreeAmountsV.swift @@ -1,185 +0,0 @@ -/* - * This file is part of GNU Taler, ©2022-24 Taler Systems S.A. - * See LICENSE.md - */ -/** - * @author Marc Stibane - */ -import SwiftUI -import taler_swift - -struct ThreeAmountsSheet: View { - let stack: CallStack - var common: TransactionCommon - var topAbbrev: String - var topTitle: String - var bottomTitle: String? - var bottomAbbrev: String? - let baseURL: String? - let noFees: Bool? // true if exchange charges no fees at all - let large: Bool // set to false for QR or IBAN - 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 - let fee = common.fee() - let incoming = common.incoming() - let pending = common.isPending - let isDone = common.isDone - let incomplete = !(isDone || pending) - - let defaultBottomTitle = incoming ? (pending ? String(localized: "Pending amount to obtain:") - : String(localized: "Obtained amount:") ) - : (pending ? String(localized: "Amount to pay:") - : String(localized: "Paid amount:") ) - let defaultBottomAbbrev = incoming ? (pending ? String(localized: "Pending:", comment: "mini") - : 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, - bottomTitle: bottomTitle ?? defaultBottomTitle, - bottomAbbrev: bottomAbbrev ?? defaultBottomAbbrev, - bottomAmount: incomplete ? nil : effective, - large: large, pending: pending, incoming: incoming, - baseURL: baseURL, - noFees: noFees, - txStateLcl: txStateLcl, - summary: summary, - merchant: merchant) - } -} -// MARK: - -struct ThreeAmountsV: View { - let stack: CallStack - var topTitle: String - var topAbbrev: String - var topAmount: Amount - var fee: Amount? // nil = don't show fee line, zero = no fee for this tx - var bottomTitle: String - var bottomAbbrev: String - var bottomAmount: Amount? // nil = incomplete (aborted, timed out) - let large: Bool - let pending: Bool - let incoming: Bool - let baseURL: String? - let noFees: Bool? // true if exchange charges no fees at all - let txStateLcl: String? // localizedState - let summary: String? - let merchant: String? - - @Environment(\.colorScheme) private var colorScheme - @Environment(\.colorSchemeContrast) private var colorSchemeContrast - @AppStorage("minimalistic") var minimalistic: Bool = false - - var body: some View { - let labelColor = WalletColors().labelColor - let foreColor = pending ? WalletColors().pendingColor(incoming) - : WalletColors().transactionColor(incoming) - let hasNoFees = noFees ?? false - Section { - if let summary { - Text(summary) - .talerFont(.title3) - .lineLimit(4) - .padding(.bottom) - } - if let merchant { - Text(merchant) - .talerFont(.title3) - .lineLimit(4) - .padding(.bottom) - } - AmountRowV(stack: stack.push(), - title: minimalistic ? topAbbrev : topTitle, - amount: topAmount, - isNegative: !incoming, - color: labelColor, - large: false) - .padding(.bottom, 4) - if hasNoFees == false { - 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") - AmountRowV(stack: stack.push(), - title: title, - amount: fee, - isNegative: !incoming, - color: labelColor, - large: false) - .padding(.bottom, 4) - } - if let bottomAmount { - AmountRowV(stack: stack.push(), - title: minimalistic ? bottomAbbrev : bottomTitle, - amount: bottomAmount, - isNegative: !incoming, - color: foreColor, - large: large) - } - } - if let baseURL { - VStack(alignment: .leading) { - // TODO: "Issued by" for withdrawals - Text(minimalistic ? "Payment provider:" : "Using payment service provider:") - .multilineTextAlignment(.leading) - .talerFont(.body) - Text(baseURL.trimURL()) - .frame(maxWidth: .infinity, alignment: .trailing) - .multilineTextAlignment(.center) - .talerFont(large ? .title3 : .body) -// .fontWeight(large ? .medium : .regular) // @available(iOS 16.0, *) - .foregroundColor(labelColor) - } - .padding(.top, 4) - .frame(maxWidth: .infinity, alignment: .leading) - .listRowSeparator(.hidden) - .accessibilityElement(children: .combine) - } - } header: { - if !minimalistic { - Text("Summary") - .talerFont(.title3) - .foregroundColor(WalletColors().secondary(colorScheme, colorSchemeContrast)) - } - } - } -} -// MARK: - -struct ThreeAmounts_Previews: PreviewProvider { - static var previews: some View { - let common = TransactionCommon(type: .withdrawal, - txState: TransactionState(major: .done), - amountEffective: Amount(currency: LONGCURRENCY, cent: 10), - amountRaw: Amount(currency: LONGCURRENCY, cent: 20), - transactionId: "someTxID", - timestamp: Timestamp(from: 1_666_666_000_000), - txActions: []) - Group { - List { - ThreeAmountsSheet(stack: CallStack("Preview"), - common: common, topAbbrev: "Withdrawal", - topTitle: "Withdrawal", baseURL: DEMOEXCHANGE, noFees: false, - large: 1==0, summary: nil, merchant: nil) - .safeAreaInset(edge: .bottom) { - Button(String(localized: "Accept"), action: {}) - .buttonStyle(TalerButtonStyle(type: .prominent)) - .padding(.horizontal) - .disabled(true) - } - } - } - } -}