taler-ios

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

WithdrawAcceptView.swift (7385B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-25 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 struct WithdrawAcceptView: View {
     13     private let symLog = SymLogV(0)
     14     let stack: CallStack
     15     let navTitle = String(localized: "Withdrawal")
     16 
     17     // the URL from the bank website
     18     let url: URL
     19     let scope: ScopeInfo
     20     @Binding var amountToTransfer: Amount
     21     @Binding var wireFee: Amount?
     22     @Binding var exchange: Exchange?            // user can select one from possibleExchanges
     23 
     24     @EnvironmentObject private var controller: Controller
     25     @EnvironmentObject private var model: WalletModel
     26     @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
     27 
     28     @State private var withdrawalDetails: WithdrawalDetailsForAmount? = nil
     29 
     30     @MainActor
     31     func reloadExchange() async -> Void {        // TODO: throws?
     32         if let exchange {
     33             if let someExchange = try? await model.getExchangeByUrl(url: exchange.exchangeBaseUrl) {
     34                 self.exchange = someExchange
     35             }
     36         }
     37     }
     38 
     39     @MainActor
     40     private func viewDidLoad() async {
     41         symLog.log(".task \(exchange?.id ?? "nil")")
     42         if !amountToTransfer.isZero, let exchange {
     43             if let details = try? await model.getWithdrawalDetailsForAmount(amountToTransfer,
     44                                                                    baseUrl: exchange.exchangeBaseUrl,
     45                                                                      scope: nil) { // TODO: scope
     46                 withdrawalDetails = details
     47             }
     48 //          agePicker.setAges(ages: details?.ageRestrictionOptions)
     49         } else {    // TODO: error
     50             symLog.log("no exchangeBaseUrl or no exchange")
     51             withdrawalDetails = nil
     52         }
     53     }
     54 
     55     var body: some View {
     56 #if PRINT_CHANGES
     57         let _ = Self._printChanges()
     58         let _ = symLog.vlog(scope.url ?? amountToTransfer.readableDescription)       // just to get the #
     59 #endif
     60         ZStack {  // there is only _one_ Z item ever - use ZStack to ensure .task is run only _once_ when exchange is switched
     61           if let exchange2 = exchange {     // there should always be an exchange...
     62             VStack {
     63                 let tosAccepted = exchange2.tosStatus == .accepted
     64                                || exchange2.tosStatus == .missingTos      // no ToS to accept
     65                 if !tosAccepted {
     66                     ToSButtonView(stack: stack.push(),
     67                         exchangeBaseUrl: exchange2.exchangeBaseUrl,
     68                                  viewID: SHEET_WITHDRAW_TOS,
     69                                     p2p: false,
     70                            acceptAction: reloadExchange)
     71                 }
     72                 List {
     73                     if let withdrawalDetails {
     74                         let raw = withdrawalDetails.amountRaw
     75                         let effective = withdrawalDetails.amountEffective
     76                         let currency = raw.currencyStr
     77                         let fee = try! Amount.diff(raw, effective)
     78                         let outColor = WalletColors().transactionColor(false)
     79                         let inColor = WalletColors().transactionColor(true)
     80 
     81                         ThreeAmountsSection(stack: stack.push(),
     82                                             scope: scope,
     83                                          topTitle: String(localized: "Chosen amount to withdraw:"),
     84                                         topAbbrev: String(localized: "Withdraw:", comment: "Chosen amount to withdraw:"),
     85                                         topAmount: raw,
     86                                            noFees: exchange2.noFees,
     87                                               fee: fee,
     88                                     feeIsNegative: true,
     89                                       bottomTitle: String(localized: "Amount to obtain:"),
     90                                      bottomAbbrev: String(localized: "Obtain:", comment: "Amount to obtain:"),
     91                                      bottomAmount: effective,
     92                                             large: false,
     93                                     pendingDialog: false,
     94                                            isDone: false,
     95                                          incoming: true,
     96                                           baseURL: exchange2.exchangeBaseUrl,
     97                                        txStateLcl: nil,        // common.txState.major.localizedState
     98                                           summary: nil,
     99                                          products: nil)
    100                         if let wireFee {
    101                             if !wireFee.isZero {
    102                                 let currencyInfo = controller.info(for: scope, controller.currencyTicker)
    103                                 let feeStr = wireFee.formatted(currencyInfo, isNegative: false)
    104                                 let feeTitle = String(localized: "FEE_WITHDRAW_BANK_WIRE",
    105                                                    defaultValue: "Your bank's wire fee: \(feeStr.0)")
    106                                 let feeA11y = String(localized: "FEE_WITHDRAW_BANK_WIRE_A11Y",
    107                                                   defaultValue: "Your bank's wire fee: \(feeStr.1)", comment: "a11y")
    108                                 Text(feeTitle)
    109                                     .accessibilityLabel(Text(feeA11y))
    110                             }
    111                         }
    112                     } else {
    113                         Section {
    114                             Text("The amount will be determined by the Cash Acceptor.")
    115                         }
    116                     }
    117                 }
    118                 .listStyle(myListStyle.style).anyView
    119                 .navigationTitle(navTitle)
    120                 .safeAreaInset(edge: .bottom) {
    121                     if tosAccepted {
    122                         let destination = WithdrawAcceptDone(stack: stack.push(),
    123 //                                                             scope: scope,
    124                                                    exchangeBaseUrl: exchange2.exchangeBaseUrl,
    125                                                                url: url,
    126                                                   amountToTransfer: amountToTransfer.isZero ? nil : amountToTransfer)
    127                         NavigationLink(destination: destination) {
    128                             Text("Confirm Withdrawal")      // SHEET_WITHDRAW_ACCEPT
    129                         }
    130                         .buttonStyle(TalerButtonStyle(type: .prominent))
    131                         .padding(.horizontal)
    132                     }
    133                 }
    134             }
    135             .onAppear() {
    136                 symLog.log("onAppear")
    137                 DebugViewC.shared.setSheetID(SHEET_WITHDRAW_ACCEPT,             // 132 WithdrawAcceptView
    138                                              stack: stack.push())
    139             }
    140           } else {        // no exchange - should not happen
    141 #if DEBUG
    142             let message = url.host
    143 #else
    144             let message: String? = nil
    145 #endif
    146             let _ = symLog.log("Loading")
    147             LoadingView(stack: stack.push(), scopeInfo: nil, message: message)
    148           }
    149         }
    150         .task(id: exchange?.id) {     // re-run this whenever the user switches the exchange
    151             await viewDidLoad()
    152         }
    153     }
    154 }