taler-ios

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

commit 20b17e68caf67de489d7942c599e6245bba8e53b
parent 02ca5592f97f7929752b47cc9c393853c8a4a099
Author: Marc Stibane <marc@taler.net>
Date:   Sun,  9 Aug 2026 18:40:36 +0200

Deposit with progress

Diffstat:
MTalerWallet1/Views/Actions/Banking/DepositAmountAction.swift | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
MTalerWallet1/Views/Actions/Banking/DepositAmountView.swift | 169+++++++++++++++++++------------------------------------------------------------
2 files changed, 139 insertions(+), 172 deletions(-)

diff --git a/TalerWallet1/Views/Actions/Banking/DepositAmountAction.swift b/TalerWallet1/Views/Actions/Banking/DepositAmountAction.swift @@ -27,6 +27,9 @@ struct DepositAmountAction: View { @State private var currencyInfo: CurrencyInfo = CurrencyInfo.zero(UNKNOWN) @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used @State private var amountAvailable = Amount.zero(currency: EMPTYSTRING) // GetMaxPeerPushAmount + @State private var depositStarted = false + @State private var txId: String? = nil + @State private var talerTX = TalerTransaction(dummyCurrency: DEMOCURRENCY) @MainActor private func viewDidLoad() async { @@ -67,55 +70,108 @@ struct DepositAmountAction: View { } } + @MainActor + private func startDeposit(_ scope: ScopeInfo) { + if let paytoUri { + depositStarted = true // don't run twice + Task { + symLog.log("Deposit") + if let result = try? await model.createDepositGroup(paytoUri, + scope: scope, + amount: amountToTransfer) { + symLog.log(result.transactionId) + txId = result.transactionId + } else { + depositStarted = false + } + } + } + } + var body: some View { #if PRINT_CHANGES let _ = Self._printChanges() #endif - let count = controller.balances.count - let _ = symLog.log("count = \(count)") - let currencySymbol = currencyInfo.symbol - let navA11y = DepositAmountView.navTitle(currencyInfo.name, true) // always include currency for a11y - let navTitle = DepositAmountView.navTitle(currencySymbol, currencyInfo.hasSymbol) - let scrollView = ScrollView { - if let label { - Text("to \(label)") - .talerFont(.picker) - .frame(maxWidth: .infinity, alignment: .leading) + if let txId { + TransactionSummaryList(stack: stack.push(), + transactionId: txId, + talerTX: $talerTX, + navTitle: nil, + hasDone: true, // conclude payment + showDone: .prominent, // TODO: isKYC ? .bordered : .prominent + url: nil, + withActions: false) + } else if depositStarted { + let message = String(localized: "Depositing...", comment: "loading") + LoadingView(stack: stack.push(), scopeInfo: nil, message: message) + .navigationBarBackButtonHidden(true) + .interactiveDismissDisabled() // can only use "Abort" button to dismiss + .safeAreaInset(edge: .bottom) { + let buttonTitle = String(localized: "Abort", comment: "deposit") + Button(buttonTitle) { dismissTop(stack.push()) } + .buttonStyle(TalerButtonStyle(type: .prominent)) + .padding(.horizontal) + } + } else { + let count = controller.balances.count + let _ = symLog.log("count = \(count)") + let currencySymbol = currencyInfo.symbol + let navA11y = DepositAmountView.navTitle(currencyInfo.name, true) // always include currency for a11y + let navTitle = DepositAmountView.navTitle(currencySymbol, currencyInfo.hasSymbol) + let scrollView = ScrollView { + if let label { + Text("to \(label)") + .talerFont(.picker) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal) + } + if count > 1 { + ScopePicker(stack: stack.push(), + value: $balanceIndex, + onlyNonZero: true) // can only send what exists + { index in + balanceIndex = index + balance = controller.balances[index] + } .padding(.horizontal) - } - if count > 1 { - ScopePicker(stack: stack.push(), - value: $balanceIndex, - onlyNonZero: true) // can only send what exists - { index in - balanceIndex = index - balance = controller.balances[index] + .padding(.bottom, 4) + } // TODO: else show static text? + DepositAmountView(stack: stack.push(), + balance: $balance, + balanceIndex: $balanceIndex, + amountLastUsed: $amountLastUsed, + amountToTransfer: $amountToTransfer, + amountAvailable: amountAvailable, + depositStarted: depositStarted + ) { + if let balance { + startDeposit(balance.scopeInfo) + } } - .padding(.horizontal) - .padding(.bottom, 4) - } // TODO: else show static text? - DepositAmountView(stack: stack.push(), - balance: $balance, - balanceIndex: $balanceIndex, - amountLastUsed: $amountLastUsed, - amountToTransfer: $amountToTransfer, - amountAvailable: amountAvailable, - paytoUri: paytoUri) - } // ScrollView - .navigationTitle(navTitle) - .frame(maxWidth: .infinity, alignment: .leading) - .background(FullBackground()) - .task { - setVoice(to: nil) - await viewDidLoad() - } - .task(id: balanceIndex + (1000 * controller.currencyTicker)) { await newBalance() } + .onAppear { + DebugViewC.shared.setViewID(VIEW_DEPOSIT, stack: stack.push()) + symLog.log("❗️ onAppear") + } + .onDisappear { + symLog.log("❗️ onDisappear") + } + } // ScrollView + .navigationTitle(navTitle) + .frame(maxWidth: .infinity, alignment: .leading) + .background(FullBackground()) +// .ignoresSafeArea(.keyboard, edges: .bottom) + .task { + setVoice(to: nil) + await viewDidLoad() + } + .task(id: balanceIndex + (1000 * controller.currencyTicker)) { await newBalance() } - if #available(iOS 16.4, *) { - scrollView.toolbar(.hidden, for: .tabBar) - .scrollBounceBehavior(.basedOnSize) - } else { - scrollView - } + if #available(iOS 16.4, *) { + scrollView.toolbar(.hidden, for: .tabBar) + .scrollBounceBehavior(.basedOnSize) + } else { + scrollView + } + } // else } } diff --git a/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift b/TalerWallet1/Views/Actions/Banking/DepositAmountView.swift @@ -9,7 +9,7 @@ import SwiftUI import taler_swift import SymLog -// Called from DepositAmountV +// Called from DepositAmountAction struct DepositAmountView: View { private let symLog = SymLogV(0) let stack: CallStack @@ -18,7 +18,8 @@ struct DepositAmountView: View { @Binding var amountLastUsed: Amount @Binding var amountToTransfer: Amount let amountAvailable: Amount - let paytoUri: String? + let depositStarted: Bool + let action: () -> Void @EnvironmentObject private var controller: Controller @EnvironmentObject private var model: WalletModel @@ -30,7 +31,6 @@ struct DepositAmountView: View { @State private var insufficient = false @State private var feeAmount: Amount? = nil @State private var feeStr: String = EMPTYSTRING - @State private var depositStarted = false @State private var exchange: Exchange? = nil // wg. noFees public static func navTitle(_ currency: String = EMPTYSTRING, @@ -87,144 +87,55 @@ struct DepositAmountView: View { return DepositAmountView.navTitle() // should never happen } - @MainActor - private func startDeposit(_ scope: ScopeInfo) { - if let paytoUri { - depositStarted = true // don't run twice - Task { - symLog.log("Deposit") - if let result = try? await model.createDepositGroup(paytoUri, - scope: scope, - amount: amountToTransfer) { - symLog.log(result.transactionId) - if let txState = result.txState { - if txState.isKYC || txState.isKYCauth { - symLog.log("Deposit KYC") - - } else { -// ViewState2.shared.popToRootView(stack.push()) - NotificationCenter.default.post(name: .TransactionDone, object: nil, userInfo: nil) - dismissTop(stack.push()) - } - } - } else { - depositStarted = false - } - } - } - } - var body: some View { #if PRINT_CHANGES let _ = Self._printChanges() let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear #endif - if depositStarted { - let message = String(localized: "Depositing...", comment: "loading") - LoadingView(stack: stack.push(), scopeInfo: nil, message: message) - .navigationBarBackButtonHidden(true) - .interactiveDismissDisabled() // can only use "Done" button to dismiss - .safeAreaInset(edge: .bottom) { - let buttonTitle = String(localized: "Abort", comment: "deposit") - Button(buttonTitle) { dismissTop(stack.push()) } - .buttonStyle(TalerButtonStyle(type: .prominent)) - .padding(.horizontal) - } - } else { ScrollView { - if let balance { - let scopeInfo = balance.scopeInfo - let availableStr = amountAvailable.formatted(scopeInfo, isNegative: false) - - let currencyInfo = controller.info(for: scopeInfo, controller.currencyTicker) -// let amountVoiceOver = amountToTransfer.formatted(scopeInfo, isNegative: false) - let insufficientLabel = String(localized: "You don't have enough \(currencyInfo.specs.name).") -// let insufficientLabel2 = String(localized: "but you only have \(available) to deposit.") + if let balance { + let scopeInfo = balance.scopeInfo + let availableStr = amountAvailable.formatted(scopeInfo, isNegative: false) - let disabled = insufficient || amountToTransfer.isZero + let currencyInfo = controller.info(for: scopeInfo, controller.currencyTicker) +// let amountVoiceOver = amountToTransfer.formatted(scopeInfo, isNegative: false) + let insufficientLabel = String(localized: "You don't have enough \(currencyInfo.specs.name).") +// let insufficientLabel2 = String(localized: "but you only have \(available) to deposit.") - Text("Available: \(availableStr.0)") - .accessibilityLabel(Text("Available: \(availableStr.1)", comment: "a11y")) - .talerFont(.title3) - .frame(maxWidth: .infinity, alignment: .trailing) - .padding(.horizontal) -// .padding(.bottom, 2) - let a11yLabel = String(localized: "Amount to deposit:", comment: "a11y, no abbreviations") - let amountLabel = minimalistic ? String(localized: "Amount:") - : a11yLabel - CurrencyInputView(scope: scopeInfo, - amount: $amountToTransfer, - amountLastUsed: amountLastUsed, - available: amountAvailable, // enable shortcuts if available >= value - title: amountLabel, - a11yTitle: a11yLabel, - shortcutAction: nil) - .padding(.horizontal) + let disabled = insufficient || amountToTransfer.isZero - Text(insufficient ? insufficientLabel - : feeLabel(feeStr)) - .talerFont(.body) - .foregroundColor(insufficient ? WalletColors().attention - : (feeAmount?.isZero ?? true) ? WalletColors().secondary(colorScheme, colorSchemeContrast) - : WalletColors().negative) - .padding(4) - let hint = String(localized: "enabled when amount is non-zero, but not higher than your available amount", - comment: "a11y") - Button(buttonTitle(amountToTransfer)) { startDeposit(balance.scopeInfo) } // TODO: use exchange scope + Text("Available: \(availableStr.0)") + .accessibilityLabel(Text("Available: \(availableStr.1)", comment: "a11y")) + .talerFont(.title3) + .frame(maxWidth: .infinity, alignment: .trailing) + .padding(.horizontal) +// .padding(.bottom, 2) + let a11yLabel = String(localized: "Amount to deposit:", comment: "a11y, no abbreviations") + let amountLabel = minimalistic ? String(localized: "Amount:") + : a11yLabel + CurrencyInputView(scope: scopeInfo, + amount: $amountToTransfer, + amountLastUsed: amountLastUsed, + available: amountAvailable, // enable shortcuts if available >= value + title: amountLabel, + a11yTitle: a11yLabel, + shortcutAction: nil) + .padding(.horizontal) + Text(insufficient ? insufficientLabel + : feeLabel(feeStr)) + .talerFont(.body) + .foregroundColor(insufficient ? WalletColors().attention + : (feeAmount?.isZero ?? true) ? WalletColors().secondary(colorScheme, colorSchemeContrast) + : WalletColors().negative) + .padding(4) + let hint = String(localized: "enabled when amount is non-zero, but not higher than your available nt", + comment: "a11y") + Button(buttonTitle(amountToTransfer)) { action() } .buttonStyle(TalerButtonStyle(type: .prominent, disabled: disabled || depositStarted)) .disabled(disabled || depositStarted) .accessibilityHint(disabled ? hint : EMPTYSTRING) .padding(.horizontal) - } else { // no balance - Yikes - Text("No balance. There seems to be a problem with the database...") - } - } -// .ignoresSafeArea(.keyboard, edges: .bottom) - .onAppear { - DebugViewC.shared.setViewID(VIEW_DEPOSIT, stack: stack.push()) - symLog.log("❗️ onAppear") + } else { // no balance - Yikes + Text("No balance. There seems to be a problem with the database...") } - .onDisappear { - symLog.log("❗️ onDisappear") - } - -// .task(id: amountToTransfer.value) { -// if let amountAvailable { -// do { -// insufficient = try amountToTransfer > amountAvailable -// } catch { -// print("Yikes❗️ insufficient failed❗️") -// insufficient = true -// } -// -// if insufficient { -// announce("\(amountVoiceOver), \(insufficientLabel2)") -// feeStr = EMPTYSTRING -// } -// } -// if !insufficient { -// if amountToTransfer.isZero { -// feeStr = EMPTYSTRING -// checkDepositResult = nil -// } else if let paytoUri { -// if let ppCheck = try? await model.checkDepositM(paytoUri, amount: amountToTransfer) { -// if let feeAmount = fee(ppCheck: ppCheck) { -// feeStr = feeAmount.formatted(scopeInfo, isNegative: false) -// let feeLabel = feeLabel(feeStr) -// announce("\(amountVoiceOver), \(feeLabel)") -// } else { -// feeStr = EMPTYSTRING -// announce(amountVoiceOver) -// } -// checkDepositResult = ppCheck -// } else { -// checkDepositResult = nil -// } -// } -// } -// } - } // else } // body } -// MARK: - -#if DEBUG -#endif