taler-ios

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

ManualDetailsV.swift (8260B)


      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 OrderedCollections
     10 import taler_swift
     11 
     12 struct ManualDetailsV: View {
     13     let stack: CallStack
     14     let common: TransactionCommon
     15     let details: WithdrawalDetails
     16 
     17     @EnvironmentObject private var model: WalletModel
     18     @AppStorage("minimalistic") var minimalistic: Bool = false
     19     @State private var accountID = 0
     20     @State private var listID = UUID()
     21     @State private var qrCodeSpecs: [QrCodeSpec] = []
     22 
     23     func redraw(_ newAccount: Int) -> Void {
     24         if newAccount != accountID {
     25             accountID = newAccount
     26             withAnimation { listID = UUID() }
     27         }
     28     }
     29     func validDetails(_ details: [ExchangeAccountDetails]) -> [ExchangeAccountDetails] {
     30         details.filter { detail in
     31             detail.status.lowercased() == "ok"
     32         }
     33     }
     34 
     35     @MainActor
     36     private func viewDidLoad(_ paytoUri: String) async {
     37         if let specs = try? await model.getQrCodesForPayto(paytoUri) {
     38             qrCodeSpecs = specs
     39             return
     40         }
     41         qrCodeSpecs = []
     42     }
     43 
     44     var body: some View {
     45         if let accountDetails = details.exchangeCreditAccountDetails {
     46             let validDetails = validDetails(accountDetails)
     47             if validDetails.count > 0 {
     48                 let account = validDetails[accountID]
     49                 if let amount = account.transferAmount {
     50                     let specs = account.currencySpecification
     51                     let amountStr = common.amountRaw.formatted(specs: specs, isNegative: false)
     52                     let amountValue = common.amountRaw.valueStr
     53                     let obtainStr = common.amountEffective.formatted(specs: specs, isNegative: false)
     54 //            let _ = print(amountStr, " | ", obtainStr)
     55                     if !minimalistic {
     56                         Text("The payment service is waiting for your wire-transfer.")
     57                             .bold()
     58                             .multilineTextAlignment(.leading)
     59                             .listRowSeparator(.hidden)
     60                     }
     61                     if validDetails.count > 1 {
     62                         if validDetails.count > 3 { // too many for SegmentControl
     63                             AccountPicker(title: String(localized: "Bank"),
     64                                           value: $accountID,
     65                                  accountDetails: validDetails,
     66                                          action: redraw)
     67                             .listRowSeparator(.hidden)
     68                             .pickerStyle(.menu)
     69                         } else {
     70                             SegmentControl(value: $accountID, accountDetails: validDetails, action: redraw)
     71                                 .listRowSeparator(.hidden)
     72                         }
     73                     } else if let amount = account.transferAmount {
     74                         if let bankName = account.bankLabel {
     75                             Text(bankName + ":   " + amountStr.0)
     76                                 .accessibilityLabel(bankName + ":   " + amountStr.1)
     77 //                        } else {
     78 //                            Text(amountStr)
     79                         }
     80                     }
     81                     let payto = PayTo(account.paytoUri)
     82                     if let receiverStr = payto.receiver {
     83                         let wireDetails = ManualDetailsWireV(stack: stack.push(),
     84                                                         reservePub: details.reservePub,
     85                                                        receiverStr: receiverStr,
     86                                                        receiverZip: payto.postalCode,
     87                                                       receiverTown: payto.town,
     88                                                               iban: payto.iban,
     89                                                             xTaler: payto.xTaler ?? EMPTYSTRING,
     90                                                        amountValue: amountValue,
     91                                                          amountStr: amountStr,
     92                                                          obtainStr: obtainStr,
     93                                                          debitIBAN: nil,        // only for deposit auth
     94                                                            account: account)
     95                         Group {
     96                             NavigationLink(destination: wireDetails) {
     97                                 Text(minimalistic ? "Instructions"
     98                                                   : "Wire transfer instructions")
     99                                 .talerFont(.title3)
    100                             }
    101 
    102                             if qrCodeSpecs.count > 0 {
    103                                 let qrCodesForPayto = QRcodesForPayto(stack: stack.push(), qrCodeSpecs: $qrCodeSpecs)
    104                                 NavigationLink(destination: qrCodesForPayto) {
    105                                     Text(minimalistic ? "QR"
    106                                                       : "Wire transfer QR codes")
    107                                     .talerFont(.title3)
    108                                 }
    109                                 .listRowSeparator(.automatic)
    110                             }
    111 #if DEBUG
    112                             if let iban = payto.iban {
    113                                 Text(minimalistic ? "**Alternative:** Use this PayTo-Link:"
    114                                     : "**Alternative:** If your bank already supports PayTo, you can use this PayTo-Link instead:")
    115                                     .multilineTextAlignment(.leading)
    116                                     .padding(.top)
    117                                     .listRowSeparator(.hidden)
    118                                 let title = String(localized: "Share the PayTo URL", comment: "a11y")
    119                                 let minTitle = String(localized: "Share PayTo", comment: "mini")
    120                                 let textToShare = String("\(payto)\n\nIBAN: \(iban)\nReceiver: \(receiverStr)\nAmount: \(amountStr.1)\nSubject: \(details.reservePub)")
    121             let _ = print(textToShare)
    122                                 ShareButton(textToShare: textToShare, title: minimalistic ? minTitle : title)
    123                                     .frame(maxWidth: .infinity, alignment: .center)
    124                                     .accessibilityLabel(Text(title))
    125                                     .disabled(false)
    126                                     .listRowSeparator(.hidden)
    127                             }
    128 #endif
    129                         }.id(listID)
    130                             .talerFont(.body)
    131                             .task { await viewDidLoad(account.paytoUri) }
    132                     } else {
    133                         // TODO: Error No payto URL
    134                     }
    135                 } else {
    136                     // TODO: Error No amount
    137                 }
    138             } else {
    139                 // TODO: Error none of the details is valid
    140             }
    141         } else {
    142             // TODO: Error No exchangeCreditAccountDetails
    143         }
    144     }
    145 }
    146 // MARK: -
    147 #if DEBUG
    148 struct ManualDetails_Previews: PreviewProvider {
    149     static var previews: some View {
    150         let common = TransactionCommon(type: .withdrawal,
    151                               transactionId: "someTxID",
    152                                   timestamp: Timestamp(from: 1_666_666_000_000),
    153                                      scopes: [],
    154                                     txState: TransactionState(major: .done),
    155                                   txActions: [],
    156                                   amountRaw: Amount(currency: LONGCURRENCY, cent: 220),
    157                             amountEffective: Amount(currency: LONGCURRENCY, cent: 110))
    158         let payto = "payto://iban/SANDBOXX/DE159593?receiver-name=Exchange+Company"
    159         let details = WithdrawalDetails(type: .manual, 
    160                                   reservePub: "ReSeRvEpUbLiC_KeY_FoR_WiThDrAwAl",
    161                               reserveIsReady: false,
    162                                    confirmed: false)
    163         List {
    164             ManualDetailsV(stack: CallStack("Preview"), common: common, details: details)
    165         }
    166     }
    167 }
    168 #endif