Stop a slow chain refresh from showing the wrong wallet balance
This commit is contained in:
@@ -23,6 +23,9 @@ final class AppModel: ObservableObject {
|
||||
private var refreshTask: Task<Void, Never>?
|
||||
private var lastSample: (height: UInt64, date: Date)?
|
||||
private var lastCheckpoint = Date.distantPast
|
||||
/// Invalidates in-flight refreshes: switching chains (or starting a newer
|
||||
/// refresh) must stop an older request from writing its result to the UI.
|
||||
private var refreshToken = UUID()
|
||||
|
||||
var wallet: WalletRecord? {
|
||||
chain == .xrp ? xrpWallet : xmrWallet
|
||||
@@ -93,6 +96,7 @@ final class AppModel: ObservableObject {
|
||||
|
||||
func select(_ newChain: Chain) async {
|
||||
chain = newChain
|
||||
refreshToken = UUID()
|
||||
errorMessage = nil
|
||||
statusMessage = nil
|
||||
balance = Balance(total: "0", unlocked: "", funded: false)
|
||||
@@ -200,14 +204,21 @@ final class AppModel: ObservableObject {
|
||||
|
||||
func refresh(force: Bool = false) async {
|
||||
guard hasWallet else { return }
|
||||
let token = UUID()
|
||||
refreshToken = token
|
||||
let requestChain = chain
|
||||
errorMessage = nil
|
||||
if chain == .xrp, let wallet = xrpWallet {
|
||||
do {
|
||||
async let balanceCall = XRPWalletService.shared.balance(address: wallet.address)
|
||||
async let txCall = XRPWalletService.shared.transactions(address: wallet.address)
|
||||
balance = try await balanceCall
|
||||
transactions = try await txCall
|
||||
let fetchedBalance = try await balanceCall
|
||||
let fetchedTransactions = try await txCall
|
||||
guard !isStale(token, requestChain) else { return }
|
||||
balance = fetchedBalance
|
||||
transactions = fetchedTransactions
|
||||
} catch {
|
||||
guard !isStale(token, requestChain) else { return }
|
||||
errorMessage = error.localizedDescription
|
||||
}
|
||||
// The Monero wallet keeps scanning while XRP is on screen, so keep its
|
||||
@@ -223,22 +234,36 @@ final class AppModel: ObservableObject {
|
||||
do {
|
||||
// Sync progress is cheap and polled every tick; the balance and transfer
|
||||
// list touch the wallet's data files, so they are refreshed less often.
|
||||
updateSyncStatus(try await MoneroService.shared.syncStatus())
|
||||
let status = try await MoneroService.shared.syncStatus()
|
||||
if !isStale(token, requestChain) {
|
||||
updateSyncStatus(status)
|
||||
}
|
||||
refreshTick += 1
|
||||
await checkpointWalletIfSyncing()
|
||||
if force || refreshTick == 1 || refreshTick % 4 == 0 {
|
||||
async let balanceCall = MoneroService.shared.balance()
|
||||
async let txCall = MoneroService.shared.transactions()
|
||||
async let accountsCall = MoneroService.shared.accounts()
|
||||
balance = try await balanceCall
|
||||
transactions = try await txCall
|
||||
moneroAccounts = try await accountsCall
|
||||
let fetchedBalance = try await balanceCall
|
||||
let fetchedTransactions = try await txCall
|
||||
let fetchedAccounts = try await accountsCall
|
||||
guard !isStale(token, requestChain) else { return }
|
||||
balance = fetchedBalance
|
||||
transactions = fetchedTransactions
|
||||
moneroAccounts = fetchedAccounts
|
||||
}
|
||||
} catch {
|
||||
guard !isStale(token, requestChain) else { return }
|
||||
errorMessage = error.localizedDescription
|
||||
}
|
||||
}
|
||||
|
||||
/// True when a newer refresh has started or the user moved to another chain
|
||||
/// while this request was in flight.
|
||||
private func isStale(_ token: UUID, _ requestChain: Chain) -> Bool {
|
||||
token != refreshToken || requestChain != chain
|
||||
}
|
||||
|
||||
/// Tracks how fast blocks are being scanned so the UI can show an estimate.
|
||||
private func updateSyncStatus(_ status: SyncStatus) {
|
||||
syncStatus = status
|
||||
|
||||
Reference in New Issue
Block a user