taler-ios

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

PayTemplateV.swift (11292B)


      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 // Will be called either by the user scanning a <pay-template> QR code or tapping the provided link,
     13 // both from the shop's website - or even from a printed QR code.
     14 // We check whether amount and/or summary is editable, and finally go to PaymentView
     15 struct PayTemplateV: View {
     16     private let symLog = SymLogV(0)
     17     let stack: CallStack
     18 
     19     // the scanned URL
     20     let url: URL
     21 
     22     @EnvironmentObject private var controller: Controller
     23     @EnvironmentObject private var model: WalletModel
     24     @AppStorage("minimalistic") var minimalistic: Bool = false
     25     @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
     26 
     27     let navTitle = String(localized: "Custom Amount", comment:"pay merchant")
     28 
     29 //    @State private var insufficient = false
     30 //    @State private var preparePayResult: PreparePayResult? = nil
     31     @State private var templateContract: TemplateContractDetails? = nil
     32     @State private var amountIsEditable = false
     33     @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING)    // Update currency when used
     34     @State private var amountShortcut = Amount.zero(currency: EMPTYSTRING)      // Update currency when used
     35     @State private var amountLastUsed = Amount.zero(currency: EMPTYSTRING)      // Update currency when used
     36     @State private var amountAvailable = Amount.zero(currency: EMPTYSTRING)     // TODO: set correct available amount (like in SendAmountV)
     37     @State private var shortcutSelected = false
     38     @State private var buttonSelected1 = false
     39     @State private var buttonSelected2 = false
     40     @State private var summaryIsEditable = false
     41     @State private var isPaivana = false
     42     @State private var summary: String = EMPTYSTRING       // templateParam
     43     @State private var scope: ScopeInfo? = nil
     44 
     45 //    @State private var feeAmount: Amount? = nil
     46 //    @State private var feeStr: String = EMPTYSTRING
     47 
     48     private func shortcutAction(_ shortcut: Amount) {
     49         amountShortcut = shortcut
     50         shortcutSelected = true
     51     }
     52     private func buttonAction1() {
     53         buttonSelected1 = true
     54     }
     55     private func buttonAction2() {
     56         buttonSelected2 = true
     57     }
     58 
     59     private func computeFeePayTemplate(_ amount: Amount) async -> ComputeFeeResult? {
     60         return nil
     61     }
     62 
     63     @MainActor
     64     private func viewDidLoad() async {
     65         if let response = try? await model.checkPayForTemplate(url.absoluteString) {
     66             let details = response.templateDetails
     67             let defaults = details.editableDefaults     // might be nil, or its fields might be nil
     68                                                         // TODO: let the user choose a currency from supportedCurrencies[]
     69             let supportedCurrencies = response.supportedCurrencies
     70 
     71             /// checkPayForTemplate does not provide fees (yet)
     72             let contract = details.templateContract     // specifies fixed amount/summary
     73             if let amount = contract.amount {
     74                 controller.updateAmount(amount, forSaved: url)
     75             }
     76             if contract.templateType == "paivana" {
     77                 // TODO: ???
     78                 isPaivana = true
     79             } else {
     80                 amountIsEditable = contract.amount == nil
     81                 summaryIsEditable = contract.summary == nil
     82             }
     83 
     84             let prepCurrency = contract.currency ?? defaults?.currency ?? supportedCurrencies.first ?? UNKNOWN
     85             let zeroAmount = Amount(currency: prepCurrency, cent: 0)
     86             let prepAmount = contract.amount ?? defaults?.amount        // might be nil
     87             let prepSummary = contract.summary ?? defaults?.summary     // might be nil
     88 //          symLog.log("LoadingView.task preparePayForTemplate")
     89             /// preparePayForTemplate will make a network call to the merchant and create a TX
     90             ///  -> we only want to do this after the user entered amount and subject - but before confirmation of course
     91 //          if let result = await preparePayForTemplate(model: model,
     92 //                                                        url: url,
     93 //                                                     amount: amountIsEditable ? prepAmount ?? zeroAmount
     94 //                                                                              : nil,
     95 //                                                    summary: summaryIsEditable ? prepSummary ?? SPACE
     96 //                                                                               : nil,
     97 //                                                   announce: announce)
     98 //          {   symLog.log("preparePayForTemplate finished")
     99                 amountToTransfer = prepAmount ?? zeroAmount
    100                 summary = prepSummary ?? EMPTYSTRING
    101                 templateContract = contract
    102 //              insufficient = result.insufficient
    103 //              feeAmount = result.feeAmount
    104 //              feeStr = result.feeStr
    105 //              preparePayResult = result.ppCheck
    106 //          } else {
    107 //              symLog.log("preparePayForTemplateM failed")
    108 //          }
    109         }
    110 
    111     }
    112     var body: some View {
    113         if let templateContract {       // preparePayResult
    114 //            let currency = templateContract.currency ?? templateContract.amount?.currencyStr ?? UNKNOWN
    115             let a11yLabel = String(localized: "Amount to pay:", comment: "a11y, no abbreviations")
    116             let amountLabel = minimalistic ? String(localized: "Amount:")
    117                                            : a11yLabel
    118             // final destination with amountToTransfer, after user input of amount
    119             let finalDestinationI = PaymentView(stack: stack.push(),
    120                                                   url: url,
    121                                              template: true,
    122                                      amountToTransfer: $amountToTransfer,
    123                                               summary: $summary,
    124                                      amountIsEditable: amountIsEditable,
    125                                     summaryIsEditable: summaryIsEditable)
    126 
    127             // final destination with amountShortcut, when user tapped a shortcut
    128             let finalDestinationS = PaymentView(stack: stack.push(),
    129                                                   url: url,
    130                                              template: true,
    131                                      amountToTransfer: $amountShortcut,
    132                                               summary: $summary,
    133                                      amountIsEditable: amountIsEditable,
    134                                     summaryIsEditable: summaryIsEditable)
    135 
    136             // destination to subject input
    137             let inputDestination = SubjectInputV(stack: stack.push(),
    138                                                    url: url,
    139                                        amountAvailable: nil,
    140                                       amountToTransfer: $amountToTransfer,
    141                                            amountLabel: amountLabel,
    142                                                summary: $summary,
    143 //                                        insufficient: $insufficient,
    144 //                                           feeAmount: $feeAmount,
    145                                           feeIsNotZero: true, // TODO: feeIsNotZero()
    146                                             targetView: finalDestinationI)
    147 
    148             // destination to subject input, when user tapped an amount shortcut
    149             let shortcutDestination = SubjectInputV(stack: stack.push(),
    150                                                       url: url,
    151                                           amountAvailable: nil,
    152                                          amountToTransfer: $amountShortcut,
    153                                               amountLabel: amountLabel,
    154                                                   summary: $summary,
    155 //                                           insufficient: $insufficient,
    156 //                                              feeAmount: $feeAmount,
    157                                              feeIsNotZero: true, // TODO: feeIsNotZero()
    158                                                targetView: finalDestinationS)
    159           Group {
    160             if amountIsEditable {           // template contract amount is not fixed => let the user input an amount first
    161                 let amountInput = AmountInputV(stack: stack.push(),
    162                                                scope: scope,
    163                                      amountAvailable: $amountAvailable,
    164                                          amountLabel: amountLabel,
    165                                            a11yLabel: a11yLabel,
    166                                     amountToTransfer: $amountToTransfer,
    167                                       amountLastUsed: amountLastUsed,
    168                                              wireFee: nil,
    169                                              summary: $summary,
    170                                       shortcutAction: shortcutAction,
    171                                         buttonAction: buttonAction1,
    172                                           isIncoming: false,
    173                                           computeFee: computeFeePayTemplate)
    174                 ScrollView {
    175                     if summaryIsEditable {  // after amount input,
    176                         amountInput
    177                             .background( NavLink($shortcutSelected) { shortcutDestination } )
    178                             .background( NavLink($buttonSelected1) { inputDestination} )
    179 
    180                     } else {
    181                         amountInput
    182                             .background( NavLink($shortcutSelected) { finalDestinationS } )
    183                             .background( NavLink($buttonSelected1) { finalDestinationI } )
    184                     }
    185                 } // amountInput
    186             } else if summaryIsEditable {   // template contract summary is not fixed => let the user input a summary
    187                 ScrollView {
    188                     inputDestination
    189                         .background( NavLink($buttonSelected2) { finalDestinationI } )
    190                 } // inputDestination
    191             } else {    // both template contract amount and summary are fixed => directly show the payment
    192                 // Attention: contains a List, thus mustn't be included in a ScrollView
    193                 PaymentView(stack: stack.push(),
    194                               url: url,
    195                          template: true,
    196                  amountToTransfer: $amountToTransfer,
    197                           summary: $summary,
    198                  amountIsEditable: amountIsEditable,
    199                 summaryIsEditable: summaryIsEditable)
    200             }
    201           } .navigationTitle(navTitle)
    202 //            .ignoresSafeArea(.keyboard, edges: .bottom)
    203             .frame(maxWidth: .infinity, alignment: .leading)
    204             .background(FullBackground())
    205             .onAppear() {
    206                 symLog.log("onAppear")
    207                 DebugViewC.shared.setSheetID(SHEET_PAY_TEMPLATE)
    208             }
    209         } else {
    210             LoadingView(stack: stack.push(), scopeInfo: nil, message: url.host)
    211                 .task { await viewDidLoad() }
    212         }
    213     }
    214 }