summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Stibane <marc@taler.net>2023-08-08 12:00:12 +0200
committerMarc Stibane <marc@taler.net>2023-08-08 12:04:30 +0200
commite728e0f48e9bb6f384b205db82c8c1dadd700c00 (patch)
tree6c2c3f1223d6d67407d34ffac4144e21a7d6a647
parentf6a838560b5d7fc6f80b74b33c4baf099c30e331 (diff)
downloadtaler-ios-e728e0f48e9bb6f384b205db82c8c1dadd700c00.tar.gz
taler-ios-e728e0f48e9bb6f384b205db82c8c1dadd700c00.tar.bz2
taler-ios-e728e0f48e9bb6f384b205db82c8c1dadd700c00.zip
started with PayTemplates
-rw-r--r--TalerWallet.xcodeproj/project.pbxproj4
-rw-r--r--TalerWallet1/Controllers/Controller.swift3
-rw-r--r--TalerWallet1/Controllers/DebugViewC.swift1
-rw-r--r--TalerWallet1/Model/Model+Payment.swift18
-rw-r--r--TalerWallet1/Views/Payment/PayTemplateView.swift113
-rw-r--r--TalerWallet1/Views/Sheets/URLSheet.swift6
6 files changed, 144 insertions, 1 deletions
diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj
index 5024d76..eae83d9 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -96,6 +96,7 @@
4EB095702989CBFE0043A8A1 /* PendingOpsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0954E2989CBFE0043A8A1 /* PendingOpsListView.swift */; };
4EB3136129FEE79B007D68BC /* SendDone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB3136029FEE79B007D68BC /* SendDone.swift */; };
4EB431672A1E55C700C5690E /* ManualWithdrawDone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB431662A1E55C700C5690E /* ManualWithdrawDone.swift */; };
+ 4EBA56412A7FF5200084948B /* PayTemplateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA56402A7FF5200084948B /* PayTemplateView.swift */; };
4EBA82AB2A3EB2CA00E5F39A /* TransactionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA82AA2A3EB2CA00E5F39A /* TransactionButton.swift */; };
4EBA82AD2A3F580500E5F39A /* QuiteSomeCoins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA82AC2A3F580500E5F39A /* QuiteSomeCoins.swift */; };
4EC90C782A1B528B0071DC58 /* ExchangeSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */; };
@@ -234,6 +235,7 @@
4EB0954E2989CBFE0043A8A1 /* PendingOpsListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PendingOpsListView.swift; sourceTree = "<group>"; };
4EB3136029FEE79B007D68BC /* SendDone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendDone.swift; sourceTree = "<group>"; };
4EB431662A1E55C700C5690E /* ManualWithdrawDone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualWithdrawDone.swift; sourceTree = "<group>"; };
+ 4EBA56402A7FF5200084948B /* PayTemplateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayTemplateView.swift; sourceTree = "<group>"; };
4EBA82AA2A3EB2CA00E5F39A /* TransactionButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionButton.swift; sourceTree = "<group>"; };
4EBA82AC2A3F580500E5F39A /* QuiteSomeCoins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuiteSomeCoins.swift; sourceTree = "<group>"; };
4EC90C772A1B528B0071DC58 /* ExchangeSectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExchangeSectionView.swift; sourceTree = "<group>"; };
@@ -452,6 +454,7 @@
isa = PBXGroup;
children = (
4EB0952D2989CBFE0043A8A1 /* PaymentView.swift */,
+ 4EBA56402A7FF5200084948B /* PayTemplateView.swift */,
);
path = Payment;
sourceTree = "<group>";
@@ -791,6 +794,7 @@
4EB3136129FEE79B007D68BC /* SendDone.swift in Sources */,
4EB0956B2989CBFE0043A8A1 /* TextFieldAlert.swift in Sources */,
4EBA82AD2A3F580500E5F39A /* QuiteSomeCoins.swift in Sources */,
+ 4EBA56412A7FF5200084948B /* PayTemplateView.swift in Sources */,
4EB431672A1E55C700C5690E /* ManualWithdrawDone.swift in Sources */,
4E9320472A164BC700A87B0E /* PaymentPurpose.swift in Sources */,
4E753A082A0B6A5F002D9328 /* ShareSheet.swift in Sources */,
diff --git a/TalerWallet1/Controllers/Controller.swift b/TalerWallet1/Controllers/Controller.swift
index 96e1fef..17201f5 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -21,6 +21,7 @@ enum UrlCommand {
case pay
case payPull
case payPush
+ case payTemplate
}
// MARK: -
@@ -103,6 +104,8 @@ extension Controller {
return UrlCommand.payPull
case "pay-push":
return UrlCommand.payPush
+ case "pay-template":
+ return UrlCommand.payTemplate
default:
symLog.log("unknown command taler://\(command)")
}
diff --git a/TalerWallet1/Controllers/DebugViewC.swift b/TalerWallet1/Controllers/DebugViewC.swift
index f25b353..4cd365c 100644
--- a/TalerWallet1/Controllers/DebugViewC.swift
+++ b/TalerWallet1/Controllers/DebugViewC.swift
@@ -73,6 +73,7 @@ public let SHEET_WITHDRAW_CONFIRM = SHEET_WITHDRAW_ACCEPT + 1 // 133 waiti
// MARK: Merchant Payment
// openURL (Link, NFC or scan QR) ==> pays merchant
public let SHEET_PAYMENT = SHEET_WITHDRAWAL + 10 // 140 Pay Merchant
+public let SHEET_PAY_TEMPLATE = SHEET_PAYMENT + 2 // 142 Pay Merchant Template
// MARK: Reward - Receive Coins (from merchant)
// openURL (Link, NFC or scan QR) ==> receive coins from merchant
diff --git a/TalerWallet1/Model/Model+Payment.swift b/TalerWallet1/Model/Model+Payment.swift
index 51e8d57..88872e2 100644
--- a/TalerWallet1/Model/Model+Payment.swift
+++ b/TalerWallet1/Model/Model+Payment.swift
@@ -147,6 +147,17 @@ fileprivate struct PreparePayForUri: WalletBackendFormattedRequest {
var talerPayUri: String
}
}
+/// A request to get an exchange's payment contract terms.
+fileprivate struct PreparePayForTemplate: WalletBackendFormattedRequest {
+ typealias Response = PreparePayResult
+ func operation() -> String { return "preparePayForTemplate" }
+ func args() -> Args { return Args(talerPayTemplateUri: talerPayTemplateUri) }
+
+ var talerPayTemplateUri: String
+ struct Args: Encodable {
+ var talerPayTemplateUri: String
+ }
+}
// MARK: -
/// The result from confirmPayForUri
struct ConfirmPayResult: Decodable {
@@ -176,6 +187,13 @@ extension WalletModel {
return response
}
@MainActor
+ func preparePayForTemplateM(_ talerPayTemplateUri: String) // M for MainActor
+ async throws -> PreparePayResult {
+ let request = PreparePayForTemplate(talerPayTemplateUri: talerPayTemplateUri)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ return response
+ }
+ @MainActor
func confirmPayM(_ transactionId: String) // M for MainActor
async throws -> ConfirmPayResult {
let request = confirmPayForUri(transactionId: transactionId)
diff --git a/TalerWallet1/Views/Payment/PayTemplateView.swift b/TalerWallet1/Views/Payment/PayTemplateView.swift
new file mode 100644
index 0000000..526d0b0
--- /dev/null
+++ b/TalerWallet1/Views/Payment/PayTemplateView.swift
@@ -0,0 +1,113 @@
+/*
+ * This file is part of GNU Taler, ©2022-23 Taler Systems S.A.
+ * See LICENSE.md
+ */
+import SwiftUI
+import taler_swift
+import SymLog
+
+// Will be called either by the user scanning a QR code or tapping the provided link,
+// both from the shop's website. We show the payment details
+struct PayTemplateView: View {
+ private let symLog = SymLogV()
+ let navTitle = String(localized: "Confirm Payment", comment:"pay merchant")
+
+ @EnvironmentObject private var controller: Controller
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
+
+ // the scanned URL
+ let url: URL
+
+ @EnvironmentObject private var model: WalletModel
+
+ func acceptAction(preparePayResult: PreparePayResult) {
+ Task {
+ do {
+ let confirmPayResult = try await model.confirmPayM(preparePayResult.transactionId)
+ // symLog.log(confirmPayResult as Any)
+ if confirmPayResult.type != "done" {
+ controller.playSound(0)
+ // TODO: show error
+ }
+ } catch {
+ controller.playSound(0)
+ // TODO: error
+ symLog.log(error.localizedDescription)
+ }
+ dismissTop()
+ }
+ }
+
+ @State var preparePayResult: PreparePayResult? = nil
+
+ func query(url: URL) -> String? {
+ if let query = url.query {
+ let array = query.components(separatedBy: "&")
+ }
+ return nil
+ }
+
+ var body: some View {
+ if let preparePayResult {
+ let effective = preparePayResult.amountEffective
+ List {
+ let baseURL = preparePayResult.contractTerms.exchanges.first?.url
+ let raw = preparePayResult.amountRaw
+ let currency = raw.currencyStr
+ let topTitle = String(localized: "Amount to pay:")
+ if let effective {
+ // TODO: already paid
+ let fee = try! Amount.diff(raw, effective) // TODO: different currencies
+ ThreeAmountsView(topTitle: topTitle,
+ topAmount: raw, fee: fee,
+ bottomTitle: String(localized: "\(currency) to be spent:"),
+ bottomAmount: effective,
+ large: false, pending: false, incoming: false,
+ baseURL: baseURL)
+ // TODO: payment: popup with all possible exchanges, check fees
+ } else if let balanceDetails = preparePayResult.balanceDetails { // Insufficient
+ Text("You don't have enough \(currency)")
+ ThreeAmountsView(topTitle: topTitle,
+ topAmount: raw, fee: nil,
+ bottomTitle: String(localized: "\(currency) available:"),
+ bottomAmount: balanceDetails.balanceAvailable,
+ large: false, pending: false, incoming: false,
+ baseURL: baseURL)
+ } else {
+ // TODO: Error - neither effective nor balanceDetails
+ Text("Error")
+ }
+ }
+ .listStyle(myListStyle.style).anyView
+ .safeAreaInset(edge: .bottom) {
+ if let effective {
+ Button(navTitle, action: { acceptAction(preparePayResult: preparePayResult) })
+ .buttonStyle(TalerButtonStyle(type: .prominent))
+ .padding(.horizontal)
+ } else {
+ Button("Cancel", action: { dismissTop() })
+ .buttonStyle(TalerButtonStyle(type: .bordered))
+ .padding(.horizontal)
+ }
+ }
+ .navigationTitle(navTitle)
+ .onAppear() {
+ symLog.log("onAppear")
+ DebugViewC.shared.setSheetID(SHEET_PAY_TEMPLATE)
+ }
+ } else {
+ let badURL = "Error in Link: \(url)"
+ WithdrawProgressView(message: url.host ?? badURL)
+ .navigationTitle("Find Exchange")
+ .task {
+ do {
+ symLog.log(".task")
+ let result = try await model.preparePayForTemplateM(url.absoluteString)
+ preparePayResult = result
+ } catch { // TODO: error
+ symLog.log(error.localizedDescription)
+ }
+ }
+ }
+ }
+}
diff --git a/TalerWallet1/Views/Sheets/URLSheet.swift b/TalerWallet1/Views/Sheets/URLSheet.swift
index 42ec8b2..1db6169 100644
--- a/TalerWallet1/Views/Sheets/URLSheet.swift
+++ b/TalerWallet1/Views/Sheets/URLSheet.swift
@@ -24,7 +24,11 @@ struct URLSheet: View {
P2pPayURIView(url: urlToOpen)
case .payPush:
P2pReceiveURIView(url: urlToOpen)
- case .unknown: // Error view
+ case .payTemplate:
+ PayTemplateView(url: urlToOpen)
+// case .reward:
+// RewardURIView(url: urlToOpen)
+ default: // Error view
VStack {
Text("unknown command")
.font(.title)