taler-ios

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

QRCodeDetailView.swift (5627B)


      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 AVFoundation
     11 
     12 struct QRCodeDetailView: View {
     13     let stack: CallStack
     14     let talerURI: String
     15     let incoming: Bool
     16     let amount: Amount
     17     let scope: ScopeInfo?
     18     let subject: String?
     19 
     20     @EnvironmentObject private var controller: Controller
     21     @AppStorage("minimalistic") var minimalistic: Bool = false
     22     @AppStorage("showQRauto16") var showQRauto16: Bool = true   // iOS 16 doesn't have NFC emulation
     23     @AppStorage("showQRauto17") var showQRauto17: Bool = false  // but iOS 17 does
     24 
     25     @State private var showQRcode = false
     26     @State private var currencyInfo: CurrencyInfo?
     27     @State private var qrImage: UIImage? = nil
     28 
     29     private func currencyTickerChanged() async {
     30         if let scope {
     31             currencyInfo = controller.info(for: scope)
     32         }
     33     }
     34 
     35     private func amountStr(_ currencyInfo : CurrencyInfo?) -> (String, String) {
     36         let amountFormatted: (String, String)
     37         let readable = amount.readableDescription
     38         let myCurrencyInfo = currencyInfo ?? (scope != nil ? controller.info(for: scope!) : nil)
     39         if let myCurrencyInfo {
     40             amountFormatted = amount.formatted(myCurrencyInfo, isNegative: false,
     41                                                useISO: false, a11yDecSep: nil)
     42         } else {
     43             amountFormatted = (readable, readable)
     44         }
     45         return amountFormatted
     46     }
     47 
     48     private func requesting(_ amountS: String) -> String {
     49         minimalistic ? String(localized: "(payer) 1 mini",
     50                            defaultValue: "Requesting \(amountS)",
     51                                 comment: "e.g. '5,3 €'")
     52                      : String(localized: "(payer) 1",
     53                            defaultValue: "Scan this to pay \(amountS)",
     54                                 comment: "e.g. '5,3 €'")
     55     }
     56     private func sending(_ amountS: String) -> String {
     57         minimalistic ? String(localized: "(payee) 1 mini",
     58                            defaultValue: "Sending \(amountS)",
     59                                 comment: "e.g. '$ 7.41'")
     60                      : String(localized: "(payee) 1",
     61                            defaultValue: "Scan this to receive \(amountS)",
     62                                 comment: "e.g. '$ 7.41'")
     63     }
     64     private var talerCopyShare: String {
     65         if talerURI.hasPrefix("taler://") {
     66             let httpString = String("https://wallet.taler.net/link#\(talerURI.dropFirst(8))")
     67             return talerURI + LINEFEED + httpString
     68         }
     69         return talerURI
     70     }
     71 
     72     var body: some View {
     73         if talerURI.count > 10 {
     74             Section {
     75                 let amountStr = amountStr(currencyInfo)
     76                 let scanLong = incoming ? (requesting(amountStr.0), requesting(amountStr.1))
     77                                         : (sending(amountStr.0), sending(amountStr.1))
     78                 let logo = Image(TALER_LOGO_QR)
     79                 let size = 276.0            // 240.0
     80                 let logoSize = 60.0         // 88 is too big, Android phones don't recognize the QR code anymore
     81                 let qrView = ZStack {
     82                     GradientBorder(size: size + 20.0,
     83                                   color: WalletColors().primaryAccent,
     84                              background: WalletColors().backgroundColor)
     85                     QRGeneratorView(image: qrImage, size: size,
     86                                     logo: logo, logoSize: logoSize)
     87                         .frame(maxWidth: .infinity, alignment: .center)
     88                 }
     89                 if #available(iOS 17.7, *) {
     90                     BorderWithHCE(talerURI: talerURI, nfcHint: true, size: size, scanHints: scanLong) {
     91                         qrView
     92                     }
     93                 } else if showQRcode {
     94                     qrView
     95                 } else {
     96                     let qrCode = Image(systemName: QRCODE)                      // 􀖂 "qrcode"
     97                     Button(minimalistic ? "\(qrCode)" : "\(qrCode) Show QR code") {
     98                         withAnimation { showQRcode = true }
     99                     }.buttonStyle(TalerButtonStyle(type: .prominent))
    100                 }
    101                 CopyShare(stack.push(), talerCopyShare, image: qrImage,
    102                           subject: subject, talerURI: talerURI)
    103                     .disabled(false)
    104 //                  .padding(.bottom)
    105                     .listRowSeparator(.hidden)
    106                 
    107             }
    108             .task(id: controller.currencyTicker) { await currencyTickerChanged() }
    109             .task {
    110                 if let image = QRCode(from: talerURI) {
    111                     qrImage = image
    112                 }
    113                 withAnimation {
    114                     if #available(iOS 17.7, *) {
    115                         showQRcode = showQRauto17
    116                     } else {
    117                         showQRcode = showQRauto16
    118                     }
    119                 }
    120             }
    121         }
    122     }
    123 }
    124 // MARK: -
    125 #if DEBUG
    126 //fileprivate struct ContentView: View {
    127 //    @State private var previewURI: String = "taler://pay-push/exchange.demo.taler.net/95ZG4D1AGFGZQ7CNQ1V49D3FT18HXKA6HQT4X3XME9YSJQVFQ520"
    128 //
    129 //    var body: some View {
    130 //        let amount = Amount(currency: LONGCURRENCY, cent: 123)
    131 //        List {
    132 //            QRCodeDetailView(talerURI: previewURI, incoming: false, amount: amount)
    133 //        }
    134 //    }
    135 //}
    136 //struct QRCodeDetailView_Previews: PreviewProvider {
    137 //
    138 //    static var previews: some View {
    139 //        ContentView()
    140 //    }
    141 //}
    142 #endif