[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-ios] branch master updated (df4fe35 -> 4f2b20c)
From: |
gnunet |
Subject: |
[taler-taler-ios] branch master updated (df4fe35 -> 4f2b20c) |
Date: |
Wed, 22 Feb 2023 16:16:27 +0100 |
This is an automated email from the git hooks/post-receive script.
marc-stibane pushed a change to branch master
in repository taler-ios.
from df4fe35 Build instructions
new 3add557 Error handling, Amount.diff
new 3cb19f2 ported remaining sync wallet-core funcs to try await
new 744d32a added ext+taler and web+taler to the list of recognized URL
schemes
new a4069f8 Constants, cleanup
new cc28130 Transaction definition and JSON decoding - Bug 7678
new a383bd5 Info & SceneConfigurations, v0.9.2, bundleID
new 4f2b20c Transaction list and details
The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
Info.plist | 11 +-
TalerWallet.xcodeproj/project.pbxproj | 22 +-
TalerWallet1/Backend/Transaction.swift | 407 +++++++++------------
TalerWallet1/Backend/WalletCore.swift | 18 +-
TalerWallet1/Controllers/Controller.swift | 2 +-
TalerWallet1/Controllers/TalerWallet1App.swift | 9 +-
.../{TalerStrings.swift => PublicConstants.swift} | 16 +-
TalerWallet1/Model/ExchangeTestModel.swift | 87 ++---
TalerWallet1/Model/WalletInitModel.swift | 6 +-
.../Views/Balances/CurrenciesListView.swift | 9 +-
TalerWallet1/Views/Exchange/ExchangeListView.swift | 4 +-
TalerWallet1/Views/Payment/PaymentAcceptView.swift | 2 +-
TalerWallet1/Views/Pending/PendingModel.swift | 4 +-
.../Views/Pending/PendingOpsListView.swift | 16 +-
TalerWallet1/Views/Settings/SettingsView.swift | 26 +-
.../Views/Transactions/TransactionDetail.swift | 95 +++--
.../Views/Transactions/TransactionRow.swift | 31 +-
.../Views/Transactions/TransactionsListView.swift | 30 +-
.../Views/Transactions/TransactionsModel.swift | 8 -
.../Views/Withdraw/WithdrawAcceptView.swift | 2 +-
TalerWallet1/Views/Withdraw/WithdrawURIView.swift | 2 +-
21 files changed, 388 insertions(+), 419 deletions(-)
copy TalerWallet1/Helper/{TalerStrings.swift => PublicConstants.swift} (75%)
diff --git a/Info.plist b/Info.plist
index b918fac..4f254b8 100644
--- a/Info.plist
+++ b/Info.plist
@@ -8,15 +8,24 @@
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
- <string>net.taler.talerwallet</string>
+ <string>com.taler-systems.talerwallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>taler</string>
+ <string>ext+taler</string>
+ <string>web+taler</string>
<string>payto</string>
</array>
</dict>
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
+ <key>UIApplicationSceneManifest</key>
+ <dict>
+ <key>UIApplicationSupportsMultipleScenes</key>
+ <true/>
+ <key>UISceneConfigurations</key>
+ <dict/>
+ </dict>
</dict>
</plist>
diff --git a/TalerWallet.xcodeproj/project.pbxproj
b/TalerWallet.xcodeproj/project.pbxproj
index 4d986fe..6281226 100644
--- a/TalerWallet.xcodeproj/project.pbxproj
+++ b/TalerWallet.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 4EA1ABBE29A3833A008821EA /* PublicConstants.swift in Sources */
= {isa = PBXBuildFile; fileRef = 4EA1ABBD29A3833A008821EA /*
PublicConstants.swift */; };
4EB094D629896CD20043A8A1 /* TalerWalletTests.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4EB094D429896CD20043A8A1 /*
TalerWalletTests.swift */; };
4EB094D729896CD20043A8A1 /* WalletBackendTests.swift in Sources
*/ = {isa = PBXBuildFile; fileRef = 4EB094D529896CD20043A8A1 /*
WalletBackendTests.swift */; };
4EB094DC29896D030043A8A1 /* TalerWalletUITestsLaunchTests.swift
in Sources */ = {isa = PBXBuildFile; fileRef = 4EB094D929896D030043A8A1 /*
TalerWalletUITestsLaunchTests.swift */; };
@@ -97,6 +98,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 4EA1ABBD29A3833A008821EA /* PublicConstants.swift */ = {isa =
PBXFileReference; lastKnownFileType = sourcecode.swift; path =
PublicConstants.swift; sourceTree = "<group>"; };
4EB094D429896CD20043A8A1 /* TalerWalletTests.swift */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path
= TalerWalletTests.swift; sourceTree = "<group>"; };
4EB094D529896CD20043A8A1 /* WalletBackendTests.swift */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift;
path = WalletBackendTests.swift; sourceTree = "<group>"; };
4EB094D929896D030043A8A1 /* TalerWalletUITestsLaunchTests.swift
*/ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.swift; path = TalerWalletUITestsLaunchTests.swift; sourceTree =
"<group>"; };
@@ -234,6 +236,7 @@
4EB095062989CB7C0043A8A1 /* TalerDater.swift */,
4EB095072989CB7C0043A8A1 /* TalerStrings.swift
*/,
4EB095082989CB7C0043A8A1 /*
View+dismissTop.swift */,
+ 4EA1ABBD29A3833A008821EA /*
PublicConstants.swift */,
);
path = Helper;
sourceTree = "<group>";
@@ -588,6 +591,7 @@
4EB095562989CBFE0043A8A1 /*
TransactionsListView.swift in Sources */,
4EB0951F2989CBCB0043A8A1 /*
WalletBackendRequest.swift in Sources */,
4EB095572989CBFE0043A8A1 /*
TransactionRow.swift in Sources */,
+ 4EA1ABBE29A3833A008821EA /*
PublicConstants.swift in Sources */,
4EB0956B2989CBFE0043A8A1 /*
TextFieldAlert.swift in Sources */,
4EB0956C2989CBFE0043A8A1 /* AmountView.swift in
Sources */,
4EB095592989CBFE0043A8A1 /*
TransactionsModel.swift in Sources */,
@@ -771,15 +775,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Taler
Wallet";
INFOPLIST_KEY_LSApplicationCategoryType =
"public.app-category.finance";
- INFOPLIST_KEY_NSHumanReadableCopyright = "©
Taler.net";
-
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "©
Taler-Systems.com";
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations
= UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad =
"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
@@ -788,8 +791,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.1;
- PRODUCT_BUNDLE_IDENTIFIER =
net.taler.talerwallet;
+ MARKETING_VERSION = 0.9.2;
+ PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet15";
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos
iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@@ -807,15 +810,14 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME
= AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Taler
Wallet";
INFOPLIST_KEY_LSApplicationCategoryType =
"public.app-category.finance";
- INFOPLIST_KEY_NSHumanReadableCopyright = "©
Taler.net";
-
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "©
Taler-Systems.com";
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations
= UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad =
"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
@@ -824,8 +826,8 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.1;
- PRODUCT_BUNDLE_IDENTIFIER =
net.taler.talerwallet;
+ MARKETING_VERSION = 0.9.2;
+ PRODUCT_BUNDLE_IDENTIFIER =
"com.taler-systems.talerwallet15";
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos
iphonesimulator";
SUPPORTS_MACCATALYST = NO;
diff --git a/TalerWallet1/Backend/Transaction.swift
b/TalerWallet1/Backend/Transaction.swift
index 86a0ae9..873733e 100644
--- a/TalerWallet1/Backend/Transaction.swift
+++ b/TalerWallet1/Backend/Transaction.swift
@@ -22,293 +22,214 @@ enum TransactionTypeError: Error {
case unknownTypeError
}
-/// Different types of transactions.
-enum TransactionType: Codable {
- case withdrawal
- case payment
- case refund
- case tip
- case refresh
-
- init(from decoder: Decoder) throws {
- let value = try decoder.singleValueContainer()
- let str = try value.decode(String.self)
- let codingNames = [
- "TransactionWithdrawal" : TransactionType.withdrawal,
- "TransactionPayment" : TransactionType.payment,
- "TransactionRefund" : TransactionType.refund,
- "TransactionTip" : TransactionType.tip,
- "TransactionRefresh" : TransactionType.refresh
- ]
- if let type = codingNames[str] {
- self = type
- } else {
- throw TransactionTypeError.unknownTypeError
- }
- }
-
- func encode(to encoder: Encoder) throws {
- var value = encoder.singleValueContainer()
- switch self {
- case .withdrawal:
- try value.encode("TransactionWithdrawal")
- case .payment:
- try value.encode("TransactionPayment")
- case .refund:
- try value.encode("TransactionRefund")
- case .tip:
- try value.encode("TransactionTip")
- case .refresh:
- try value.encode("TransactionRefresh")
- }
- }
-}
-
enum TransactionDecodingError: Error {
case invalidStringValue
}
-/// Details for a manual withdrawal.
-struct ManualWithdrawalDetails: Codable {
- /// The payto URIs that the exchange supports.
- var exchangePaytoUris: [String]
-
- /// The public key of the newly created reserve.
- var reservePub: String
+struct TransactionCommon: Decodable {
+ var type: String
+ var amountEffective: Amount
+ var amountRaw: Amount
+ var transactionId: String
+ var timestamp: Timestamp
+ var extendedStatus: String // TODO: enum with some fixed values?
+ var pending: Bool
+ var frozen: Bool
+
+ func fee() -> Amount {
+ do {
+ return try Amount.diff(amountRaw, amountEffective)
+ } catch {
+ return Amount(currency: amountRaw.currencyStr, integer: 0,
fraction: 0)
+ }
+ }
}
-/// Details for a bank-integrated withdrawal.
-struct BankIntegratedWithdrawalDetails: Codable {
- /// Whether the bank has confirmed the withdrawal.
- var confirmed: Bool
+struct WithdrawalDetails: Decodable {
+ enum WithdrawalType: String, Decodable {
+ case manual = "manual-transfer"
+ case bankIntegrated = "taler-bank-integration-api"
+ case peerPullCredit = "peer-pull-credit"
+ case peerPushCredit = "peer-push-credit"
+ }
+ var type: WithdrawalType
+ /// The public key of the reserve.
+ var reservePub: String
- /// The public key of the newly created reserve.
- var reservePub: String?
+ /// Details for manual withdrawals:
+ /// The payto URIs that the exchange supports.
+ var exchangePaytoUris: [String]?
+ /// Details for bank-integrated withdrawals:
+ /// Whether the bank has confirmed the withdrawal.
+ var confirmed: Bool?
/// URL for user-initiated confirmation
var bankConfirmationUrl: String?
}
-/// A withdrawal transaction.
-struct TransactionWithdrawal: Decodable {
- enum WithdrawalDetails {
- case manual(ManualWithdrawalDetails)
- case bankIntegrated(BankIntegratedWithdrawalDetails)
- }
-
- /// The exchange that was withdrawn from.
+struct WithdrawalTransactionDetails: Decodable {
var exchangeBaseUrl: String
-
- /// The amount of the withdrawal, including fees.
- var amountRaw: Amount
-
- /// The amount that will be added to the withdrawer's account.
- var amountEffective: Amount
-
- /// The details of the withdrawal.
var withdrawalDetails: WithdrawalDetails
-
- init(from decoder: Decoder) throws {
- enum CodingKeys: String, CodingKey {
- case exchangeBaseUrl
- case amountRaw
- case amountEffective
- case withdrawalDetails
- case type
- case exchangePaytoUris
- case reservePub
- case confirmed
- case bankConfirmationUrl
- }
-
- let value = try decoder.container(keyedBy: CodingKeys.self)
- self.exchangeBaseUrl = try value.decode(String.self, forKey:
.exchangeBaseUrl)
- self.amountRaw = try value.decode(Amount.self, forKey: .amountRaw)
- self.amountEffective = try value.decode(Amount.self, forKey:
.amountEffective)
-
- let detail = try value.nestedContainer(keyedBy: CodingKeys.self,
forKey: .withdrawalDetails)
- let detailType = try detail.decode(String.self, forKey: .type)
- if detailType == "manual-transfer" {
- let paytoUris = try detail.decode([String].self, forKey:
.exchangePaytoUris)
- let reservePub = try detail.decode(String.self, forKey:
.reservePub)
- let manual = ManualWithdrawalDetails(exchangePaytoUris: paytoUris,
reservePub: reservePub)
- self.withdrawalDetails = .manual(manual)
- } else if detailType == "taler-bank-integration-api" {
- let confirmed = try detail.decode(Bool.self, forKey: .confirmed)
- var bankConfirmationUrl: String? = nil
- if detail.contains(.bankConfirmationUrl) {
- bankConfirmationUrl = try detail.decode(String.self, forKey:
.bankConfirmationUrl)
- }
- var reservePub : String? = nil
- if detail.contains(.reservePub) {
- reservePub = try detail.decode(String.self, forKey:
.reservePub)
- }
- let bankDetails = BankIntegratedWithdrawalDetails(confirmed:
confirmed, reservePub: reservePub,
-
bankConfirmationUrl: bankConfirmationUrl)
- self.withdrawalDetails = .bankIntegrated(bankDetails)
- } else {
- throw TransactionDecodingError.invalidStringValue
- }
- }
}
-#if DEBUG
-extension TransactionWithdrawal { // for PreViews
- init(url: String) {
- self.exchangeBaseUrl = url
- self.amountRaw = try! Amount(fromString: "Taler:5")
- self.amountEffective = try! Amount(fromString: "Taler:4.8")
- let bankDetails = BankIntegratedWithdrawalDetails(confirmed: true,
reservePub: nil,
- bankConfirmationUrl:
nil)
- self.withdrawalDetails = .bankIntegrated(bankDetails)
- }
+
+struct WithdrawalTransaction {
+ var common: TransactionCommon
+ var details: WithdrawalTransactionDetails
}
-#endif
-/// A payment transaction.
-struct TransactionPayment: Codable {
- /// Additional information about the payment.
- // TODO
-
- /// An identifier for the payment.
+struct PaymentTransactionDetails: Decodable {
var proposalId: String
-
- /// The current status of the payment.
- // TODO
-
- /// The amount that must be paid.
- var amountRaw: Amount
-
- /// The amount that was paid.
- var amountEffective: Amount
+ var status: String // "paid"
+ var totalRefundRaw: Amount
+ var totalRefundEffective: Amount
+ var refundPending: Amount?
+// var refunds: []
+ var info: OrderShortInfo
}
-/// A refund transaction.
-struct TransactionRefund: Codable {
- /// Identifier for the refund.
+struct PaymentTransaction {
+ var common: TransactionCommon
+ var details: PaymentTransactionDetails
+}
+
+struct RefundTransactionDetails: Decodable {
var refundedTransactionId: String
-
- /// Additional information about the refund
- // TODO
-
+ var refundPending: Amount?
/// The amount that couldn't be applied because refund permissions expired.
- var amountInvalid: Amount
-
- /// The amount refunded by the merchant.
- var amountRaw: Amount
-
- /// The amount paid to the wallet after fees.
- var amountEffective: Amount
+ var amountInvalid: Amount?
+ var info: OrderShortInfo
+}
+
+struct RefundTransaction {
+ var common: TransactionCommon
+ var details: RefundTransactionDetails
}
-/// A tip transaction.
-struct TransactionTip: Codable {
- /// The current status of the tip.
- // TODO
-
+struct TipTransactionDetails: Decodable {
/// The exchange that the tip will be withdrawn from
var exchangeBaseUrl: String
-
- /// More information about the merchant sending the tip.
- // TODO
-
- /// The raw amount of the tip without fees.
- var amountRaw: Amount
-
- /// The amount added to the recipient's wallet.
- var amountEffective: Amount
}
-/// A refresh transaction.
-struct TransactionRefresh: Codable {
+struct TipTransaction {
+ var common: TransactionCommon
+ var details: TipTransactionDetails
+}
+
+struct RefreshTransactionDetails: Decodable {
/// The exchange that the coins are refreshed with.
var exchangeBaseUrl: String
-
- /// The raw amount to refresh.
- var amountRaw: Amount
-
- /// The amount to be paid as fees for the refresh.
- var amountEffective: Amount
}
-/// A wallet transaction.
-struct Transaction: Decodable, Hashable {
-// private let symLog = SymLogC(0)
-
- var type: String
- var amountRaw: Amount
- var amountEffective: Amount
- var transactionId: String
- var timestamp: Timestamp
- var extendedStatus: String
- var pending: Bool
- var frozen: Bool
+struct RefreshTransaction {
+ var common: TransactionCommon
+ var details: RefreshTransactionDetails
+}
- var error: AnyCodable?
- var exchangeBaseUrl: String?
+enum Transaction: Decodable, Hashable, Identifiable {
+ case withdrawal (WithdrawalTransaction)
+ case payment (PaymentTransaction)
+ case refund (RefundTransaction)
+ case tip (TipTransaction)
+ case refresh (RefreshTransaction)
+ init(from decoder: Decoder) throws {
+ let common = try TransactionCommon.init(from: decoder)
+
+ switch (common.type) {
+ case WITHDRAWAL:
+ let details = try WithdrawalTransactionDetails.init(from:
decoder)
+ self = .withdrawal(WithdrawalTransaction(common: common,
details: details))
+ case PAYMENT:
+ let details = try PaymentTransactionDetails.init(from: decoder)
+ self = .payment(PaymentTransaction(common: common, details:
details))
+ case REFUND:
+ let details = try RefundTransactionDetails.init(from: decoder)
+ self = .refund(RefundTransaction(common: common, details:
details))
+ case TIP:
+ let details = try TipTransactionDetails.init(from: decoder)
+ self = .tip(TipTransaction(common: common, details: details))
+ case REFRESH:
+ let details = try RefreshTransactionDetails.init(from: decoder)
+ self = .refresh(RefreshTransaction(common: common, details:
details))
+ default:
+ let context = DecodingError.Context(
+ codingPath: decoder.codingPath,
+ debugDescription: "Invalid transaction type")
+ throw DecodingError.typeMismatch(Transaction.self, context)
+ }
+ }
+ var id: String { common().transactionId }
-// enum TransactionDetail {
-// case withdrawal(TransactionWithdrawal)
-// }
-
-// var detail: TransactionDetail
-
-// init(from decoder: Decoder) throws {
-// enum CodingKeys: String, CodingKey {
-// case transactionId
-// case timestamp
-// case pending
-// case error
-// case amountRaw
-// case amountEffective
-// case type
-// }
-//
-// let value = try decoder.container(keyedBy: CodingKeys.self)
-// self.transactionId = try value.decode(String.self, forKey:
.transactionId)
-// self.timestamp = try value.decode(Timestamp.self, forKey: .timestamp)
-// self.pending = try value.decode(Bool.self, forKey: .pending)
-// if value.contains(.error) {
-// self.error = try value.decode(AnyCodable.self, forKey: .error)
-// }
-// self.amountRaw = try value.decode(Amount.self, forKey: .amountRaw)
-// self.amountEffective = try value.decode(Amount.self, forKey:
.amountEffective)
-//
-// let type = try value.decode(String.self, forKey: .type)
-// if type == "withdrawal" {
-// let withdrawDetail = try TransactionWithdrawal.init(from:
decoder)
-// self.detail = .withdrawal(withdrawDetail)
-// } else {
-// throw TransactionDecodingError.invalidStringValue
-// }
-// symLog.log("\(self)")
-// }
-
static func == (lhs: Transaction, rhs: Transaction) -> Bool {
- return lhs.transactionId == rhs.transactionId
+ return lhs.id == rhs.id
}
-
+
func hash(into hasher: inout Hasher) {
- transactionId.hash(into: &hasher)
+ id.hash(into: &hasher)
+ }
+
+ func common() -> TransactionCommon {
+ switch self {
+ case .withdrawal(let withdrawalTransaction):
+ return withdrawalTransaction.common
+ case .payment(let paymentTransaction):
+ return paymentTransaction.common
+ case .refund(let refundTransaction):
+ return refundTransaction.common
+ case .tip(let tipTransaction):
+ return tipTransaction.common
+ case .refresh(let refreshTransaction):
+ return refreshTransaction.common
+ }
+ }
+
+ func detailsToShow() -> Dictionary<String, String> {
+ var result: [String:String] = [:]
+ switch self {
+ case .withdrawal(let withdrawalTransaction):
+ result[EXCHANGEBASEURL] =
withdrawalTransaction.details.exchangeBaseUrl
+ case .payment(let paymentTransaction):
+ result["status"] = paymentTransaction.details.status
+ case .refund(let refundTransaction):
+ result["summary"] = refundTransaction.details.info.summary
+ case .tip(let tipTransaction):
+ result[EXCHANGEBASEURL] =
tipTransaction.details.exchangeBaseUrl
+ case .refresh(let refreshTransaction):
+ result[EXCHANGEBASEURL] =
refreshTransaction.details.exchangeBaseUrl
+ }
+ return result
}
}
+
#if DEBUG
extension Transaction { // for PreViews
- init(id: String, time: Timestamp) {
- self.type = "withdrawal"
- self.amountRaw = try! Amount(fromString: "Taler:5")
- self.amountEffective = try! Amount(fromString: "Taler:4.8")
- self.transactionId = id
- self.timestamp = time
- self.extendedStatus = "done"
- self.pending = false
- self.frozen = false
- self.error = nil
- self.exchangeBaseUrl = "Exchange.Demo.Taler.net"
-// let withdrawDetail = TransactionWithdrawal(url:
"Exchange.Demo.Taler.net")
-// self.detail = .withdrawal(withdrawDetail)
+ init(incoming: Bool, id: String, time: Timestamp) {
+ let effective = incoming ? "Taler:4.8" : "Taler:5.2"
+ let common = TransactionCommon(type: incoming ? WITHDRAWAL : PAYMENT,
+ amountEffective: try! Amount(fromString:
effective),
+ amountRaw: try! Amount(fromString:
"Taler:5"),
+ transactionId: id, timestamp: time,
+ extendedStatus: "done", pending: false, frozen:
false)
+ if incoming {
+ let withdrawalDetails = WithdrawalDetails(type:
WithdrawalDetails.WithdrawalType.bankIntegrated,
+ reservePub: "Public Key
of the Exchange",
+ confirmed: true)
+ let wDetails = WithdrawalTransactionDetails(exchangeBaseUrl:
"Exchange.Demo.Taler.net",
+ withdrawalDetails:
withdrawalDetails)
+ self = .withdrawal(WithdrawalTransaction(common: common, details:
wDetails))
+ } else {
+ let merchant = Merchant(name: "some random shop")
+ let info = OrderShortInfo(orderId: "some order ID",
+ merchant: merchant, summary: "some
product summary", products: [])
+ let pDetails = PaymentTransactionDetails(proposalId: "some
proposal ID",
+ status: "paid",
+ totalRefundRaw: try!
Amount(fromString: "Taler:3.2"),
+ totalRefundEffective:
try! Amount(fromString: "Taler:3"),
+ info: info)
+ self = .payment(PaymentTransaction(common: common, details:
pDetails))
+ }
}
}
#endif
diff --git a/TalerWallet1/Backend/WalletCore.swift
b/TalerWallet1/Backend/WalletCore.swift
index ff67b15..be7450d 100644
--- a/TalerWallet1/Backend/WalletCore.swift
+++ b/TalerWallet1/Backend/WalletCore.swift
@@ -116,6 +116,7 @@ extension WalletCore {
symLog.log(payload)
Task {
do {
+ // automatically fetch balances after receiving
these notifications
try await
Controller.shared.balancesModel.fetchBalances()
} catch {
// TODO: show error
@@ -210,23 +211,6 @@ extension WalletCore {
completionHandler(id, nil, WalletCore.serializeRequestError());
}
}
-
- /// call this to send requests to wallet-core
- func sendFormattedRequest<T: WalletBackendFormattedRequest>
- (request: T, completionHandler: @escaping (T.Response?,
WalletBackendResponseError?) -> Void)
- {
- let reqData = WalletBackendRequest(operation: request.operation(),
- args:
AnyEncodable(request.args()))
- sendRequest(request: reqData) { (id: UInt, result: Data?, err:
WalletBackendResponseError?) in
- guard let json = result else { completionHandler(nil, err); return
}
- do {
- let decoded = try JSONDecoder().decode(T.Response.self, from:
json)
- completionHandler(decoded, err)
- } catch {
- completionHandler(nil, WalletCore.parseResponseError())
- }
- }
- }
}
// MARK: - async / await function
extension WalletCore {
diff --git a/TalerWallet1/Controllers/Controller.swift
b/TalerWallet1/Controllers/Controller.swift
index 513472a..8e10ec6 100644
--- a/TalerWallet1/Controllers/Controller.swift
+++ b/TalerWallet1/Controllers/Controller.swift
@@ -89,7 +89,7 @@ extension Controller {
case "taler+http":
uncrypted = true
fallthrough
- case "taler":
+ case "taler", "ext+taler", "web+taler":
return talerScheme(url, uncrypted)
case "payto":
messageForSheet = url.absoluteString
diff --git a/TalerWallet1/Controllers/TalerWallet1App.swift
b/TalerWallet1/Controllers/TalerWallet1App.swift
index 11f8645..1eac830 100644
--- a/TalerWallet1/Controllers/TalerWallet1App.swift
+++ b/TalerWallet1/Controllers/TalerWallet1App.swift
@@ -16,11 +16,6 @@
import BackgroundTasks
import SwiftUI
import SymLog
-#if DEBUG
-let schemes: Set = ["taler", "payto", "taler+http"]
-#else
-let schemes: Set = ["taler", "payto"]
-#endif
@main
struct TalerWallet1App: App {
@@ -40,10 +35,12 @@ struct TalerWallet1App: App {
WindowGroup {
symLog { ContentView()
.environmentObject(controller)
+ /// external events are taler:// or payto:// URLs
passed to this app
+ /// we handle them in .onOpenURL in ContentView.swift
.handlesExternalEvents(preferring: ["*"], allowing: ["*"])
.task {
symLog.log("task -> initWalletCore")
- try? await controller.initWalletCore()
+ try! await controller.initWalletCore() // will
(and should) crash on failure
symLog.log("task done")
}
}
diff --git a/TalerWallet1/Helper/TalerStrings.swift
b/TalerWallet1/Helper/PublicConstants.swift
similarity index 75%
copy from TalerWallet1/Helper/TalerStrings.swift
copy to TalerWallet1/Helper/PublicConstants.swift
index b642798..01680a0 100644
--- a/TalerWallet1/Helper/TalerStrings.swift
+++ b/TalerWallet1/Helper/PublicConstants.swift
@@ -15,14 +15,10 @@
*/
import Foundation
-extension StringProtocol {
+public let EXCHANGEBASEURL = "exchangeBaseUrl"
- func trimURL() -> String {
- if let url = URL(string: String(self)) {
- if let host = url.host {
- return host
- }
- }
- return String(self)
- }
-}
+public let WITHDRAWAL = "withdrawal"
+public let PAYMENT = "payment"
+public let REFUND = "refund"
+public let TIP = "tip"
+public let REFRESH = "refresh"
diff --git a/TalerWallet1/Model/ExchangeTestModel.swift
b/TalerWallet1/Model/ExchangeTestModel.swift
index f73592a..98702d5 100644
--- a/TalerWallet1/Model/ExchangeTestModel.swift
+++ b/TalerWallet1/Model/ExchangeTestModel.swift
@@ -16,70 +16,47 @@
import Foundation
import taler_swift
import SymLog
+fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for
debugging
-fileprivate let EXCHANGEBASEURL = "https://exchange.demo.taler.net/"
-fileprivate let BANKBASEURL = "https://bank.demo.taler.net/"
-fileprivate let BANKACCESSAPIBASEURL =
"https://bank.demo.taler.net/demobanks/default/access-api/"
-fileprivate let MERCHANTBASEURL = "https://backend.demo.taler.net/"
-fileprivate let MERCHANTAUTHTOKEN = "secret-token:sandbox"
+fileprivate let DEMO_EXCHANGEBASEURL = "https://exchange.demo.taler.net/"
+fileprivate let DEMO_BANKBASEURL = "https://bank.demo.taler.net/"
+fileprivate let DEMO_BANKAPIBASEURL =
"https://bank.demo.taler.net/demobanks/default/access-api/"
+fileprivate let DEMO_MERCHANTBASEURL = "https://backend.demo.taler.net/"
+fileprivate let DEMO_MERCHANTAUTHTOKEN = "secret-token:sandbox"
// MARK: -
-class ExchangeTestModel: ObservableObject {
- private let symLog = SymLogC(0)
-
- var walletCore: WalletCore
-
- @Published var loading: Bool = false
-
- init(walletCore: WalletCore) {
- self.walletCore = walletCore
- }
+class ExchangeTestModel: WalletModel {
}
// MARK: -
extension ExchangeTestModel {
- func loadTestKudos() {
- loading = true
-
- let amount = Amount(currency: "KUDOS", integer: 11, fraction: 0)
- let req = WalletBackendWithdrawTestBalance(amount: amount,
bankBaseUrl: BANKBASEURL,
- exchangeBaseUrl: EXCHANGEBASEURL,
bankAccessApiBaseUrl: BANKACCESSAPIBASEURL)
- symLog.log("sending: \(req)")
- walletCore.sendFormattedRequest(request: req) { response, err in
- DispatchQueue.main.async {
- self.loading = false
- if let res = response {
- // TODO: ?
- self.symLog.log("received: \(res)")
- } else {
- // TODO: Handle error
- }
- }
+ @MainActor func loadTestKudos() async throws {
+ do {
+ let amount = Amount(currency: "KUDOS", integer: 11, fraction: 0)
+ let request = WalletBackendWithdrawTestBalance(amount: amount,
+ bankBaseUrl:
DEMO_BANKBASEURL,
+ exchangeBaseUrl:
DEMO_EXCHANGEBASEURL,
+ bankAccessApiBaseUrl:
DEMO_BANKAPIBASEURL)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ symLog?.log("received: \(response)")
+ } catch {
+ throw error
}
}
- func runIntegrationTest() {
- loading = true
-
- let amountW = Amount(currency: "KUDOS", integer: 3, fraction: 0)
- let amountS = Amount(currency: "KUDOS", integer: 1, fraction: 0)
- let req = WalletBackendRunIntegration(amountToWithdraw: amountW,
- amountToSpend: amountS,
- bankBaseUrl:
BANKACCESSAPIBASEURL,
- exchangeBaseUrl: EXCHANGEBASEURL,
- merchantBaseUrl: MERCHANTBASEURL,
- merchantAuthToken:
MERCHANTAUTHTOKEN
- )
- symLog.log("sending: \(req)")
- walletCore.sendFormattedRequest(request: req) { response, err in
- DispatchQueue.main.async {
- self.loading = false
- if let res = response {
- // TODO: ?
- self.symLog.log("received: \(res)")
- } else {
- // TODO: Handle error
- }
- }
+ @MainActor func runIntegrationTest() async throws {
+ do {
+ let amountW = Amount(currency: "KUDOS", integer: 3, fraction: 0)
+ let amountS = Amount(currency: "KUDOS", integer: 1, fraction: 0)
+ let request = WalletBackendRunIntegration(amountToWithdraw:
amountW,
+ amountToSpend:
amountS,
+ bankBaseUrl:
DEMO_BANKAPIBASEURL,
+ exchangeBaseUrl:
DEMO_EXCHANGEBASEURL,
+ merchantBaseUrl:
DEMO_MERCHANTBASEURL,
+ merchantAuthToken:
DEMO_MERCHANTAUTHTOKEN)
+ let response = try await sendRequest(request, ASYNCDELAY)
+ symLog?.log("received: \(response)")
+ } catch {
+ throw error
}
}
}
diff --git a/TalerWallet1/Model/WalletInitModel.swift
b/TalerWallet1/Model/WalletInitModel.swift
index e254d41..7be0dff 100644
--- a/TalerWallet1/Model/WalletInitModel.swift
+++ b/TalerWallet1/Model/WalletInitModel.swift
@@ -27,12 +27,14 @@ fileprivate struct WalletBackendInitRequest:
WalletBackendFormattedRequest {
func operation() -> String { return "init" }
func args() -> Args {
return Args(persistentStoragePath: persistentStoragePath,
- cryptoWorkerType: "sync")
+// cryptoWorkerType: "sync",
+ logLevel: "info") // "trace", "info", "warn",
"error", "none"
}
struct Args: Encodable {
var persistentStoragePath: String
- var cryptoWorkerType: String?
+// var cryptoWorkerType: String
+ var logLevel: String
}
var persistentStoragePath: String
diff --git a/TalerWallet1/Views/Balances/CurrenciesListView.swift
b/TalerWallet1/Views/Balances/CurrenciesListView.swift
index a40b074..192d531 100644
--- a/TalerWallet1/Views/Balances/CurrenciesListView.swift
+++ b/TalerWallet1/Views/Balances/CurrenciesListView.swift
@@ -69,8 +69,13 @@ extension CurrenciesListView {
}
.navigationBarTitleDisplayMode(.large) // .inline
.refreshable {
- symLog?.log("refreshing")
- try? await reloadAction() // TODO: catch error
+ do {
+ symLog?.log("refreshing")
+ try await reloadAction()
+ } catch {
+ // TODO: error
+ symLog?.log(error.localizedDescription)
+ }
}
}
}
diff --git a/TalerWallet1/Views/Exchange/ExchangeListView.swift
b/TalerWallet1/Views/Exchange/ExchangeListView.swift
index b4b8b9f..fbd52e4 100644
--- a/TalerWallet1/Views/Exchange/ExchangeListView.swift
+++ b/TalerWallet1/Views/Exchange/ExchangeListView.swift
@@ -85,11 +85,11 @@ extension ExchangeListView {
}
.navigationBarTitleDisplayMode(.large) // .inline
.refreshable {
- symLog.log("refreshing")
do {
+ symLog.log("refreshing")
try await reloadAction()
} catch {
- // TODO: catch error
+ // TODO: error
symLog.log(error.localizedDescription)
}
}
diff --git a/TalerWallet1/Views/Payment/PaymentAcceptView.swift
b/TalerWallet1/Views/Payment/PaymentAcceptView.swift
index 7920b87..26eb916 100644
--- a/TalerWallet1/Views/Payment/PaymentAcceptView.swift
+++ b/TalerWallet1/Views/Payment/PaymentAcceptView.swift
@@ -35,7 +35,7 @@ struct PaymentAcceptView: View {
symLog { Group {
let raw = detailsForAmount.amountRaw
let effective = detailsForAmount.amountEffective
- let fee = try! effective - raw
+ let fee = try! Amount.diff(raw, effective) // TODO: different
currencies
Form {
AmountView(title: "Amount to pay:",
value: raw.readableDescription, color:
Color(UIColor.label))
diff --git a/TalerWallet1/Views/Pending/PendingModel.swift
b/TalerWallet1/Views/Pending/PendingModel.swift
index cb88523..6b0e38e 100644
--- a/TalerWallet1/Views/Pending/PendingModel.swift
+++ b/TalerWallet1/Views/Pending/PendingModel.swift
@@ -56,7 +56,7 @@ struct PendingOperation: Codable, Hashable {
}
//let pending1 = ["type": "exchange-update",
-// "exchangeBaseUrl": "https://exchange.demo.taler.net/",
+// EXCHANGEBASEURL: "https://exchange.demo.taler.net/",
// "id": "exchange-update:https://exchange.demo.taler.net/",
// "timestampDue": ["t_ms": 1669931055000],
// "isDue": false,
@@ -64,7 +64,7 @@ struct PendingOperation: Codable, Hashable {
// "givesLifeness": false] as [String : Any]
//
//let pending2 = ["type": "exchange-check-refresh",
-// "exchangeBaseUrl": "https://exchange.demo.taler.net/",
+// EXCHANGEBASEURL: "https://exchange.demo.taler.net/",
// "id": "exchange-update:https://exchange.demo.taler.net/",
// "timestampDue": ["t_ms": 1670013862000],
// "isDue": false,
diff --git a/TalerWallet1/Views/Pending/PendingOpsListView.swift
b/TalerWallet1/Views/Pending/PendingOpsListView.swift
index 30a5de3..a4d9e61 100644
--- a/TalerWallet1/Views/Pending/PendingOpsListView.swift
+++ b/TalerWallet1/Views/Pending/PendingOpsListView.swift
@@ -37,7 +37,12 @@ struct PendingOpsListView: View {
}
}.task {
symLog.log(".task")
- try? await reloadAction() // TODO: catch error
+ do {
+ try await reloadAction()
+ } catch {
+ // TODO: show error
+ symLog.log(error.localizedDescription)
+ }
}
}
}
@@ -56,8 +61,13 @@ extension PendingOpsListView {
}
.navigationBarTitleDisplayMode(.large) // .inline
.refreshable {
- symLog?.log("refreshing")
- try? await reloadAction() // TODO: catch error
+ do {
+ symLog?.log("refreshing")
+ try await reloadAction()
+ } catch {
+ // TODO: error
+ symLog?.log(error.localizedDescription)
+ }
}
}
}
diff --git a/TalerWallet1/Views/Settings/SettingsView.swift
b/TalerWallet1/Views/Settings/SettingsView.swift
index a2f3ea5..b84b242 100644
--- a/TalerWallet1/Views/Settings/SettingsView.swift
+++ b/TalerWallet1/Views/Settings/SettingsView.swift
@@ -66,9 +66,16 @@ struct SettingsView: View {
SettingsItem(name: "Withdraw KUDOS", description: "Get
money for testing") {
Button("Withdraw") {
withDrawDisabled = true // don't run twice
- let testModel: ExchangeTestModel =
ExchangeTestModel(walletCore: walletCore)
- symLog.log("Withdrawing ")
- testModel.loadTestKudos()
+ Task {
+ let testModel: ExchangeTestModel =
ExchangeTestModel(walletCore: walletCore)
+ symLog.log("Withdrawing")
+ do {
+ try await testModel.loadTestKudos()
+ } catch {
+ // TODO: show error
+ symLog.log(error.localizedDescription)
+ }
+ }
}
.buttonStyle(.bordered)
.disabled(withDrawDisabled)
@@ -76,9 +83,16 @@ struct SettingsView: View {
SettingsItem(name: "Run Integration Test", description:
"Check if wallet-core works") {
Button("Check") {
checkDisabled = true // don't run twice
- let testModel: ExchangeTestModel =
ExchangeTestModel(walletCore: walletCore)
- symLog.log("running integration test ")
- testModel.runIntegrationTest()
+ Task {
+ let testModel: ExchangeTestModel =
ExchangeTestModel(walletCore: walletCore)
+ symLog.log("running integration test")
+ do {
+ try await testModel.runIntegrationTest()
+ } catch {
+ // TODO: show error
+ symLog.log(error.localizedDescription)
+ }
+ }
}
.buttonStyle(.bordered)
.disabled(checkDisabled)
diff --git a/TalerWallet1/Views/Transactions/TransactionDetail.swift
b/TalerWallet1/Views/Transactions/TransactionDetail.swift
index 84b442a..57faf07 100644
--- a/TalerWallet1/Views/Transactions/TransactionDetail.swift
+++ b/TalerWallet1/Views/Transactions/TransactionDetail.swift
@@ -20,40 +20,47 @@ struct TransactionDetail: View {
var transaction : Transaction
var body: some View {
- let raw = transaction.amountRaw
- let effective = transaction.amountEffective
- let fee = try! Amount.diff(raw, effective)
- let dateString = TalerDater.dateString(from: transaction.timestamp)
+ let common = transaction.common()
+ let details = transaction.detailsToShow()
+ let dateString = TalerDater.dateString(from: common.timestamp)
VStack() {
Spacer()
- Text("\(dateString)")
+ Text("\(common.type)") // TODO: translation
.font(.title)
.fontWeight(.medium)
.padding(.bottom)
- AmountView(title: "Chosen amount to withdraw:",
- value: raw.readableDescription, color:
Color(UIColor.label))
- .padding(.bottom)
- AmountView(title: "Exchange fee:",
- value: fee.readableDescription, color:
Color("Outgoing"))
- .padding(.bottom)
- AmountView(title: "Obtained coins:",
- value: effective.readableDescription, color:
Color("Incoming"))
- .padding(.bottom)
- if let baseURL = transaction.exchangeBaseUrl {
- VStack {
- Text("From exchange:")
- .font(.title3)
- Text("\(baseURL.trimURL())")
- .font(.title)
- .fontWeight(.medium)
- }
- .frame(maxWidth: .infinity, alignment: .center)
+ Text("\(dateString)")
+ .font(.title)
+ .fontWeight(.medium)
+ .padding(.vertical)
+ switch transaction {
+ case .withdrawal(let withdrawalTransaction):
+ threeAmounts(common: common, topTitle: "Chosen amount to
withdraw:", bottomTitle: "Obtained coins:", incoming: true)
+ case .payment(let paymentTransaction):
+ threeAmounts(common: common, topTitle: "Sum to be paid:",
bottomTitle: "Paid coins:", incoming: false)
+ case .refund(let refundTransaction):
+ threeAmounts(common: common, topTitle: "Refunded amount:",
bottomTitle: "Obtained coins:", incoming: true)
+ case .tip(let tipTransaction):
+ threeAmounts(common: common, topTitle: "Tip to be paid:",
bottomTitle: "Paid coins:", incoming: false)
+ case .refresh(let refreshTransaction):
+ threeAmounts(common: common, topTitle: "Refreshed
amount:", bottomTitle: "Paid coins:", incoming: false)
}
+
+// if let baseURL = transaction.exchangeBaseUrl {
+// VStack {
+// Text("From exchange:")
+// .font(.title3)
+// Text("\(baseURL.trimURL())")
+// .font(.title)
+// .fontWeight(.medium)
+// }
+// .frame(maxWidth: .infinity, alignment: .center)
+// }
Spacer()
Button(role: .destructive, action: {
// TODO: delete from wallet-core
- print("Should delete \(transaction.transactionId)")
+ print("Should delete \(common.transactionId)")
}, label: {
HStack {
Text("Delete from list" + " ")
@@ -69,11 +76,47 @@ struct TransactionDetail: View {
}
}
+extension TransactionDetail {
+ struct threeAmounts: View {
+ var common: TransactionCommon
+ var topTitle: String
+ var bottomTitle: String
+ var incoming: Bool
+
+ var body: some View {
+ let raw = common.amountRaw
+ let effective = common.amountEffective
+ let fee = common.fee()
+ let labelColor = Color(UIColor.label)
+ let outColor = Color("Outgoing")
+ let inColor = Color("Incoming")
+
+ AmountView(title: topTitle,
+ value: raw.readableDescription, color: labelColor)
+ .padding(.bottom)
+ AmountView(title: "Exchange fee:",
+ value: fee.readableDescription, color: fee.isZero ?
labelColor : outColor)
+ .padding(.bottom)
+ AmountView(title: bottomTitle,
+ value: effective.readableDescription, color: incoming ?
inColor : outColor)
+ .padding(.bottom)
+ }
+ }
+}
+
#if DEBUG
struct TransactionDetail_Previews: PreviewProvider {
- static var transaction = Transaction(id:"some transActionID", time:
Timestamp(from: 1_666_000_000_000))
+ static var withdrawal = Transaction(incoming: true,
+ id: "some withdrawal ID",
+ time: Timestamp(from:
1_666_000_000_000))
+ static var payment = Transaction(incoming: false,
+ id: "some payment ID",
+ time: Timestamp(from: 1_666_666_000_000))
static var previews: some View {
- TransactionDetail(transaction: transaction)
+ Group {
+ TransactionDetail(transaction: withdrawal)
+ TransactionDetail(transaction: payment)
+ }
}
}
#endif
diff --git a/TalerWallet1/Views/Transactions/TransactionRow.swift
b/TalerWallet1/Views/Transactions/TransactionRow.swift
index 63df274..899aaf4 100644
--- a/TalerWallet1/Views/Transactions/TransactionRow.swift
+++ b/TalerWallet1/Views/Transactions/TransactionRow.swift
@@ -36,13 +36,16 @@ struct TransactionRow: View {
var transaction : Transaction
var body: some View {
- let amount = transaction.amountEffective
- let withdraw: Bool = transaction.type == "withdrawal"
- let payment: Bool = transaction.type == "payment"
- let refund: Bool = transaction.type == "refund"
+ let common = transaction.common()
+ let details = transaction.detailsToShow()
+ let keys = details.keys
+ let amount = common.amountEffective
+ let withdraw: Bool = common.type == WITHDRAWAL
+ let payment: Bool = common.type == PAYMENT
+ let refund: Bool = common.type == REFUND
let incoming = withdraw || refund
- let counterparty = transaction.exchangeBaseUrl
- let dateString = TalerDater.dateString(from: transaction.timestamp,
relative: true)
+// let counterparty = transaction.exchangeBaseUrl
+ let dateString = TalerDater.dateString(from: common.timestamp,
relative: true)
HStack {
Image(systemName: incoming ? "text.badge.plus" :
"text.badge.minus")
@@ -50,8 +53,8 @@ struct TransactionRow: View {
.padding(.trailing)
.font(.largeTitle)
- if withdraw {
- if let baseURL = counterparty {
+ if keys.contains(EXCHANGEBASEURL) {
+ if let baseURL = details[EXCHANGEBASEURL] {
TransactionRowCenter(centerTop: baseURL.trimURL(),
centerBottom: dateString)
}
} else if payment {
@@ -73,9 +76,17 @@ struct TransactionRow: View {
#if DEBUG
struct TransactionRow_Previews: PreviewProvider {
- static var transaction = Transaction(id:"some transActionID", time:
Timestamp(from: 1_666_000_000_000))
+ static var withdrawal = Transaction(incoming: true,
+ id: "some withdrawal ID",
+ time: Timestamp(from:
1_666_000_000_000))
+ static var payment = Transaction(incoming: false,
+ id: "some payment ID",
+ time: Timestamp(from:
1_666_666_000_000))
static var previews: some View {
- TransactionRow(transaction: transaction)
+ VStack {
+ TransactionRow(transaction: withdrawal)
+ TransactionRow(transaction: payment)
+ }
}
}
#endif
diff --git a/TalerWallet1/Views/Transactions/TransactionsListView.swift
b/TalerWallet1/Views/Transactions/TransactionsListView.swift
index 8f9a6a3..ef365e1 100644
--- a/TalerWallet1/Views/Transactions/TransactionsListView.swift
+++ b/TalerWallet1/Views/Transactions/TransactionsListView.swift
@@ -53,15 +53,16 @@ extension TransactionsListView {
var body: some View {
let transactions = viewModel.transactions!
- List(transactions, id: \.transactionId) { transaction in
- NavigationLink {
- TransactionDetail(transaction: transaction)
- } label: {
- TransactionRow(transaction: transaction)
- }
+ List(transactions) { transaction in
+ let common = transaction.common()
+ NavigationLink {
+ TransactionDetail(transaction: transaction)
+ } label: {
+ TransactionRow(transaction: transaction)
+ }
.swipeActions(edge: .leading, allowsFullSwipe: true) {
Button {
- symLog?.log("bookmarked
\(transaction.transactionId)")
+ symLog?.log("bookmarked \(common.transactionId)")
// TODO: Bookmark
} label: {
Label("Bookmark", systemImage: "bookmark")
@@ -69,18 +70,23 @@ extension TransactionsListView {
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button(role: .destructive) {
- symLog?.log("deleted \(transaction.transactionId)")
+ symLog?.log("deleted \(common.transactionId)")
// TODO: delete from Model. SwiftUI deletes this
row from view already :-)
} label: {
Label("Delete", systemImage: "trash")
}
}
- }
- .navigationBarTitleDisplayMode(.large) // .inline
- .refreshable {
+ }
+ .navigationBarTitleDisplayMode(.large) // .inline
+ .refreshable {
+ do {
symLog?.log("refreshing")
- try? await reloadAction() // TODO: catch error
+ try await reloadAction()
+ } catch {
+ // TODO: error
+ symLog?.log(error.localizedDescription)
}
+ }
}
}
}
diff --git a/TalerWallet1/Views/Transactions/TransactionsModel.swift
b/TalerWallet1/Views/Transactions/TransactionsModel.swift
index 9786c1e..253a557 100644
--- a/TalerWallet1/Views/Transactions/TransactionsModel.swift
+++ b/TalerWallet1/Views/Transactions/TransactionsModel.swift
@@ -22,14 +22,6 @@ fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9
seconds for debugging
class TransactionsModel: WalletModel {
@Published var transactions: [Transaction]? // update view
}
-//extension Transaction {
-// func exchangeBaseUrl() -> String {
-// switch detail {
-// case .withdrawal(let transactionWithdrawal):
-// return transactionWithdrawal.exchangeBaseUrl
-// }
-// }
-//}
// MARK: -
/// A request to get the transactions in the wallet's history.
diff --git a/TalerWallet1/Views/Withdraw/WithdrawAcceptView.swift
b/TalerWallet1/Views/Withdraw/WithdrawAcceptView.swift
index becc6dd..4f9578c 100644
--- a/TalerWallet1/Views/Withdraw/WithdrawAcceptView.swift
+++ b/TalerWallet1/Views/Withdraw/WithdrawAcceptView.swift
@@ -37,7 +37,7 @@ struct WithdrawAcceptView: View {
case .receivedAmountDetails, .receivedTOS, .receivedTOSAck:
let raw = detailsForAmount.amountRaw
let effective = detailsForAmount.amountEffective
- let fee = try! raw - effective
+ let fee = try! Amount.diff(raw, effective) // TODO:
different currencies
Form {
AmountView(title: "Chosen amount to withdraw:",
value: raw.readableDescription, color:
Color(UIColor.label))
diff --git a/TalerWallet1/Views/Withdraw/WithdrawURIView.swift
b/TalerWallet1/Views/Withdraw/WithdrawURIView.swift
index 939c24d..e928e44 100644
--- a/TalerWallet1/Views/Withdraw/WithdrawURIView.swift
+++ b/TalerWallet1/Views/Withdraw/WithdrawURIView.swift
@@ -66,7 +66,7 @@ struct WithdrawURIView: View {
symLog.log(".task")
detailsForUri = try await
viewModel.loadWithdrawalDetailsForURI(url.absoluteString)
let baseURL = detailsForUri!.defaultExchangeBaseUrl
- symLog.log("amount: \(detailsForUri!.amount), baseURL:
\(baseURL)")
+ symLog.log("amount: \(detailsForUri!.amount), baseURL:
\(String(describing: baseURL))")
// TODO: let user choose exchange from array
detailsForAmount = try await
viewModel.loadWithdrawalDetailsForAmount(detailsForUri!)
symLog.log("raw: \(detailsForAmount!.amountRaw), effective:
\(detailsForAmount!.amountEffective)")
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-ios] branch master updated (df4fe35 -> 4f2b20c),
gnunet <=
- [taler-taler-ios] 01/07: Error handling, Amount.diff, gnunet, 2023/02/22
- [taler-taler-ios] 04/07: Constants, cleanup, gnunet, 2023/02/22
- [taler-taler-ios] 03/07: added ext+taler and web+taler to the list of recognized URL schemes, gnunet, 2023/02/22
- [taler-taler-ios] 06/07: Info & SceneConfigurations, v0.9.2, bundleID, gnunet, 2023/02/22
- [taler-taler-ios] 02/07: ported remaining sync wallet-core funcs to try await, gnunet, 2023/02/22
- [taler-taler-ios] 05/07: Transaction definition and JSON decoding - Bug 7678, gnunet, 2023/02/22
- [taler-taler-ios] 07/07: Transaction list and details, gnunet, 2023/02/22