commit a914a934b9268d65b8db53ee4d2d1723b47b5f3d
parent f26e277802ecf62ad042cb485c4cfc981c773368
Author: Marc Stibane <marc@taler.net>
Date: Fri, 17 Nov 2023 16:46:58 +0100
Notifications
Diffstat:
3 files changed, 92 insertions(+), 62 deletions(-)
diff --git a/TalerWallet1/Backend/WalletCore.swift b/TalerWallet1/Backend/WalletCore.swift
@@ -184,26 +184,46 @@ extension WalletCore {
@MainActor private func handleStateTransition(_ jsonData: Data) throws {
do {
let decoded = try JSONDecoder().decode(TransactionTransition.self, from: jsonData)
- if decoded.newTxState != decoded.oldTxState {
- let components = decoded.transactionId.components(separatedBy: ":")
- if components.count >= 3 { // txn:$txtype:$uid
- if let type = TransactionType(rawValue: components[1]) {
- guard type != .refresh else { return }
- if decoded.newTxState.major == .done {
+ guard decoded.newTxState != decoded.oldTxState else {
+ // TODO: Same state usually means that an error is transmitted
+ logger.info("No State change: \(decoded.transactionId, privacy: .private(mask: .hash))")
+ return
+ }
+ let components = decoded.transactionId.components(separatedBy: ":")
+ if components.count >= 3 { // txn:$txtype:$uid
+ if let type = TransactionType(rawValue: components[1]) {
+ guard type != .refresh else { return }
+ switch decoded.newTxState.major {
+ case .done:
logger.info("Done: \(decoded.transactionId, privacy: .private(mask: .hash))")
Controller.shared.playSound(type.isIncoming ? 2 : 1)
- } else if decoded.newTxState.major == .expired {
+ postNotification(.TransactionDone,
+ userInfo: [TRANSACTIONTRANSITION: decoded])
+ case .expired:
logger.log("Expired: \(decoded.transactionId, privacy: .private(mask: .hash))")
Controller.shared.playSound(0)
- }
- postNotification(.TransactionStateTransition,
- userInfo: [TRANSACTIONTRANSITION: decoded])
- }
- }
- } else {
- // TODO: Same state usually means that an error is transmitted
- logger.info("No State change: \(decoded.transactionId, privacy: .private(mask: .hash))")
- }
+ postNotification(.TransactionExpired,
+ userInfo: [TRANSACTIONTRANSITION: decoded])
+ case .pending:
+ if let newMinor = decoded.newTxState.minor {
+ if newMinor == .ready {
+ postNotification(.PendingReady,
+ userInfo: [TRANSACTIONTRANSITION: decoded])
+ } else if newMinor == .exchangeWaitReserve // user did confirm on bank website
+ || newMinor == .withdrawCoins { // coin-withdrawal has started
+ postNotification(.DismissSheet,
+ userInfo: [TRANSACTIONTRANSITION: decoded])
+ } else if newMinor == .kyc { // user did confirm on bank website, but KYC is needed
+ postNotification(.KYCrequired,
+ userInfo: [TRANSACTIONTRANSITION: decoded])
+ }
+ }
+ default: break
+ } // switch
+ postNotification(.TransactionStateTransition,
+ userInfo: [TRANSACTIONTRANSITION: decoded])
+ } // type
+ } // 3 components
} catch { // rethrows
symLog.log(jsonData) // TODO: .error
throw WalletBackendError.deserializationError
diff --git a/TalerWallet1/Controllers/PublicConstants.swift b/TalerWallet1/Controllers/PublicConstants.swift
@@ -46,12 +46,20 @@ public let EXCHANGEBASEURL = "exchangeBaseUrl"
public let TALERURI = "talerUri"
public let TRANSACTIONTRANSITION = "transactionTransition"
+public let TRANSACTIONID = "transactionID"
/// Notifications sent by wallet-core
extension Notification.Name {
static let BalanceChange = Notification.Name("balance-change")
- static let TransactionStateTransition = Notification.Name(TransactionTransition.TransitionType.transition.rawValue)
static let ExchangeAdded = Notification.Name("exchange-added")
+ static let TransactionStateTransition = Notification.Name(TransactionTransition.TransitionType.transition.rawValue)
+ static let TransactionDone = Notification.Name("transaction-done")
+ static let TransactionExpired = Notification.Name("transaction-expired")
+ static let PendingReady = Notification.Name("pending-ready")
+ static let WaitReserve = Notification.Name("wait-reserve")
+ static let WithdrawCoins = Notification.Name("withdraw-coins")
+ static let KYCrequired = Notification.Name("kyc-required")
+ static let DismissSheet = Notification.Name("dismiss-sheet")
static let PendingOperationProcessed = Notification.Name("pending-operation-processed")
static let ReserveNotYetFound = Notification.Name("reserve-not-yet-found")
// static let WithdrawalGroupBankConfirmed = Notification.Name("withdrawal-group-bank-confirmed")
diff --git a/TalerWallet1/Views/Transactions/TransactionDetailView.swift b/TalerWallet1/Views/Transactions/TransactionDetailView.swift
@@ -56,6 +56,31 @@ struct TransactionDetailView: View {
return nil
}
+ func loadTransaction(_ txId: String) async {
+ do {
+ let reloadedTransaction = try await reloadAction(txId)
+ symLog.log("reloaded transaction: \(reloadedTransaction.common.txState.major)")
+ withAnimation() { transaction = reloadedTransaction; viewId = UUID() } // redraw
+ } catch {
+ symLog.log(error.localizedDescription)
+ withAnimation() { transaction = Transaction(dummyCurrency: DEMOCURRENCY); viewId = UUID() }
+ }
+ }
+
+ @discardableResult
+ func checkDismiss(_ notification: Notification, _ logStr: String = "") -> Bool {
+ if let doneAction {
+ if let transition = notification.userInfo?[TRANSACTIONTRANSITION] as? TransactionTransition {
+ if transition.transactionId == transaction.common.transactionId { // is the transition for THIS transaction?
+ symLog.log(logStr)
+ doneAction() // if this view is in a sheet then dissmiss the sheet
+ return true
+ }
+ }
+ }
+ return false
+ }
+
var body: some View {
#if DEBUG
let _ = Self._printChanges()
@@ -116,45 +141,28 @@ struct TransactionDetailView: View {
.padding(.horizontal)
}
}
- }.onNotification(.TransactionStateTransition) { notification in
+ }
+ .onNotification(.TransactionExpired) { notification in
+ if checkDismiss(notification, "newTxState.major == expired => dismiss sheet") {
+ // TODO: logger.info("newTxState.major == expired => dismiss sheet")
+ }
+ }
+ .onNotification(.TransactionDone) { notification in
+ checkDismiss(notification, "newTxState.major == done => dismiss sheet")
+ }
+ .onNotification(.DismissSheet) { notification in
+ checkDismiss(notification, "exchangeWaitReserve or withdrawCoins => dismiss sheet")
+ }
+ .onNotification(.TransactionStateTransition) { notification in
if let transition = notification.userInfo?[TRANSACTIONTRANSITION] as? TransactionTransition {
if transition.transactionId == common.transactionId { // is the transition for THIS transaction?
let newMajor = transition.newTxState.major
- let newMinor = transition.newTxState.minor
- if let doneAction {
- if newMajor == .done {
- symLog.log("newTxState.major == done => dismiss sheet")
-// TODO: logger.info("newTxState.major == done => dismiss sheet")
- doneAction() // if this view is in a sheet this action will dissmiss it
- } else if newMajor == .expired {
- symLog.log("newTxState.major == expired => dismiss sheet")
-// TODO: logger.info("newTxState.major == expired => dismiss sheet")
- doneAction() // if this view is in a sheet this action will dissmiss it
- } else if newMajor == .pending {
- if let newMinor {
- if newMinor == .exchangeWaitReserve { // user did confirm on bank website
- symLog.log("newTxState.minor == exchangeWaitReserve => dismiss sheet")
- doneAction() // if this view is in a sheet this action will dissmiss it
- } else if newMinor == .withdrawCoins { // coin-withdrawal has started
- symLog.log("newTxState.minor == withdrawCoins => dismiss sheet")
- doneAction() // if this view is in a sheet this action will dissmiss it
- } else {
- symLog.log("ignoring newTxState: \(newMajor):\(newMinor)")
- }
- }
- } else {
- symLog.log("ignoring newTxState.major: \(newMajor)")
- }
- } else { Task { // runs on MainActor
- do {
- symLog.log("newState: \(newMajor), reloading transaction")
- withAnimation() { transaction = Transaction(dummyCurrency: DEMOCURRENCY); viewId = UUID() }
- let reloadedTransaction = try await reloadAction(common.transactionId)
- symLog.log("reloaded transaction: \(reloadedTransaction.common.txState.major)")
- withAnimation() { transaction = reloadedTransaction; viewId = UUID() } // redraw
- } catch {
- symLog.log(error.localizedDescription)
- }}}
+ Task { // runs on MainActor
+ // flush the screen first, then reload
+ withAnimation() { transaction = Transaction(dummyCurrency: DEMOCURRENCY); viewId = UUID() }
+ symLog.log("newState: \(newMajor), reloading transaction")
+ await loadTransaction(common.transactionId)
+ }
}
} else { // Yikes - should never happen
// TODO: logger.warning("Can't get notification.userInfo as TransactionTransition")
@@ -163,14 +171,8 @@ struct TransactionDetailView: View {
}
.navigationTitle(navTitle ?? navTitle2)
.task {
- do {
- symLog.log("task - load transaction")
- let reloadedTransaction = try await reloadAction(transactionId)
- withAnimation() { transaction = reloadedTransaction; viewId = UUID() } // redraw
- } catch {
- symLog.log(error)
- withAnimation() { transaction = Transaction(dummyCurrency: DEMOCURRENCY); viewId = UUID() }
- }
+ symLog.log("task - load transaction")
+ await loadTransaction(transactionId)
}
.onAppear {
symLog.log("onAppear")
@@ -224,7 +226,7 @@ struct TransactionDetailView: View {
}
}
}
- }
+ } // switch
} // ManualDetails or Confirm with bank
ThreeAmountsSheet(common: common, topAbbrev: String(localized: "Chosen:"),
topTitle: String(localized: "Chosen amount to withdraw:"),