taler-ios

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

ManualDetailsV.swift (9964B)


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