P2pPayURIView.swift (5548B)
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 taler_swift 10 import SymLog 11 12 // Called either when scanning a QR code or tapping the provided link 13 // from another user's Request(Invoice). We show the P2P details. 14 struct P2pPayURIView: View { 15 private let symLog = SymLogV(0) 16 let stack: CallStack 17 18 // the scanned URL 19 let url: URL 20 21 @EnvironmentObject private var model: WalletModel 22 @EnvironmentObject private var controller: Controller 23 @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic 24 25 @State private var peerPullDebitResponse: PreparePeerPullDebitResponse? 26 27 let navTitle = String(localized: "Pay Request", comment: "Nav Title") 28 29 @MainActor 30 private func viewDidLoad() async { 31 do { 32 symLog.log(".task") 33 let response = try? await model.preparePeerPullDebit(url.absoluteString) 34 if let response { 35 controller.removeURL(url) // tx is now saved by wallet-core 36 } 37 peerPullDebitResponse = response 38 } 39 } 40 41 var body: some View { 42 VStack { 43 if let peerPullDebitResponse { 44 List { 45 PeerPullDebitView(stack: stack.push(), 46 raw: peerPullDebitResponse.amountRaw, 47 effective: peerPullDebitResponse.amountEffective, 48 isDone: false, 49 scope: peerPullDebitResponse.scopeInfo, 50 summary: peerPullDebitResponse.contractTerms.summary) 51 let expiration = peerPullDebitResponse.contractTerms.purse_expiration 52 ExpiresView(expiration: expiration) 53 } 54 .listStyle(myListStyle.style).anyView 55 .navigationTitle(navTitle) 56 // .task(id: controller.currencyTicker) { 57 // let currency = peerPullDebitResponse.amountRaw.currencyStr 58 // currencyInfo = controller.info2(for: currency, controller.currencyTicker) 59 // } 60 .safeAreaInset(edge: .bottom) { 61 if peerPullDebitResponse.txState.isConfirmed { 62 Button("Done") { dismissTop(stack.push()) } 63 .buttonStyle(TalerButtonStyle(type: .prominent)) 64 .padding(.horizontal) 65 } else { 66 PeerPullDebitConfirm(stack: stack.push(), url: url, 67 transactionId: peerPullDebitResponse.transactionId) 68 } 69 } 70 } else { 71 #if DEBUG 72 let message = url.host 73 #else 74 let message: String? = nil 75 #endif 76 LoadingView(stack: stack.push(), scopeInfo: nil, message: message) 77 .task { await viewDidLoad() } 78 } 79 } 80 .onAppear() { 81 symLog.log("onAppear") 82 DebugViewC.shared.setSheetID(SHEET_PAY_P2P, stack: stack.push()) 83 } 84 } 85 } 86 // MARK: - 87 //#Preview { 88 // P2pPayURIView(url: <#T##URL#>, model: <#T##WalletModel#>) 89 //} 90 // MARK: - 91 struct PeerPullDebitConfirm: View { 92 let stack: CallStack 93 let url: URL? 94 let transactionId: String 95 96 var body: some View { 97 let destination = P2pAcceptDone(stack: stack.push(), 98 url: url, 99 transactionId: transactionId, 100 incoming: false) 101 NavigationLink(destination: destination) { 102 Text("Confirm Payment", comment:"pay P2P request/invoice") // SHEET_PAY_P2P 103 } 104 .buttonStyle(TalerButtonStyle(type: .prominent)) 105 .padding(.horizontal) 106 } 107 } 108 // MARK: - 109 struct PeerPullDebitView: View { 110 let stack: CallStack 111 // let peerPullDebitResponse: PreparePeerPullDebitResponse 112 let raw: Amount 113 let effective: Amount 114 let isDone: Bool 115 let scope: ScopeInfo? 116 let summary: String 117 118 @Environment(\.colorScheme) private var colorScheme 119 @Environment(\.colorSchemeContrast) private var colorSchemeContrast 120 @AppStorage("minimalistic") var minimalistic: Bool = false 121 var body: some View { 122 // let raw = peerPullDebitResponse.amountRaw 123 // let effective = peerPullDebitResponse.amountEffective 124 // let scope = peerPullDebitResponse.scopeInfo 125 let fee = try! Amount.diff(raw, effective) 126 ThreeAmountsSection(stack: stack.push(), 127 scope: scope, 128 topTitle: String(localized: "Amount to pay:"), 129 topAbbrev: String(localized: "Pay:", comment: "mini"), 130 topAmount: raw, 131 noFees: nil, // TODO: check baseURL for fees 132 fee: fee, 133 bottomTitle: String(localized: "Amount to be spent:"), 134 bottomAbbrev: String(localized: "Effective:", comment: "mini"), 135 bottomAmount: effective, 136 large: false, 137 pendingDialog: false, 138 isDone: isDone, 139 incoming: false, 140 baseURL: nil, 141 txStateLcl: nil, 142 summary: summary, 143 products: nil) 144 } 145 }