P2PReadyV.swift (6020B)
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 SymLog 11 12 // Called when initiating a P2P transaction: Send or Request(Invoice) 13 struct P2PReadyV: View { 14 private let symLog = SymLogV(0) 15 let stack: CallStack 16 let scope: ScopeInfo 17 let summary: String 18 let iconID: String? 19 let expireDays: UInt 20 let outgoing: Bool 21 let amountToTransfer: Amount 22 @Binding var transactionStarted: Bool 23 24 @EnvironmentObject private var controller: Controller 25 @EnvironmentObject private var model: WalletModel 26 #if DEBUG 27 @AppStorage("developerMode") var developerMode: Bool = true 28 #else 29 @AppStorage("developerMode") var developerMode: Bool = false 30 #endif 31 @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic 32 33 @State private var transactionId: String? = nil 34 @State private var initiationError: Error? = nil 35 @State private var noTransaction: TalerTransaction? = nil 36 @State private var talerTX = TalerTransaction(dummyCurrency: DEMOCURRENCY) 37 @Namespace var namespace 38 39 @MainActor 40 private func viewDidLoad() async { 41 symLog.log("viewDidLoad") 42 guard transactionStarted == false else { 43 // TODO: logger.warning("Trying to start P2P a second time") 44 symLog.log("Yikes❗️ Trying to start P2P a second time") 45 return 46 } 47 transactionStarted = true 48 // keep expiration of outgoing P2P in developer mode for debugging 49 let timestamp = developerMode ? Timestamp.inSomeMinutes(expireDays > 20 ? (24*60) // 24h 50 : expireDays > 5 ? 60 // 1h 51 : 3) // 3m 52 : Timestamp.inSomeDays(expireDays) 53 let purseExpiration = developerMode ? timestamp 54 : outgoing ? nil : timestamp // nil for outgoing (non-dev) 55 let terms = PeerContractTerms(amount: amountToTransfer, 56 summary: summary, 57 purse_expiration: purseExpiration, 58 icon_id: iconID) 59 do { 60 if outgoing { 61 let response = try await model.initiatePeerPushDebit(scope: scope, terms: terms, 62 viewHandles: true) 63 // will switch from WithdrawProgressView to TransactionSummaryList 64 transactionId = response.transactionId 65 } else { 66 // scope is the exchange the user picked in the ScopePicker, and the one the 67 // fee was computed for. nil (== wallet-core decides) only for global scope. 68 let response = try await model.initiatePeerPullCredit(scope.url, terms: terms, 69 viewHandles: true) 70 // will switch from WithdrawProgressView to TransactionSummaryList 71 transactionId = response.transactionId 72 } 73 } catch { 74 symLog.log("❗️ \(error), \(error.localizedDescription)") 75 transactionStarted = false // failed, so let the user try again 76 initiationError = error // we show it ourselves (viewHandles: true) 77 } 78 } 79 80 func doneAction() { 81 dismissTop(stack.push()) 82 } 83 84 var body: some View { 85 #if PRINT_CHANGES 86 let _ = Self._printChanges() 87 let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear 88 #endif 89 let navTitle = String(localized: "Ready") 90 ZStack { 91 if let transactionId { 92 TransactionSummaryList(stack: stack.push(), 93 // scope: scope, 94 transactionId: transactionId, 95 talerTX: $talerTX, 96 navTitle: navTitle, 97 hasDone: true, // conclude p2p 98 showDone: .prominent, 99 url: nil, 100 withActions: false) 101 } else if let initiationError { 102 // don't spin forever - the user can go back and start over 103 ErrorView(stack.push(), error: initiationError, devMode: developerMode) 104 } else { 105 #if DEBUG 106 let message = amountToTransfer.currencyStr 107 #else 108 let message: String? = nil 109 #endif 110 LoadingView(stack: stack.push(), scopeInfo: scope, message: message) 111 .task { await viewDidLoad() } 112 } 113 }.onAppear { 114 symLog.log("onAppear") 115 DebugViewC.shared.setViewID(VIEW_P2P_READY, stack: stack.push()) 116 } 117 .onDisappear { 118 // print("❗️ P2PReadyV onDisappear") 119 } 120 #if OIM 121 .overlay { if #available(iOS 16.4, *) { 122 if controller.oimModeActive { 123 OIMp2pReadyView(stack: stack.push(), 124 transactionId: $transactionId, 125 talerTX: talerTX, 126 scope: scope, 127 action: doneAction) 128 .environmentObject(NamespaceWrapper(namespace)) // keep OIMviews apart 129 } 130 } } 131 #endif 132 } 133 } 134 // MARK: - 135 //struct SendNow_Previews: PreviewProvider { 136 // static var previews: some View { 137 // Group { 138 // SendDoneV(stack: CallStack("Preview"), 139 // amountToSend: Amount(currency: LONGCURRENCY, cent: 480), 140 // amountToReceive: nil, 141 // summary: "some subject/purpose", 142 // expireDays: 0) 143 // } 144 // } 145 //}