taler-ios

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

ManualDetailsV.swift (9364B)


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