diff --git a/Kukai Mobile/Localization/en.lproj/Localizable.strings b/Kukai Mobile/Localization/en.lproj/Localizable.strings index b2cb777d..d83588c4 100644 --- a/Kukai Mobile/Localization/en.lproj/Localizable.strings +++ b/Kukai Mobile/Localization/en.lproj/Localizable.strings @@ -73,5 +73,6 @@ "error-unknown"="Unknwon error occured"; "error-unknown-later"="Unknwon error occured fetching information. PLease try again later"; +"error-stake-wizard-unknown"="The server failed to respond multiple times to indicate the status of the transaction. Please try again later"; "warning-fee-very-high"="Warning: Transaction fee is very high"; diff --git a/Kukai Mobile/Modules/Account/AccountViewController.swift b/Kukai Mobile/Modules/Account/AccountViewController.swift index e6edac97..79371766 100644 --- a/Kukai Mobile/Modules/Account/AccountViewController.swift +++ b/Kukai Mobile/Modules/Account/AccountViewController.swift @@ -69,6 +69,7 @@ class AccountViewController: UIViewController, UITableViewDelegate, EstimatedTot override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) AccountViewModel.reconnectAccountActivityListenerIfNeeded() + refreshControl.didMoveToSuperview() } override func viewWillDisappear(_ animated: Bool) { diff --git a/Kukai Mobile/Modules/Stake/StakeOnboardingContainerViewController.swift b/Kukai Mobile/Modules/Stake/StakeOnboardingContainerViewController.swift index b0de8522..4b090afa 100644 --- a/Kukai Mobile/Modules/Stake/StakeOnboardingContainerViewController.swift +++ b/Kukai Mobile/Modules/Stake/StakeOnboardingContainerViewController.swift @@ -8,6 +8,7 @@ import UIKit import KukaiCoreSwift import Combine +import OSLog class StakeOnboardingContainerViewController: UIViewController { @@ -33,6 +34,12 @@ class StakeOnboardingContainerViewController: UIViewController { private var currentStep: String = "" private var isStakeOnly = false + private var backupTimer: Timer? = nil + private var numberOfTimesPendingCalled = 0 + private var pendingHandledByAutomaticChecker = false + private var pendingHandledByManualChecker = false + private var numberOfManualChecks = 0 + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) @@ -80,10 +87,20 @@ class StakeOnboardingContainerViewController: UIViewController { DispatchQueue.main.async { [weak self] in if addresses.contains([address]) { + self?.numberOfTimesPendingCalled += 1 + self?.pendingHandledByAutomaticChecker = false + self?.pendingHandledByManualChecker = false + self?.numberOfManualChecks = 0 + self?.backupOperationCompleteChecker(withTime: 12) + self?.showLoadingView() self?.updateLoadingViewStatusLabel(message: "Waiting for transaction to complete \n\nThis should only take a few seconds") } else { + self?.backupTimer?.invalidate() + self?.backupTimer = nil + self?.pendingHandledByAutomaticChecker = true + self?.hideLoadingView() self?.handleOperationComplete() } @@ -93,6 +110,9 @@ class StakeOnboardingContainerViewController: UIViewController { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) + + backupTimer?.invalidate() + backupTimer = nil } func setProgressSegmentComplete(_ view: UIProgressView?) { @@ -101,6 +121,62 @@ class StakeOnboardingContainerViewController: UIViewController { } } + private func backupOperationCompleteChecker(withTime: TimeInterval) { + + self.backupTimer = Timer.scheduledTimer(withTimeInterval: withTime, repeats: false, block: { [weak self] t in + guard self?.pendingHandledByAutomaticChecker == false else { + Logger.app.info("backupOperationCompleteChecker exiting due to automatic check succeeding") + return + } + + Logger.app.info("backupOperationCompleteChecker proceeding due to automatic check failing") + let currentAddress = DependencyManager.shared.selectedWalletAddress ?? "" + DependencyManager.shared.tzktClient.getAccount(forAddress: currentAddress) { result in + self?.numberOfManualChecks += 1 + + guard let res = try? result.get() else { + self?.backupOperationCheckerFail() + Logger.app.error("backupOperationCompleteChecker encountered failure fetching account") + return + } + + if self?.numberOfTimesPendingCalled == 1 && self?.isStakeOnly == false { + if res.delegate != nil { + Logger.app.info("backupOperationCompleteChecker delegation check succeeded") + self?.backupOperationCheckerSuccess() + } else { + Logger.app.error("backupOperationCompleteChecker delegation check failed") + self?.backupOperationCheckerFail() + } + + } else if (self?.numberOfTimesPendingCalled == 2 && self?.isStakeOnly == false) || self?.isStakeOnly == true { + if (res.stakedBalance ?? 0) > 0 { + Logger.app.info("backupOperationCompleteChecker stake check succeeded") + self?.backupOperationCheckerSuccess() + } else { + Logger.app.error("backupOperationCompleteChecker stake check failed") + self?.backupOperationCheckerFail() + } + } + } + }) + } + + private func backupOperationCheckerSuccess() { + hideLoadingView() + handleOperationComplete() + } + + private func backupOperationCheckerFail() { + if numberOfManualChecks == 0 { + backupOperationCompleteChecker(withTime: 5) + } else { + hideLoadingView() + self.windowError(withTitle: "error".localized(), description: "error-stake-wizard-unknown".localized()) + self.navigationController?.popToDetails() + } + } + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if !isStakeOnly, segue.identifier == "embed-delegate", let dest = segue.destination as? UINavigationController { childNavigationController = dest