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