taler-ios

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

DepositAmountV.swift (4563B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-26 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * @author Marc Stibane
      7  */
      8 import SwiftUI
      9 import taler_swift
     10 import SymLog
     11 
     12 // Called from DepositSelectV
     13 struct DepositAmountV: View {
     14     private let symLog = SymLogV(0)
     15     let stack: CallStack
     16     // when Action is tapped while in currency TransactionList…
     17     let selectedBalance: Balance?   // …then use THIS balance, otherwise show picker
     18     @Binding var amountLastUsed: Amount
     19     let paytoUri: String?
     20     let label: String?
     21 
     22     @EnvironmentObject private var controller: Controller
     23     @EnvironmentObject private var model: WalletModel
     24 
     25     @State private var balanceIndex = 0
     26     @State private var balance: Balance? = nil      // nil only when balances == []
     27     @State private var currencyInfo: CurrencyInfo = CurrencyInfo.zero(UNKNOWN)
     28     @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING)    // Update currency when used
     29     @State private var amountAvailable = Amount.zero(currency: EMPTYSTRING)     // GetMaxPeerPushAmount
     30 
     31     @MainActor
     32     private func viewDidLoad() async {
     33         let balances = controller.balances
     34         if let selectedBalance {
     35             let disableDeposits = selectedBalance.disableDirectDeposits ?? false
     36             if disableDeposits {
     37                 // find another balance
     38                 balance = Balance.firstwithDeposit(balances)
     39             } else {
     40                 balance = selectedBalance
     41             }
     42         } else {
     43             balance = Balance.firstwithDeposit(balances)
     44         }
     45         if let balance {
     46             balanceIndex = balances.firstIndex(of: balance) ?? 0
     47         } else {
     48             balanceIndex = 0
     49             balance = (balances.count > 0) ? balances[0] : nil
     50         }
     51     }
     52 
     53     @MainActor
     54     private func newBalance() async {
     55         // runs whenever the user changes the exchange via ScopePicker, or on new currencyInfo
     56         symLog.log("❗️ task \(balanceIndex)")
     57         if let balance {
     58             let scope = balance.scopeInfo
     59             amountToTransfer.setCurrency(scope.currency)
     60             currencyInfo = controller.info(for: scope, controller.currencyTicker)
     61             do {
     62                 amountAvailable = try await model.getMaxDepositAmount(scope)
     63             } catch {
     64                 // TODO: Error
     65                 amountAvailable = balance.available
     66             }
     67         }
     68     }
     69 
     70     var body: some View {
     71 #if PRINT_CHANGES
     72         let _ = Self._printChanges()
     73 #endif
     74         let count = controller.balances.count
     75         let _ = symLog.log("count = \(count)")
     76         let currencySymbol = currencyInfo.symbol
     77         let navA11y = DepositAmountView.navTitle(currencyInfo.name, true)          // always include currency for a11y
     78         let navTitle = DepositAmountView.navTitle(currencySymbol, currencyInfo.hasSymbol)
     79         let scrollView = ScrollView {
     80             if let label {
     81                 Text("to \(label)")
     82                     .talerFont(.picker)
     83                     .frame(maxWidth: .infinity, alignment: .leading)
     84                     .padding(.horizontal)
     85             }
     86             if count > 0 {
     87                 ScopePicker(stack: stack.push(),
     88                             value: $balanceIndex,
     89                       onlyNonZero: true)                                        // can only send what exists
     90                 { index in
     91                     balanceIndex = index
     92                     balance = controller.balances[index]
     93                 }
     94                 .padding(.horizontal)
     95                 .padding(.bottom, 4)
     96             }
     97             DepositAmountView(stack: stack.push(),
     98                             balance: $balance,
     99                        balanceIndex: $balanceIndex,
    100                      amountLastUsed: $amountLastUsed,
    101                    amountToTransfer: $amountToTransfer,
    102                     amountAvailable: amountAvailable,
    103                            paytoUri: paytoUri)
    104         } // ScrollView
    105             .navigationTitle(navTitle)
    106             .frame(maxWidth: .infinity, alignment: .leading)
    107             .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
    108             .task {
    109                 setVoice(to: nil)
    110                 await viewDidLoad()
    111             }
    112             .task(id: balanceIndex + (1000 * controller.currencyTicker)) { await newBalance() }
    113 
    114         if #available(iOS 16.4, *) {
    115             scrollView.toolbar(.hidden, for: .tabBar)
    116                 .scrollBounceBehavior(.basedOnSize)
    117         } else {
    118             scrollView
    119         }
    120     }
    121 }