Refresh wallets balances on pull

pull/3273/head
Vladyslav shepitko 3 years ago committed by Vladyslav Shepitko
parent 19b95f8dc8
commit d232ff8f01
  1. 16
      AlphaWallet/Accounts/ViewControllers/AccountsViewController.swift
  2. 28
      AlphaWallet/Core/Coordinators/WalletBalance/PrivateBalanceFetcher.swift
  3. 23
      AlphaWallet/Core/Coordinators/WalletBalance/WalletBalanceCoordinator.swift
  4. 40
      AlphaWallet/Core/Coordinators/WalletBalance/WalletBalanceFetcher.swift
  5. 8
      AlphaWallet/Transactions/Coordinators/BalanceCoordinator.swift
  6. 9
      AlphaWalletTests/Redeem/CreateRedeemTests.swift
  7. 12
      AlphaWalletTests/Settings/Coordinators/SettingsCoordinatorTests.swift

@ -43,6 +43,7 @@ class AccountsViewController: UIViewController {
tableView.rowHeight = UITableView.automaticDimension tableView.rowHeight = UITableView.automaticDimension
tableView.register(AccountViewCell.self) tableView.register(AccountViewCell.self)
tableView.register(WalletSummaryTableViewCell.self) tableView.register(WalletSummaryTableViewCell.self)
tableView.addSubview(tableViewRefreshControl)
roundedBackground.addSubview(tableView) roundedBackground.addSubview(tableView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
@ -53,6 +54,12 @@ class AccountsViewController: UIViewController {
] + roundedBackground.createConstraintsWithContainer(view: view)) ] + roundedBackground.createConstraintsWithContainer(view: view))
} }
private lazy var tableViewRefreshControl: UIRefreshControl = {
let control = UIRefreshControl()
control.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
return control
}()
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
@ -81,6 +88,15 @@ class AccountsViewController: UIViewController {
} }
} }
@objc private func pullToRefresh(_ sender: UIRefreshControl) {
tableViewRefreshControl.beginRefreshing()
walletBalanceCoordinator.refreshBalance(updatePolicy: .all, force: true).done { _ in
// no-op
}.cauterize().finally { [weak self] in
self?.tableViewRefreshControl.endRefreshing()
}
}
private func delete(account: Wallet) { private func delete(account: Wallet) {
navigationController?.displayLoading(text: R.string.localizable.deleting()) navigationController?.displayLoading(text: R.string.localizable.deleting())
let result = keystore.delete(wallet: account) let result = keystore.delete(wallet: account)

@ -21,7 +21,7 @@ protocol PrivateBalanceFetcherType: AnyObject {
var delegate: PrivateTokensDataStoreDelegate? { get set } var delegate: PrivateTokensDataStoreDelegate? { get set }
var erc721TokenIdsFetcher: Erc721TokenIdsFetcher? { get set } var erc721TokenIdsFetcher: Erc721TokenIdsFetcher? { get set }
func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) -> Promise<Void>
} }
// swiftlint:disable type_body_length // swiftlint:disable type_body_length
@ -65,13 +65,17 @@ class PrivateBalanceFetcher: PrivateBalanceFetcherType {
case .initial(let tokenObjects): case .initial(let tokenObjects):
let tokenObjects = tokenObjects.map { Activity.AssignedToken(tokenObject: $0) } let tokenObjects = tokenObjects.map { Activity.AssignedToken(tokenObject: $0) }
strongSelf.refreshBalance(tokenObjects: Array(tokenObjects), updatePolicy: .all, force: true) strongSelf.refreshBalance(tokenObjects: Array(tokenObjects), updatePolicy: .all, force: true).done { _ in
// no-op
}.cauterize()
case .update(let updates, _, let insertions, _): case .update(let updates, _, let insertions, _):
let values = updates.map { Activity.AssignedToken(tokenObject: $0) } let values = updates.map { Activity.AssignedToken(tokenObject: $0) }
let tokenObjects = insertions.map { values[$0] } let tokenObjects = insertions.map { values[$0] }
guard !tokenObjects.isEmpty else { return } guard !tokenObjects.isEmpty else { return }
strongSelf.refreshBalance(tokenObjects: tokenObjects, updatePolicy: .all, force: true) strongSelf.refreshBalance(tokenObjects: tokenObjects, updatePolicy: .all, force: true).done { _ in
// no-op
}.cauterize()
strongSelf.delegate?.didAddToken(in: strongSelf) strongSelf.delegate?.didAddToken(in: strongSelf)
case .error: case .error:
@ -89,7 +93,7 @@ class PrivateBalanceFetcher: PrivateBalanceFetcherType {
return openSea.makeFetchPromise() return openSea.makeFetchPromise()
} }
func refreshBalance(updatePolicy: RefreshBalancePolicy, force: Bool = false) { func refreshBalance(updatePolicy: RefreshBalancePolicy, force: Bool = false) -> Promise<Void> {
Promise<[Activity.AssignedToken]> { seal in Promise<[Activity.AssignedToken]> { seal in
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else { return seal.reject(PMKError.cancelled) } guard let strongSelf = self else { return seal.reject(PMKError.cancelled) }
@ -97,9 +101,9 @@ class PrivateBalanceFetcher: PrivateBalanceFetcherType {
seal.fulfill(tokenObjects) seal.fulfill(tokenObjects)
} }
}.done(on: queue, { tokenObjects in }.then(on: queue, { tokenObjects in
self.refreshBalance(tokenObjects: tokenObjects, updatePolicy: .all, force: false) return self.refreshBalance(tokenObjects: tokenObjects, updatePolicy: .all, force: false)
}).cauterize() })
} }
private func refreshBalanceForNonErc721Or1155Tokens(tokens: [Activity.AssignedToken]) -> Promise<[PrivateBalanceFetcher.TokenBatchOperation]> { private func refreshBalanceForNonErc721Or1155Tokens(tokens: [Activity.AssignedToken]) -> Promise<[PrivateBalanceFetcher.TokenBatchOperation]> {
@ -118,8 +122,8 @@ class PrivateBalanceFetcher: PrivateBalanceFetcherType {
case all case all
} }
private func refreshBalance(tokenObjects: [Activity.AssignedToken], updatePolicy: RefreshBalancePolicy, force: Bool = false) { private func refreshBalance(tokenObjects: [Activity.AssignedToken], updatePolicy: RefreshBalancePolicy, force: Bool = false) -> Promise<Void> {
guard !isRefeshingBalance || force else { return } guard !isRefeshingBalance || force else { return .value(()) }
isRefeshingBalance = true isRefeshingBalance = true
var promises: [Promise<Bool?>] = [] var promises: [Promise<Bool?>] = []
@ -134,18 +138,18 @@ class PrivateBalanceFetcher: PrivateBalanceFetcherType {
promises += [refreshEthBalance(etherToken: etherToken)] promises += [refreshEthBalance(etherToken: etherToken)]
} }
firstly { return firstly {
when(resolved: promises).map(on: queue, { values -> Bool? in when(resolved: promises).map(on: queue, { values -> Bool? in
//NOTE: taking for first element means that values was updated //NOTE: taking for first element means that values was updated
return values.compactMap { $0.optionalValue }.compactMap { $0 }.first return values.compactMap { $0.optionalValue }.compactMap { $0 }.first
}) })
}.done(on: queue, { balanceValueHasChange in }.get(on: queue, { balanceValueHasChange in
self.isRefeshingBalance = false self.isRefeshingBalance = false
if let value = balanceValueHasChange, value { if let value = balanceValueHasChange, value {
self.delegate?.didUpdate(in: self) self.delegate?.didUpdate(in: self)
} }
}) }).asVoid()
} }
private func refreshEthBalance(etherToken: Activity.AssignedToken) -> Promise<Bool?> { private func refreshEthBalance(etherToken: Activity.AssignedToken) -> Promise<Bool?> {

@ -16,8 +16,9 @@ protocol WalletBalanceCoordinatorType: AnyObject {
func subscribableWalletBalance(wallet: Wallet) -> Subscribable<WalletBalance> func subscribableWalletBalance(wallet: Wallet) -> Subscribable<WalletBalance>
func subscribableTokenBalance(addressAndRPCServer: AddressAndRPCServer) -> Subscribable<BalanceBaseViewModel> func subscribableTokenBalance(addressAndRPCServer: AddressAndRPCServer) -> Subscribable<BalanceBaseViewModel>
func start() func start()
func refreshBalance() func refreshBalance() -> Promise<Void>
func refreshEthBalance() func refreshEthBalance() -> Promise<Void>
func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) -> Promise<Void>
func transactionsStorage(wallet: Wallet, server: RPCServer) -> TransactionsStorage func transactionsStorage(wallet: Wallet, server: RPCServer) -> TransactionsStorage
func tokensDatastore(wallet: Wallet, server: RPCServer) -> TokensDataStore func tokensDatastore(wallet: Wallet, server: RPCServer) -> TokensDataStore
@ -83,12 +84,22 @@ class WalletBalanceCoordinator: NSObject, WalletBalanceCoordinatorType {
return .init(nil) return .init(nil)
} }
func refreshBalance() { func refreshBalance() -> Promise<Void> {
balanceFetchers[keystore.currentWallet].flatMap { $0.refreshBalance() } guard let promise = balanceFetchers[keystore.currentWallet].flatMap({ $0.refreshBalance() }) else { return .value(()) }
return promise
} }
func refreshEthBalance() { func refreshEthBalance() -> Promise<Void> {
balanceFetchers[keystore.currentWallet].flatMap { $0.refreshEthBalance() } guard let promise = balanceFetchers[keystore.currentWallet].flatMap({ $0.refreshEthBalance() }) else { return .value(()) }
return promise
}
///Refreshes available wallets balances
func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) -> Promise<Void> {
let promises = keystore.wallets.compactMap { wallet in
balanceFetchers[wallet]?.refreshBalance(updatePolicy: updatePolicy, force: force)
}
return when(resolved: promises).asVoid()
} }
func start() { func start() {

@ -28,8 +28,9 @@ protocol WalletBalanceFetcherType: AnyObject {
func start() func start()
func stop() func stop()
func update(servers: [RPCServer]) func update(servers: [RPCServer])
func refreshEthBalance() func refreshEthBalance() -> Promise<Void>
func refreshBalance() func refreshBalance() -> Promise<Void>
func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) -> Promise<Void>
func transactionsStorage(server: RPCServer) -> TransactionsStorage func transactionsStorage(server: RPCServer) -> TransactionsStorage
func tokensDatastore(server: RPCServer) -> TokensDataStore func tokensDatastore(server: RPCServer) -> TokensDataStore
} }
@ -106,8 +107,8 @@ class WalletBalanceFetcher: NSObject, WalletBalanceFetcherType {
} }
} }
let delatedServers = services.filter { !servers.contains($0.key) }.map { $0.key } let deletedServers = services.filter { !servers.contains($0.key) }.map { $0.key }
for each in delatedServers { for each in deletedServers {
services.remove(at: each) services.remove(at: each)
} }
} }
@ -226,33 +227,48 @@ class WalletBalanceFetcher: NSObject, WalletBalanceFetcherType {
} }
func start() { func start() {
timedCallForBalanceRefresh() timedCallForBalanceRefresh().done { _ in
}.cauterize()
timer = Timer.scheduledTimer(withTimeInterval: Self.updateBalanceInterval, repeats: true) { [weak self] _ in timer = Timer.scheduledTimer(withTimeInterval: Self.updateBalanceInterval, repeats: true) { [weak self] _ in
guard let strongSelf = self else { return } guard let strongSelf = self else { return }
strongSelf.queue.async { strongSelf.queue.async {
strongSelf.timedCallForBalanceRefresh() strongSelf.timedCallForBalanceRefresh().done { _ in
}.cauterize()
} }
} }
} }
private func timedCallForBalanceRefresh() { private func timedCallForBalanceRefresh() -> Promise<Void> {
for each in services { let promises = services.map { each in
each.value.1.refreshBalance(updatePolicy: .all, force: false) each.value.1.refreshBalance(updatePolicy: .all, force: false)
} }
return when(resolved: promises).asVoid()
}
func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) -> Promise<Void> {
let promises = services.map { each in
each.value.1.refreshBalance(updatePolicy: updatePolicy, force: force)
}
return when(resolved: promises).asVoid()
} }
func refreshEthBalance() { func refreshEthBalance() -> Promise<Void> {
for each in services { let promises = services.map { each in
each.value.1.refreshBalance(updatePolicy: .eth, force: true) each.value.1.refreshBalance(updatePolicy: .eth, force: true)
} }
return when(resolved: promises).asVoid()
} }
func refreshBalance() { func refreshBalance() -> Promise<Void> {
for each in services { let promises = services.map { each in
each.value.1.refreshBalance(updatePolicy: .ercTokens, force: true) each.value.1.refreshBalance(updatePolicy: .ercTokens, force: true)
} }
return when(resolved: promises).asVoid()
} }
func stop() { func stop() {

@ -69,10 +69,14 @@ class BalanceCoordinator: NSObject, BalanceCoordinatorType {
} }
func refresh() { func refresh() {
walletBalanceCoordinator.refreshBalance() walletBalanceCoordinator.refreshBalance().done { _ in
}.cauterize()
} }
func refreshEthBalance() { func refreshEthBalance() {
walletBalanceCoordinator.refreshEthBalance() walletBalanceCoordinator.refreshEthBalance().done { _ in
}.cauterize()
} }
func update() { func update() {

@ -18,11 +18,14 @@ class CreateRedeemTests: XCTestCase {
let account = keyStore.createAccount() let account = keyStore.createAccount()
let message = CreateRedeem(token: TokenObject()).redeemMessage(tokenIds: token).0 let message = CreateRedeem(token: TokenObject()).redeemMessage(tokenIds: token).0
let data = message.data(using: String.Encoding.utf8) let data = message.data(using: String.Encoding.utf8)
do {
let signature = try! keyStore.signMessageData(data!, for: account.dematerialize()) let signature = try keyStore.signMessageData(data!, for: account.dematerialize())
//message and signature is to go in qr code //message and signature is to go in qr code
debug("message: " + message) debug("message: " + message)
debug(try! "signature: " + signature.dematerialize().hexString) debug(try "signature: " + signature.dematerialize().hexString)
//TODO no test? //TODO no test?
} catch {
debug(error)
}
} }
} }

@ -72,6 +72,8 @@ class SettingsCoordinatorTests: XCTestCase {
} }
} }
import PromiseKit
final class FakeWalletBalanceCoordinator: WalletBalanceCoordinatorType { final class FakeWalletBalanceCoordinator: WalletBalanceCoordinatorType {
var subscribableWalletsSummary: Subscribable<WalletSummary> = .init(nil) var subscribableWalletsSummary: Subscribable<WalletSummary> = .init(nil)
@ -87,12 +89,16 @@ final class FakeWalletBalanceCoordinator: WalletBalanceCoordinatorType {
} }
func refreshBalance() { func refreshBalance() -> Promise<Void> {
return .value(())
} }
func refreshEthBalance() { func refreshEthBalance() -> Promise<Void> {
return .value(())
}
func refreshBalance(updatePolicy: PrivateBalanceFetcher.RefreshBalancePolicy, force: Bool) -> Promise<Void> {
return .value(())
} }
func transactionsStorage(wallet: Wallet, server: RPCServer) -> TransactionsStorage { func transactionsStorage(wallet: Wallet, server: RPCServer) -> TransactionsStorage {

Loading…
Cancel
Save