commit 9bd0c7d7f4fad5621fdb782695a2bd8fcdb34fc6
parent 06abe762457f47aadb6b528e1da612cee72c970e
Author: Marc Stibane <marc@taler.net>
Date: Sat, 27 Jul 2024 14:49:21 +0200
Fee
Diffstat:
8 files changed, 123 insertions(+), 112 deletions(-)
diff --git a/TalerWallet1/Views/Banking/ManualWithdraw.swift b/TalerWallet1/Views/Banking/ManualWithdraw.swift
@@ -80,10 +80,11 @@ struct ManualWithdraw: View {
shortcutAction: nil)
.padding(.top)
QuiteSomeCoins(currencyInfo: $currencyInfo,
+// amountEffective: withdrawalAmountDetails?.amountEffective,
currency: currency,
coinData: coinData,
shouldShowFee: true, // TODO: set to false if we never charge withdrawal fees
- amountEffective: withdrawalAmountDetails?.amountEffective)
+ feeIsNegative: true)
// agePicker
NavigationLink(destination: destination) {
Text("Confirm Withdrawal") // VIEW_WITHDRAW_ACCEPT
diff --git a/TalerWallet1/Views/Banking/QuiteSomeCoins.swift b/TalerWallet1/Views/Banking/QuiteSomeCoins.swift
@@ -18,12 +18,11 @@ struct CoinData {
var tooMany: Bool { numCoins > 999 }
let fee: Amount?
- func feeLabel(_ currencyInfo: CurrencyInfo?) -> String {
+ func feeLabel(_ currencyInfo: CurrencyInfo, feeZero: String?, isNegative: Bool = false) -> String {
return if let fee {
- invalid ? String(localized: "Amount too small!")
- : tooMany ? String(localized: "Amount too big for a single withdrawal!")
- : fee.isZero ? String(localized: "No withdrawal fee")
- : String(localized: "- \(fee.formatted(currencyInfo, isNegative: false)) fee")
+ fee.isZero ? feeZero ?? EMPTYSTRING // String(localized: "No withdrawal fee")
+ : isNegative ? String(localized: "- \(fee.formatted(currencyInfo, isNegative: false)) fee")
+ : String(localized: "+ \(fee.formatted(currencyInfo, isNegative: false)) fee")
} else {
EMPTYSTRING
}
@@ -31,6 +30,10 @@ struct CoinData {
}
extension CoinData {
+ init(coins numCoins: Int?, fee: Amount?) {
+ self.init(numCoins: numCoins ?? -1, fee: fee) // either the number of coins, or unknown
+ }
+
init(details: WithdrawalAmountDetails?) {
do {
if let details {
@@ -61,31 +64,34 @@ extension CoinData {
struct QuiteSomeCoins: View {
private let symLog = SymLogV(0)
@Binding var currencyInfo: CurrencyInfo
+// let amountEffective: Amount?
let currency: String
let coinData: CoinData
let shouldShowFee: Bool
- let amountEffective: Amount?
+ let feeIsNegative: Bool
var body: some View {
- if !coinData.invalid {
- if !coinData.tooMany {
- if coinData.manyCoins {
- Text(coinData.quiteSome ? "Note: It will take quite some time to withdraw this amount! Be more patient..."
- : "Note: It will take some time to withdraw this amount. Be patient...")
- .foregroundColor(coinData.quiteSome ? .red : .primary)
- .talerFont(.body)
- .multilineTextAlignment(.leading)
- .padding(.vertical, 6)
- } // warnings
- }
- }
- if shouldShowFee {
+ let isError = coinData.invalid || coinData.tooMany
+ let showFee = shouldShowFee && !isError
+ if showFee {
if let fee = coinData.fee {
- Text(coinData.feeLabel(currencyInfo))
- .foregroundColor((coinData.invalid || coinData.tooMany || !fee.isZero) ? .red : .primary)
- .talerFont(.body)
+ Text(coinData.feeLabel(currencyInfo,
+ feeZero: String(localized: "No withdrawal fee"),
+ isNegative: feeIsNegative))
+ .foregroundColor(.primary)
+ .talerFont(.body)
}
}
+ if isError || coinData.quiteSome || coinData.manyCoins {
+ Text(coinData.invalid ? "Amount too small!"
+ : coinData.tooMany ? "Amount too big for a single withdrawal!"
+ : coinData.quiteSome ? "Note: It will take quite some time to prepare this amount! Be more patient..."
+ : "Note: It will take some time to prepare this amount. Be patient...")
+ .foregroundColor(isError || coinData.quiteSome ? .red : .primary)
+ .talerFont(.body)
+ .multilineTextAlignment(.leading)
+ .padding(.vertical, 6)
+ }
}
}
// MARK: -
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift b/TalerWallet1/Views/HelperViews/AmountInputV.swift
@@ -13,6 +13,7 @@ struct ComputeFeeResult {
let insufficient: Bool
let feeAmount: Amount?
let feeStr: String
+ let numCoins: Int?
}
struct AmountInputV: View {
@@ -20,38 +21,37 @@ struct AmountInputV: View {
let stack: CallStack
@Binding var currencyInfo: CurrencyInfo
- // the scanned URL
- let url: URL?
let amountAvailable: Amount? // TODO: GetMaxPeerPushAmount
+ let amountLabel: String
@Binding var amountToTransfer: Amount
let wireFee: Amount?
- let amountLabel: String
- let summaryIsEditable: 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 feeAmount: Amount?
let shortcutAction: ((_ amount: Amount) -> Void)?
let buttonAction: () -> Void
+ let feeIsNegative: Bool
let computeFee: ((_ amount: Amount) async -> ComputeFeeResult?)?
@EnvironmentObject private var controller: Controller
- @EnvironmentObject private var model: WalletModel
@Environment(\.colorScheme) private var colorScheme
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
- @State private var preparePayResult: PreparePayResult? = nil
+ @State private var feeAmount: Amount? = nil
@State private var feeStr: String = EMPTYSTRING
+ @State private var numCoins: Int?
struct Flags {
let insufficient: Bool
let disabled: Bool
}
- func checkAvailable(amount: Amount) -> Flags {
+ func checkAvailable(_ amount: Amount, _ coinData: CoinData) -> Flags {
if let amountAvailable {
do {
let insufficient = try amount > amountAvailable
- let disabled = insufficient || amount.isZero
+ let disabled = insufficient || amount.isZero || coinData.invalid || coinData.tooMany
return Flags(insufficient: insufficient, disabled: disabled)
} catch {
// TODO: error Amounts don't match
@@ -65,7 +65,6 @@ struct AmountInputV: View {
// let currencyInfo = controller.info(for: currency, controller.currencyTicker)
let insufficientLabel = String(localized: "You don't have enough \(currency).")
let available = amountAvailable?.formatted(currencyInfo, isNegative: false) ?? nil
- let flags = checkAvailable(amount: amountToTransfer)
VStack(alignment: .trailing) {
if summary.count > 0 {
Text(summary)
@@ -86,23 +85,20 @@ struct AmountInputV: View {
shortcutAction: shortcutAction)
// .accessibility(sortPriority: 2)
-// let color = flags.insufficient || !(feeAmount?.isZero ?? true) ? .red
-// : WalletColors().secondary(colorScheme, colorSchemeContrast)
-// Text(flags.insufficient ? insufficientLabel : feeLabel(feeStr))
-// .talerFont(.body)
-// .foregroundColor(color)
-// .padding(4)
-// .accessibility(sortPriority: 1)
+ let coinData = CoinData(coins: numCoins, fee: feeAmount)
+ QuiteSomeCoins(currencyInfo: $currencyInfo,
+// amountEffective: amountEffective,
+ currency: currency,
+ coinData: coinData,
+ shouldShowFee: true, // TODO: set to false if we never charge withdrawal fees
+ feeIsNegative: feeIsNegative)
+ let flags = checkAvailable(amountToTransfer, coinData)
Button("Next") { buttonAction() }
.buttonStyle(TalerButtonStyle(type: .prominent, disabled: flags.disabled))
.disabled(flags.disabled)
}.padding(.horizontal)
.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) {
// re-compute the fees on every tapped digit or backspace
if let computeFee {
@@ -111,7 +107,8 @@ struct AmountInputV: View {
symLog.log("computeFee() finished")
feeStr = result.feeStr
// insufficient = result.insufficient
-// feeAmount = result.feeAmount
+ feeAmount = result.feeAmount
+ numCoins = result.numCoins
} else {
symLog.log("computeFee() failed")
}
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -23,7 +23,7 @@ struct RequestPayment: View {
@State private var peerPullCheck: CheckPeerPullCreditResponse? = nil
@State private var expireDays: UInt = 0
- @State private var feeAmount: Amount? = nil
+// @State private var feeAmount: Amount? = nil
@State private var buttonSelected = false
@State private var shortcutSelected = false
@State private var amountShortcut = Amount.zero(currency: EMPTYSTRING) // Update currency when used
@@ -59,7 +59,7 @@ struct RequestPayment: View {
peerPullCheck = try? await model.checkPeerPullCreditM(baseURL, amount: amount,
cancellationId: "cancel")
-// return ComputeFeeResult(insufficient: false, feeAmount: <#T##Amount?#>, feeStr: <#T##String#>)
+// return ComputeFeeResult(insufficient: false, feeStr: feeLabel(feeStr), numCoins: details.numCoins)
}
return nil
}
@@ -82,7 +82,9 @@ struct RequestPayment: View {
let inputDestination = LazyView {
P2PSubjectV(stack: stack.push(),
currencyInfo: $currencyInfo,
- feeLabel: coinData.feeLabel(currencyInfo),
+ feeLabel: coinData.feeLabel(currencyInfo,
+ feeZero: String(localized: "No payment fee"),
+ isNegative: false),
feeIsNotZero: feeIsNotZero(),
outgoing: false,
amountToTransfer: $amountToTransfer,
@@ -106,17 +108,14 @@ struct RequestPayment: View {
: String(localized: "Amount to request:")
AmountInputV(stack: stack.push(),
currencyInfo: $currencyInfo,
- url: nil,
amountAvailable: nil,
+ amountLabel: amountLabel,
amountToTransfer: $amountToTransfer,
wireFee: nil,
- amountLabel: amountLabel,
- summaryIsEditable: true,
summary: $summary,
-// insufficient: $insufficient,
- feeAmount: $feeAmount,
shortcutAction: shortcutAction,
buttonAction: buttonAction,
+ feeIsNegative: true,
computeFee: computeFeeRequest)
.background(NavigationLink(destination: shortcutDestination, isActive: $shortcutSelected)
{ EmptyView() }.frame(width: 0).opacity(0).hidden()
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -30,7 +30,7 @@ struct SendAmount: View {
@State var peerPushCheck: CheckPeerPushDebitResponse? = nil
@State private var expireDays = SEVENDAYS
@State private var insufficient = false
- @State private var feeAmount: Amount? = nil
+// @State private var feeAmount: Amount? = nil
@State private var feeStr: String = EMPTYSTRING
@State private var buttonSelected = false
@State private var shortcutSelected = false
@@ -54,12 +54,11 @@ struct SendAmount: View {
do {
if let ppCheck {
// Outgoing: fee = effective - raw
- feeAmount = try ppCheck.amountEffective - ppCheck.amountRaw
- return feeAmount
+ let fee = try ppCheck.amountEffective - ppCheck.amountRaw
+ return fee
}
} catch {}
- feeAmount = nil
- return feeAmount
+ return nil
}
private func feeIsNotZero() -> Bool? {
@@ -68,8 +67,8 @@ struct SendAmount: View {
return nil // this exchange never has fees
}
}
- return peerPushCheck != nil ? (!(feeAmount?.isZero ?? false))
- : false
+ return peerPushCheck == nil ? false
+ : true // TODO: !(feeAmount?.isZero ?? false)
}
private func computeFeeSend(_ amount: Amount) async -> ComputeFeeResult? {
@@ -150,17 +149,14 @@ struct SendAmount: View {
: String(localized: "Amount to send:")
AmountInputV(stack: stack.push(),
currencyInfo: $currencyInfo,
- url: nil,
amountAvailable: amountAvailable,
+ amountLabel: amountLabel,
amountToTransfer: $amountToTransfer,
wireFee: nil,
- amountLabel: amountLabel,
- summaryIsEditable: true,
summary: $summary,
-// insufficient: $insufficient,
- feeAmount: $feeAmount,
shortcutAction: shortcutAction,
buttonAction: buttonAction,
+ feeIsNegative: false,
computeFee: computeFeeSend)
.background(NavigationLink(destination: shortcutDestination, isActive: $shortcutSelected)
{ EmptyView() }.frame(width: 0).opacity(0).hidden()
diff --git a/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift b/TalerWallet1/Views/Sheets/Payment/PayTemplateV.swift
@@ -39,8 +39,8 @@ struct PayTemplateV: View {
@State private var summaryIsEditable = false
@State private var summary: String = EMPTYSTRING // templateParam
- @State private var feeAmount: Amount? = nil
@State private var currencyInfo: CurrencyInfo = CurrencyInfo.zero(UNKNOWN)
+// @State private var feeAmount: Amount? = nil
// @State private var feeStr: String = EMPTYSTRING
private func shortcutAction(_ shortcut: Amount) {
@@ -134,17 +134,15 @@ struct PayTemplateV: View {
if amountIsEditable { // template contract amount is not fixed => let the user input an amount first
let amountInput = AmountInputV(stack: stack.push(),
currencyInfo: $currencyInfo,
- url: url,
+// url: url,
amountAvailable: nil,
+ amountLabel: amountLabel,
amountToTransfer: $amountToTransfer,
wireFee: nil,
- amountLabel: amountLabel,
- summaryIsEditable: summaryIsEditable,
summary: $summary,
-// insufficient: $insufficient,
- feeAmount: $feeAmount,
shortcutAction: shortcutAction,
buttonAction: buttonAction1,
+ feeIsNegative: false,
computeFee: computeFeePayTemplate)
ScrollView {
if summaryIsEditable { // after amount input,
diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawAcceptView.swift
@@ -73,10 +73,11 @@ struct WithdrawAcceptView: View {
merchant: nil)
let coinData = CoinData(details: withdrawalAmountDetails)
QuiteSomeCoins(currencyInfo: $currencyInfo,
+// amountEffective: effective,
currency: currency,
coinData: coinData,
shouldShowFee: true, // TODO: set to false if we never charge withdrawal fees
- amountEffective: effective)
+ feeIsNegative: true)
}
.listStyle(myListStyle.style).anyView
.navigationTitle(navTitle)
diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawURIView.swift
@@ -41,7 +41,8 @@ struct WithdrawURIView: View {
@State private var defaultExchangeBaseUrl: String? // if nil then use possibleExchanges
@State private var currencyInfo: CurrencyInfo = CurrencyInfo.zero(UNKNOWN)
- @State private var feeAmount: Amount? = nil
+// @State private var feeAmount: Amount? = nil
+ @State private var withdrawalAmountDetails: WithdrawalAmountDetails? = nil
let navTitle = String(localized: "Withdrawal")
@@ -70,9 +71,19 @@ struct WithdrawURIView: View {
if let details = try? await model.getWithdrawalDetailsForAmountM(exchange.exchangeBaseUrl,
amount: amount) {
let fee = try? details.amountRaw - details.amountEffective
- let feeStr = fee?.readableDescription ?? "nix"
+ let feeStr = fee?.formatted(currencyInfo, isNegative: true) ?? "nix"
symLog.log("Fee = \(feeStr)")
+ let insufficient = if let amountAvailable {
+ (try? details.amountRaw < amountAvailable) ?? true
+ } else {
+ false
+ }
+ withdrawalAmountDetails = details
+ return ComputeFeeResult(insufficient: insufficient, feeAmount: fee,
+ feeStr: feeLabel(feeStr), numCoins: details.numCoins)
}
+ } else {
+ symLog.log("No exchange!")
}
return nil
}
@@ -85,7 +96,7 @@ struct WithdrawURIView: View {
if possibleExchanges.count > 0 {
if let defaultBaseUrl = defaultExchangeBaseUrl ?? possibleExchanges.first?.exchangeBaseUrl {
VStack {
- let title = String(localized: "Exchange")
+ let title = String(localized: "using:", comment: "using: exchange.taler.net")
if possibleExchanges.count > 1 {
Picker(title, selection: $selectedExchange) {
ForEach(possibleExchanges, id: \.self) { exchange in
@@ -104,10 +115,14 @@ struct WithdrawURIView: View {
}
}
} else {
- Text(defaultBaseUrl)
- .task {
- await loadExchange(defaultBaseUrl)
- }
+ HStack {
+ Text(title)
+ Text(defaultBaseUrl.trimURL())
+ }
+ .talerFont(.body)
+// .task {
+// await loadExchange(defaultBaseUrl)
+// }
} // load defaultBaseUrl
let acceptDestination = WithdrawAcceptView(stack: stack.push(),
currencyInfo: $currencyInfo,
@@ -115,38 +130,35 @@ struct WithdrawURIView: View {
amountToTransfer: $amountToTransfer,
exchange: $exchange)
if amountIsEditable {
- ScrollView {
- let shortcutDestination = LazyView {
- WithdrawAcceptView(stack: stack.push(),
- currencyInfo: $currencyInfo,
- url: url,
- amountToTransfer: $amountShortcut,
- exchange: $exchange)
- }
- // TODO: input amount, then
- let amountLabel = minimalistic ? String(localized: "Amount:")
- : String(localized: "Amount to withdraw:")
- AmountInputV(stack: stack.push(),
- currencyInfo: $currencyInfo,
- url: nil,
- amountAvailable: amountAvailable,
- amountToTransfer: $amountToTransfer,
- wireFee: wireFee,
- amountLabel: amountLabel,
- summaryIsEditable: false,
- summary: $summary,
-// insufficient: $insufficient,
- feeAmount: $feeAmount,
- shortcutAction: shortcutAction,
- buttonAction: buttonAction,
- computeFee: computeFeeWithdraw)
- .background(NavigationLink(destination: shortcutDestination, isActive: $shortcutSelected)
- { EmptyView() }.frame(width: 0).opacity(0).hidden()
- ) // shortcutDestination
- .background(NavigationLink(destination: acceptDestination, isActive: $buttonSelected)
- { EmptyView() }.frame(width: 0).opacity(0).hidden()
- ) // acceptDestination
- }
+ ScrollView {
+ let shortcutDestination = LazyView {
+ WithdrawAcceptView(stack: stack.push(),
+ currencyInfo: $currencyInfo,
+ url: url,
+ amountToTransfer: $amountShortcut,
+ exchange: $exchange)
+ }
+ // TODO: input amount, then
+ let amountLabel = minimalistic ? String(localized: "Amount:")
+ : String(localized: "Amount to withdraw:")
+ AmountInputV(stack: stack.push(),
+ currencyInfo: $currencyInfo,
+ amountAvailable: amountAvailable,
+ amountLabel: amountLabel,
+ amountToTransfer: $amountToTransfer,
+ wireFee: wireFee,
+ summary: $summary,
+ shortcutAction: shortcutAction,
+ buttonAction: buttonAction,
+ feeIsNegative: true,
+ computeFee: computeFeeWithdraw)
+ .background(NavigationLink(destination: shortcutDestination, isActive: $shortcutSelected)
+ { EmptyView() }.frame(width: 0).opacity(0).hidden()
+ ) // shortcutDestination
+ .background(NavigationLink(destination: acceptDestination, isActive: $buttonSelected)
+ { EmptyView() }.frame(width: 0).opacity(0).hidden()
+ ) // acceptDestination
+ } // ScrollView
} else {
acceptDestination
} // directly show the accept view
@@ -180,13 +192,14 @@ struct WithdrawURIView: View {
let amount = uriInfoResponse.amount
let currency = amount?.currencyStr ?? uriInfoResponse.currency
amountToTransfer = amount ?? Amount.zero(currency: currency)
+ amountIsEditable = uriInfoResponse.editableAmount
amountAvailable = uriInfoResponse.maxAmount // may be nil
wireFee = uriInfoResponse.wireFee // may be nil
let baseUrl = uriInfoResponse.defaultExchangeBaseUrl
?? uriInfoResponse.possibleExchanges[0].exchangeBaseUrl
defaultExchangeBaseUrl = uriInfoResponse.defaultExchangeBaseUrl
possibleExchanges = uriInfoResponse.possibleExchanges
- amountIsEditable = uriInfoResponse.editableAmount
+ await loadExchange(baseUrl)
symLog.log("\(baseUrl.trimURL()) loaded")
await controller.checkInfo(for: baseUrl, model: model)
symLog.log("Info(for: \(baseUrl.trimURL())) loaded")