diff --git a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj index 2588d69cad..62d92f9928 100644 --- a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj +++ b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj @@ -2232,6 +2232,7 @@ ABC9AC50E2E966F009D78FD5 /* CheckboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A6B2EF46FF7EDA4728D3 /* CheckboxView.swift */; }; ABC9AC5552508D091D622027 /* SendZcashFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A6F55A2C6777D25F57D5 /* SendZcashFactory.swift */; }; ABC9AC55F33A3BFBDBCD5580 /* SendEip1155AvailableBalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AB612DE3C8AA3A1EEAC7 /* SendEip1155AvailableBalanceViewModel.swift */; }; + ABC9AC5671A5EA9BF5ACBC5D /* NoAccountWalletTokenListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A141E4C255C3E450863E /* NoAccountWalletTokenListService.swift */; }; ABC9AC5C8EE0A8C7F10B8A50 /* ContactBookSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A309A58148C40912B964 /* ContactBookSettingsService.swift */; }; ABC9AC692F695C5F81E0453D /* DonateAddressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A525C1E9A53F37EC3918 /* DonateAddressViewController.swift */; }; ABC9AC73C488F8B1F54929B5 /* NftAssetCellFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A30A8F78E9C9AEE861F1 /* NftAssetCellFactory.swift */; }; @@ -2261,6 +2262,7 @@ ABC9ACEE45E455BA098231EE /* SendMemoInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A3C103C1DE359184D944 /* SendMemoInputCell.swift */; }; ABC9AD05E7B986179310D6D7 /* SwapInputAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A56611CF5E7B3F25CD5C /* SwapInputAccessoryView.swift */; }; ABC9AD1C8D0CE88A604D5250 /* SendBinanceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AD0DD32AB4B9BAB79F11 /* SendBinanceFactory.swift */; }; + ABC9AD2688A8DF327A3F92FC /* NoAccountWalletTokenListService.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A141E4C255C3E450863E /* NoAccountWalletTokenListService.swift */; }; ABC9AD27E074CF3FA292C647 /* IndicatorAdviceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A044BFF4E76CD17835CA /* IndicatorAdviceView.swift */; }; ABC9AD3001AAA0570B503876 /* ManageBarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A6CFDF38D413679D2088 /* ManageBarButtonView.swift */; }; ABC9AD3276132B33F6045AFF /* MarketCategoryMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9ADC1A3B17225B6CC0869 /* MarketCategoryMarketCapFetcher.swift */; }; @@ -3690,6 +3692,7 @@ ABC9A12E4155640075755699 /* IndicatorDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndicatorDataSource.swift; sourceTree = ""; }; ABC9A1360FE305343B1049CF /* SwapRevokeConfirmationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapRevokeConfirmationViewController.swift; sourceTree = ""; }; ABC9A13DB598B22516E5AD76 /* RestoreTypeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreTypeViewModel.swift; sourceTree = ""; }; + ABC9A141E4C255C3E450863E /* NoAccountWalletTokenListService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoAccountWalletTokenListService.swift; sourceTree = ""; }; ABC9A1667330B8DBC1A8FE52 /* WalletConnectSessionKiller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletConnectSessionKiller.swift; sourceTree = ""; }; ABC9A1833D302B63028A3966 /* WalletTokenBalanceModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletTokenBalanceModule.swift; sourceTree = ""; }; ABC9A1BD3B1B53C72DDF923A /* SendBitcoinAdapterService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendBitcoinAdapterService.swift; sourceTree = ""; }; @@ -4871,6 +4874,7 @@ 11B357D222B4819BE881E182 /* WalletTokenListViewController.swift */, 11B35C6E5282F55B88042F8D /* WalletTokenListViewItemFactory.swift */, ABC9A3FBE68E228E3BE66F7B /* WalletTokenListDataSource.swift */, + ABC9A141E4C255C3E450863E /* NoAccountWalletTokenListService.swift */, ); path = TokenList; sourceTree = ""; @@ -9174,6 +9178,7 @@ 11B35F134E5EF8572BF330CB /* NavigationRow.swift in Sources */, 11B35FA70EB07440E1576A56 /* RowButton.swift in Sources */, 11B35CA92AA402BE72B4F5D6 /* Image.swift in Sources */, + ABC9AD2688A8DF327A3F92FC /* NoAccountWalletTokenListService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -10459,6 +10464,7 @@ 11B3574287AAA5FC16E3E3DA /* NavigationRow.swift in Sources */, 11B35631BD5C6570C9359BEC /* RowButton.swift in Sources */, 11B3541ED37746BAFF1832BA /* Image.swift in Sources */, + ABC9AC5671A5EA9BF5ACBC5D /* NoAccountWalletTokenListService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift new file mode 100644 index 0000000000..4467cfcef1 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/NoAccountWalletTokenListService.swift @@ -0,0 +1,44 @@ +import Combine +import ComponentKit +import HsExtensions +import RxSwift + +class NoAccountWalletTokenListService: IWalletTokenListService { + let reachabilityManager: IReachabilityManager + let balancePrimaryValueManager: BalancePrimaryValueManager + + var state: WalletTokenListService.State = .noAccount + var stateUpdatedPublisher: AnyPublisher { + Just(state).eraseToAnyPublisher() + } + + init(reachabilityManager: IReachabilityManager, balancePrimaryValueManager: BalancePrimaryValueManager) { + self.reachabilityManager = reachabilityManager + self.balancePrimaryValueManager = balancePrimaryValueManager + } + +} + +extension NoAccountWalletTokenListService { + + var isReachable: Bool { + reachabilityManager.isReachable + } + + var balancePrimaryValueObservable: Observable { + balancePrimaryValueManager.balancePrimaryValueObservable + } + + var balancePrimaryValue: BalancePrimaryValue { + balancePrimaryValueManager.balancePrimaryValue + } + + var itemUpdatedObservable: Observable { + .never() + } + + func item(element: WalletModule.Element) -> WalletTokenListService.Item? { + nil + } + +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift index 68139b6f4e..3b42ca122a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListDataSource.swift @@ -105,8 +105,8 @@ class WalletTokenListDataSource: NSObject { updateIndexes.forEach { if let originalIndexPath = delegate?.originalIndexPath(tableView: tableView, dataSource: self, indexPath: IndexPath(row: $0, section: 0)), let cell = tableView.cellForRow(at: originalIndexPath) as? WalletTokenCell { - let heightBefore = delegate?.height(tableView: tableView, before: self) ?? 0 - bind(cell: cell, index: $0, hideTopSeparator: heightBefore != 0 && $0 == 0, animated: true) + let hideTopSeparator = originalIndexPath.row == 0 && originalIndexPath.section != 0 + bind(cell: cell, index: $0, hideTopSeparator: hideTopSeparator, animated: true) } } } @@ -258,8 +258,9 @@ extension WalletTokenListDataSource: ISectionDataSource { } if let cell = cell as? WalletTokenCell { - let heightBefore = delegate?.height(tableView: tableView, before: self) ?? 0 - bind(cell: cell, index: indexPath.row, hideTopSeparator: heightBefore != 0 && indexPath.row == 0) + let originalIndexPath = delegate?.originalIndexPath(tableView: tableView, dataSource: self, indexPath: indexPath) ?? indexPath + let hideTopSeparator = originalIndexPath.row == 0 && originalIndexPath.section != 0 + bind(cell: cell, index: indexPath.row, hideTopSeparator: hideTopSeparator) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift index 2d7697af63..bfc40d0135 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListService.swift @@ -7,7 +7,7 @@ import HsExtensions import StorageKit import CurrencyKit -class WalletTokenListService { +class WalletTokenListService: IWalletTokenListService { private let elementService: IWalletElementService private let coinPriceService: WalletCoinPriceService private let cacheManager: EnabledWalletCacheManager @@ -40,7 +40,12 @@ class WalletTokenListService { } } - @PostPublished private(set) var state: State = .loading + var state: State = .loading { + didSet { + stateUpdatedSubject.send(state) + } + } + let stateUpdatedSubject = PassthroughSubject() private let itemUpdatedRelay = PublishRelay() @@ -71,12 +76,6 @@ class WalletTokenListService { } private func sync(elementState: WalletModule.ElementState, elementService: IWalletElementService) { - // this service used only for coins accounts, not cexes or watch accounts - if account.cexAccount || account.watchAccount { - internalState = .noAccount - return - } - switch elementState { case .loading: internalState = .loading @@ -142,6 +141,10 @@ class WalletTokenListService { } } + var stateUpdatedPublisher: AnyPublisher { + stateUpdatedSubject.eraseToAnyPublisher() + } + var balancePrimaryValueObservable: Observable { balancePrimaryValueManager.balancePrimaryValueObservable } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift index 88353791df..f5145bfa7e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/TokenList/WalletTokenListViewModel.swift @@ -6,8 +6,20 @@ import RxCocoa import MarketKit import HsExtensions +protocol IWalletTokenListService { + var state: WalletTokenListService.State { get set } + var stateUpdatedPublisher: AnyPublisher { get } + + var isReachable: Bool { get } + var balancePrimaryValueObservable: Observable { get } + var balancePrimaryValue: BalancePrimaryValue { get } + var itemUpdatedObservable: Observable { get } + + func item(element: WalletModule.Element) -> WalletTokenListService.Item? +} + class WalletTokenListViewModel { - private let service: WalletTokenListService + private let service: IWalletTokenListService private let factory: WalletTokenListViewItemFactory private var cancellables = Set() private let disposeBag = DisposeBag() @@ -27,7 +39,7 @@ class WalletTokenListViewModel { private let queue = DispatchQueue(label: "\(AppConfig.label).wallet-tokens-view-model", qos: .userInitiated) - init(service: WalletTokenListService, factory: WalletTokenListViewItemFactory, title: String, emptyText: String) { + init(service: IWalletTokenListService, factory: WalletTokenListViewItemFactory, title: String, emptyText: String) { self.service = service self.factory = factory self.title = title @@ -36,7 +48,7 @@ class WalletTokenListViewModel { subscribe(disposeBag, service.itemUpdatedObservable) { [weak self] in self?.syncUpdated(item: $0) } subscribe(disposeBag, service.balancePrimaryValueObservable) { [weak self] _ in self?.onUpdateBalancePrimaryValue() } - service.$state + service.stateUpdatedPublisher .sink { [weak self] in self?.sync(serviceState: $0) } .store(in: &cancellables) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletModule.swift index 9262a876ed..7bdad50b16 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/WalletModule.swift @@ -167,37 +167,43 @@ struct WalletModule { } static func donateTokenListViewController() -> UIViewController? { - guard let account = App.shared.accountManager.activeAccount else { - return nil + let service: IWalletTokenListService + if let account = App.shared.accountManager.activeAccount, !account.watchAccount, !account.cexAccount { + let coinPriceService = WalletCoinPriceService( + tag: "send-token-list", + currencyKit: App.shared.currencyKit, + marketKit: App.shared.marketKit + ) + + let adapterService = WalletAdapterService(account: account, adapterManager: App.shared.adapterManager) + let elementService = WalletBlockchainElementService( + account: account, + adapterService: adapterService, + walletManager: App.shared.walletManager + ) + adapterService.delegate = elementService + + let tokenListService = WalletTokenListService( + elementService: elementService, + coinPriceService: coinPriceService, + cacheManager: App.shared.enabledWalletCacheManager, + reachabilityManager: App.shared.reachabilityManager, + balancePrimaryValueManager: App.shared.balancePrimaryValueManager, + appManager: App.shared.appManager, + feeCoinProvider: App.shared.feeCoinProvider, + account: account + ) + elementService.delegate = tokenListService + coinPriceService.delegate = tokenListService + + service = tokenListService + } else { + service = NoAccountWalletTokenListService( + reachabilityManager: App.shared.reachabilityManager, + balancePrimaryValueManager: App.shared.balancePrimaryValueManager + ) } - let coinPriceService = WalletCoinPriceService( - tag: "send-token-list", - currencyKit: App.shared.currencyKit, - marketKit: App.shared.marketKit - ) - - let adapterService = WalletAdapterService(account: account, adapterManager: App.shared.adapterManager) - let elementService = WalletBlockchainElementService( - account: account, - adapterService: adapterService, - walletManager: App.shared.walletManager - ) - adapterService.delegate = elementService - - let service = WalletTokenListService( - elementService: elementService, - coinPriceService: coinPriceService, - cacheManager: App.shared.enabledWalletCacheManager, - reachabilityManager: App.shared.reachabilityManager, - balancePrimaryValueManager: App.shared.balancePrimaryValueManager, - appManager: App.shared.appManager, - feeCoinProvider: App.shared.feeCoinProvider, - account: account - ) - elementService.delegate = service - coinPriceService.delegate = service - let viewModel = WalletTokenListViewModel( service: service, factory: WalletTokenListViewItemFactory(),