diff --git a/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriber.swift index d8ea4f7c0..dd1e3b2e4 100644 --- a/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriber.swift @@ -9,6 +9,33 @@ protocol WalletListLocalStorageSubscriber where Self: AnyObject { func subscribeAllWalletsProvider() -> StreamableProvider? func subscribeWallet(by walletId: String) -> StreamableProvider? + + func subscribeSelectedWalletProvider() -> StreamableProvider? +} + +private extension WalletListLocalStorageSubscriber { + func subscribeWallets( + provider: StreamableProvider, + updateClosure: @escaping ([DataProviderChange]) -> Void, + failureClosure: @escaping (Error) -> Void + ) -> StreamableProvider? { + let options = StreamableProviderObserverOptions( + alwaysNotifyOnRefresh: false, + waitsInProgressSyncOnAdd: false, + initialSize: 0, + refreshWhenEmpty: false + ) + + provider.addObserver( + self, + deliverOn: .main, + executing: updateClosure, + failing: failureClosure, + options: options + ) + + return provider + } } extension WalletListLocalStorageSubscriber { @@ -27,22 +54,11 @@ extension WalletListLocalStorageSubscriber { return } - let options = StreamableProviderObserverOptions( - alwaysNotifyOnRefresh: false, - waitsInProgressSyncOnAdd: false, - initialSize: 0, - refreshWhenEmpty: false + return subscribeWallets( + provider: provider, + updateClosure: updateClosure, + failureClosure: failureClosure ) - - provider.addObserver( - self, - deliverOn: .main, - executing: updateClosure, - failing: failureClosure, - options: options - ) - - return provider } func subscribeWallet(by walletId: String) -> StreamableProvider? { @@ -58,26 +74,39 @@ extension WalletListLocalStorageSubscriber { } let failureClosure = { [weak self] (error: Error) in - self?.walletListLocalSubscriptionHandler.handleAllWallets(result: .failure(error)) + self?.walletListLocalSubscriptionHandler.handleWallet(result: .failure(error), for: walletId) return } - let options = StreamableProviderObserverOptions( - alwaysNotifyOnRefresh: false, - waitsInProgressSyncOnAdd: false, - initialSize: 0, - refreshWhenEmpty: false + return subscribeWallets( + provider: provider, + updateClosure: updateClosure, + failureClosure: failureClosure ) + } - provider.addObserver( - self, - deliverOn: .main, - executing: updateClosure, - failing: failureClosure, - options: options - ) + func subscribeSelectedWalletProvider() -> StreamableProvider? { + guard let provider = try? walletListLocalSubscriptionFactory.getSelectedWalletProvider() else { + return nil + } - return provider + let updateClosure = { [weak self] (changes: [DataProviderChange]) in + let wallet = changes.reduceToLastChange() + + self?.walletListLocalSubscriptionHandler.handleSelectedWallet(result: .success(wallet)) + return + } + + let failureClosure = { [weak self] (error: Error) in + self?.walletListLocalSubscriptionHandler.handleSelectedWallet(result: .failure(error)) + return + } + + return subscribeWallets( + provider: provider, + updateClosure: updateClosure, + failureClosure: failureClosure + ) } } diff --git a/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriptionHandler.swift b/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriptionHandler.swift index 283c3bc65..e72a72eb6 100644 --- a/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriptionHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/WalletListLocalStorageSubscriptionHandler.swift @@ -4,9 +4,11 @@ import Operation_iOS protocol WalletListLocalSubscriptionHandler { func handleAllWallets(result: Result<[DataProviderChange], Error>) func handleWallet(result: Result, for walletId: String) + func handleSelectedWallet(result: Result) } extension WalletListLocalSubscriptionHandler { func handleAllWallets(result _: Result<[DataProviderChange], Error>) {} func handleWallet(result _: Result, for _: String) {} + func handleSelectedWallet(result _: Result) {} } diff --git a/novawallet/Common/DataProvider/WalletListLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/WalletListLocalSubscriptionFactory.swift index a03ec6016..1e644cee3 100644 --- a/novawallet/Common/DataProvider/WalletListLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/WalletListLocalSubscriptionFactory.swift @@ -3,6 +3,7 @@ import Operation_iOS protocol WalletListLocalSubscriptionFactoryProtocol { func getWalletProvider(for walletId: String) throws -> StreamableProvider + func getSelectedWalletProvider() throws -> StreamableProvider func getWalletsProvider() throws -> StreamableProvider } @@ -28,11 +29,15 @@ final class WalletListLocalSubscriptionFactory: BaseLocalSubscriptionFactory { } } -extension WalletListLocalSubscriptionFactory: WalletListLocalSubscriptionFactoryProtocol { - func getWalletProvider(for walletId: String) throws -> StreamableProvider { - clearIfNeeded() +// MARK: Private - let cacheKey = "wallet-\(walletId)" +private extension WalletListLocalSubscriptionFactory { + func getWalletProvider( + cacheKey: String, + with filter: NSPredicate?, + predicateClosure: @escaping (ManagedMetaAccountMapper.CoreDataEntity) -> Bool + ) throws -> StreamableProvider { + clearIfNeeded() if let provider = getProvider(for: cacheKey) as? StreamableProvider { return provider @@ -42,7 +47,6 @@ extension WalletListLocalSubscriptionFactory: WalletListLocalSubscriptionFactory let mapper = ManagedMetaAccountMapper() - let filter = NSPredicate.metaAccountById(walletId) let repository = storageFacade.createRepository( filter: filter, sortDescriptors: [], @@ -52,7 +56,7 @@ extension WalletListLocalSubscriptionFactory: WalletListLocalSubscriptionFactory let observable = CoreDataContextObservable( service: storageFacade.databaseService, mapper: AnyCoreDataMapper(mapper), - predicate: { entity in entity.metaId == walletId } + predicate: predicateClosure ) observable.start { [weak self] error in @@ -72,42 +76,50 @@ extension WalletListLocalSubscriptionFactory: WalletListLocalSubscriptionFactory return provider } +} - func getWalletsProvider() throws -> StreamableProvider { - clearIfNeeded() - - let cacheKey = "all-wallets" +// MARK: WalletListLocalSubscriptionFactoryProtocol - if let provider = getProvider(for: cacheKey) as? StreamableProvider { - return provider - } - - let source = EmptyStreamableSource() +extension WalletListLocalSubscriptionFactory: WalletListLocalSubscriptionFactoryProtocol { + func getWalletProvider(for walletId: String) throws -> StreamableProvider { + try getWalletProvider( + cacheKey: CacheKeys.wallet(with: walletId), + with: NSPredicate.metaAccountById(walletId), + predicateClosure: { entity in entity.metaId == walletId } + ) + } - let mapper = ManagedMetaAccountMapper() - let repository = storageFacade.createRepository(mapper: AnyCoreDataMapper(mapper)) + func getSelectedWalletProvider() throws -> StreamableProvider { + try getWalletProvider( + cacheKey: CacheKeys.selectedWallet, + with: NSPredicate.selectedMetaAccount(), + predicateClosure: { $0.isSelected } + ) + } - let observable = CoreDataContextObservable( - service: storageFacade.databaseService, - mapper: AnyCoreDataMapper(mapper), - predicate: { _ in true } + func getWalletsProvider() throws -> StreamableProvider { + try getWalletProvider( + cacheKey: CacheKeys.allWallets, + with: nil, + predicateClosure: { _ in true } ) + } +} - observable.start { [weak self] error in - if let error = error { - self?.logger.error("Did receive error: \(error)") - } - } +// MARK: CacheKeys - let provider = StreamableProvider( - source: AnyStreamableSource(source), - repository: AnyDataProviderRepository(repository), - observable: AnyDataProviderRepositoryObservable(observable), - operationManager: operationManager - ) +private extension WalletListLocalSubscriptionFactory { + enum CacheKeys { + static var allWallets: String { + "all-wallets" + } - saveProvider(provider, for: cacheKey) + static var selectedWallet: String { + "selected-wallet" + } - return provider + static func wallet(with id: String) -> String { + "wallet-\(id)" + } } } diff --git a/novawallet/Common/Extension/Foundation/Predicate/NSPredicate+Filter.swift b/novawallet/Common/Extension/Foundation/Predicate/NSPredicate+Filter.swift index 9c089319d..4c6af3999 100644 --- a/novawallet/Common/Extension/Foundation/Predicate/NSPredicate+Filter.swift +++ b/novawallet/Common/Extension/Foundation/Predicate/NSPredicate+Filter.swift @@ -310,6 +310,10 @@ extension NSPredicate { NSPredicate(format: "%K == %@", #keyPath(CDDAppFavorite.identifier), identifier) } + static func filterDAppBrowserTabs(by metaId: String) -> NSPredicate { + NSPredicate(format: "%K == %@", #keyPath(CDDAppBrowserTab.metaId), metaId) + } + static func filterAuthorizedBrowserDApps(by metaId: String) -> NSPredicate { let metaId = NSPredicate(format: "%K == %@", #keyPath(CDDAppSettings.metaId), metaId) let source = NSPredicate(format: "%K = nil", #keyPath(CDDAppSettings.source)) diff --git a/novawallet/Common/Storage/EntityToModel/DAppBrowserTabMapper.swift b/novawallet/Common/Storage/EntityToModel/DAppBrowserTabMapper.swift index 80782c22a..54ce4bc63 100644 --- a/novawallet/Common/Storage/EntityToModel/DAppBrowserTabMapper.swift +++ b/novawallet/Common/Storage/EntityToModel/DAppBrowserTabMapper.swift @@ -16,6 +16,7 @@ extension DAppBrowserTabMapper: CoreDataMapperProtocol { uuid: UUID(uuidString: entity.identifier!)!, name: entity.label, url: entity.url!, + metaId: entity.metaId!, createdAt: entity.createdAt!, renderModifiedAt: entity.renderModifiedAt, icon: entity.icon, @@ -31,6 +32,7 @@ extension DAppBrowserTabMapper: CoreDataMapperProtocol { entity.identifier = model.identifier entity.label = model.name entity.url = model.url + entity.metaId = model.metaId entity.createdAt = model.createdAt entity.renderModifiedAt = model.renderModifiedAt entity.icon = model.icon diff --git a/novawallet/Common/Storage/UserDataModel.xcdatamodeld/MultiassetUserDataModel14.xcdatamodel/contents b/novawallet/Common/Storage/UserDataModel.xcdatamodeld/MultiassetUserDataModel14.xcdatamodel/contents index 28c15f1c6..563787d7d 100644 --- a/novawallet/Common/Storage/UserDataModel.xcdatamodeld/MultiassetUserDataModel14.xcdatamodel/contents +++ b/novawallet/Common/Storage/UserDataModel.xcdatamodeld/MultiassetUserDataModel14.xcdatamodel/contents @@ -22,6 +22,7 @@ + diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserInteractor.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserInteractor.swift index 6a2ef0391..5e92f00e2 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserInteractor.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserInteractor.swift @@ -330,7 +330,10 @@ private extension DAppBrowserInteractor { } func proceedWithNewTab(opening dApp: DApp) { - let newTab = DAppBrowserTab(from: dApp) + let newTab = DAppBrowserTab( + from: dApp, + metaId: dataSource.wallet.metaId + ) let states = transports.compactMap { $0.makeOpaqueState() } diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListPresenter.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListPresenter.swift index f2a930ee0..e4b556180 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListPresenter.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListPresenter.swift @@ -7,6 +7,8 @@ final class DAppBrowserTabListPresenter { let interactor: DAppBrowserTabListInteractorInputProtocol let localizationManager: LocalizationManagerProtocol + let metaId: MetaAccountModel.Id + private let viewModelFactory: DAppBrowserTabListViewModelFactoryProtocol private var tabs: [DAppBrowserTab] = [] @@ -15,11 +17,13 @@ final class DAppBrowserTabListPresenter { interactor: DAppBrowserTabListInteractorInputProtocol, wireframe: DAppBrowserTabListWireframeProtocol, viewModelFactory: DAppBrowserTabListViewModelFactoryProtocol, + metaId: MetaAccountModel.Id, localizationManager: LocalizationManagerProtocol ) { self.interactor = interactor self.wireframe = wireframe self.viewModelFactory = viewModelFactory + self.metaId = metaId self.localizationManager = localizationManager } } @@ -98,7 +102,7 @@ extension DAppBrowserTabListPresenter: DAppBrowserTabListInteractorOutputProtoco extension DAppBrowserTabListPresenter: DAppSearchDelegate { func didCompleteDAppSearchResult(_ result: DAppSearchResult) { - guard let tab = DAppBrowserTab(from: result) else { + guard let tab = DAppBrowserTab(from: result, metaId: metaId) else { return } diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListViewFactory.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListViewFactory.swift index 02a213a89..e9475183c 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListViewFactory.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserTabList/DAppBrowserTabListViewFactory.swift @@ -36,10 +36,13 @@ struct DAppBrowserTabListViewFactory { ) let viewModelFactory = DAppBrowserTabListViewModelFactory(imageViewModelFactory: imageViewModelFactory) + let wallet: MetaAccountModel = SelectedWalletSettings.shared.value + let presenter = DAppBrowserTabListPresenter( interactor: interactor, wireframe: wireframe, viewModelFactory: viewModelFactory, + metaId: wallet.metaId, localizationManager: localizationManager ) diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetInteractor.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetInteractor.swift index 6c202b906..b3f5739fa 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetInteractor.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetInteractor.swift @@ -5,14 +5,9 @@ final class DAppBrowserWidgetInteractor { weak var presenter: DAppBrowserWidgetInteractorOutputProtocol? private let tabManager: DAppBrowserTabManagerProtocol - private let eventCenter: EventCenterProtocol - init( - tabManager: DAppBrowserTabManagerProtocol, - eventCenter: EventCenterProtocol - ) { + init(tabManager: DAppBrowserTabManagerProtocol) { self.tabManager = tabManager - self.eventCenter = eventCenter } } @@ -24,10 +19,6 @@ extension DAppBrowserWidgetInteractor: DAppBrowserWidgetInteractorInputProtocol self, sendOnSubscription: false ) - eventCenter.add( - observer: self, - dispatchIn: .main - ) } func closeTabs() { @@ -44,11 +35,3 @@ extension DAppBrowserWidgetInteractor: DAppBrowserTabsObserver { presenter?.didReceive(tabsById) } } - -// MARK: EventVisitorProtocol - -extension DAppBrowserWidgetInteractor: EventVisitorProtocol { - func processSelectedWalletChanged(event _: SelectedWalletSwitched) { - presenter?.didReceiveWalletChanged() - } -} diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetPresenter.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetPresenter.swift index 953dded60..e2a276e00 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetPresenter.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetPresenter.swift @@ -146,6 +146,8 @@ extension DAppBrowserWidgetPresenter: DAppBrowserWidgetInteractorOutputProtocol case .disabled where !browserTabs.isEmpty: state = .closed view?.didReceiveRequestForMinimizing() + case .closed where !browserTabs.isEmpty: + view?.didReceiveRequestForMinimizing() case .miniature where browserTabs.isEmpty: state = .closed provideModel() @@ -153,10 +155,6 @@ extension DAppBrowserWidgetPresenter: DAppBrowserWidgetInteractorOutputProtocol break } } - - func didReceiveWalletChanged() { - view?.didChangeWallet() - } } // MARK: Localizable diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetProtocols.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetProtocols.swift index 43a2dce8e..456a6eb5d 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetProtocols.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetProtocols.swift @@ -19,7 +19,6 @@ protocol DAppBrowserWidgetProtocol { protocol DAppBrowserWidgetViewProtocol: ControllerBackedProtocol { func didReceive(_ browserWidgetModel: DAppBrowserWidgetModel) func didReceiveRequestForMinimizing() - func didChangeWallet() } // MARK: VIEW -> PRESENTER @@ -47,7 +46,6 @@ protocol DAppBrowserWidgetInteractorInputProtocol: AnyObject { protocol DAppBrowserWidgetInteractorOutputProtocol: AnyObject { func didReceive(_ browserTabs: [UUID: DAppBrowserTab]) - func didReceiveWalletChanged() } // MARK: PRESENTER -> WIREFRAME diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewController.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewController.swift index 689d867e4..738e57ff9 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewController.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewController.swift @@ -87,10 +87,6 @@ private extension DAppBrowserWidgetViewController { // MARK: DAppBrowserWidgetViewProtocol extension DAppBrowserWidgetViewController: DAppBrowserWidgetViewProtocol { - func didChangeWallet() { - webViewPoolEraser.removeAll() - } - func didReceiveRequestForMinimizing() { minimize() } diff --git a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewFactory.swift b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewFactory.swift index ba14a06d5..398559cb8 100644 --- a/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewFactory.swift +++ b/novawallet/Modules/DApp/DAppBrowser/DAppBrowserWidget/DAppBrowserWidgetViewFactory.swift @@ -3,10 +3,7 @@ import SoraFoundation struct DAppBrowserWidgetViewFactory { static func createView() -> DAppBrowserWidgetViewProtocol? { - let interactor = DAppBrowserWidgetInteractor( - tabManager: DAppBrowserTabManager.shared, - eventCenter: EventCenter.shared - ) + let interactor = DAppBrowserWidgetInteractor(tabManager: DAppBrowserTabManager.shared) let wireframe = DAppBrowserWidgetWireframe() diff --git a/novawallet/Modules/DApp/DAppBrowser/Model/DAppBrowserTab.swift b/novawallet/Modules/DApp/DAppBrowser/Model/DAppBrowserTab.swift index 382cfa540..5d5613327 100644 --- a/novawallet/Modules/DApp/DAppBrowser/Model/DAppBrowserTab.swift +++ b/novawallet/Modules/DApp/DAppBrowser/Model/DAppBrowserTab.swift @@ -5,6 +5,7 @@ struct DAppBrowserTab { let uuid: UUID let name: String? let url: URL + let metaId: MetaAccountModel.Id let createdAt: Date let renderModifiedAt: Date? let transportStates: [DAppTransportState]? @@ -16,6 +17,7 @@ struct DAppBrowserTab { uuid: uuid, name: name, url: url, + metaId: metaId, createdAt: createdAt, renderModifiedAt: renderModifiedAt, icon: icon?.absoluteString, @@ -27,6 +29,7 @@ struct DAppBrowserTab { uuid: UUID, name: String?, url: URL, + metaId: MetaAccountModel.Id, createdAt: Date, renderModifiedAt: Date?, transportStates: [DAppTransportState]?, @@ -36,6 +39,7 @@ struct DAppBrowserTab { self.uuid = uuid self.name = name self.url = url + self.metaId = metaId self.createdAt = createdAt self.renderModifiedAt = renderModifiedAt self.transportStates = transportStates @@ -43,16 +47,22 @@ struct DAppBrowserTab { self.icon = icon } - init?(from searchResult: DAppSearchResult) { + init?( + from searchResult: DAppSearchResult, + metaId: MetaAccountModel.Id + ) { switch searchResult { case let .query(query): - self.init(from: query) + self.init(from: query, metaId: metaId) case let .dApp(dApp): - self.init(from: dApp) + self.init(from: dApp, metaId: metaId) } } - init?(from query: String) { + init?( + from query: String, + metaId: MetaAccountModel.Id + ) { guard let url = DAppBrowserTab.resolveUrl(for: query) else { return nil } @@ -65,9 +75,13 @@ struct DAppBrowserTab { name = nil icon = nil self.url = url + self.metaId = metaId } - init(from dApp: DApp) { + init( + from dApp: DApp, + metaId: MetaAccountModel.Id + ) { uuid = UUID() createdAt = Date() renderModifiedAt = nil @@ -76,6 +90,7 @@ struct DAppBrowserTab { name = dApp.name url = dApp.url icon = dApp.icon + self.metaId = metaId } func updating( @@ -89,6 +104,7 @@ struct DAppBrowserTab { uuid: uuid, name: name ?? self.name, url: url, + metaId: metaId, createdAt: createdAt, renderModifiedAt: renderModifiedAt ?? self.renderModifiedAt, transportStates: transportStates ?? self.transportStates, @@ -113,6 +129,7 @@ struct DAppBrowserTab { uuid: uuid, name: dApp.name, url: dApp.url, + metaId: metaId, createdAt: createdAt, renderModifiedAt: renderModifiedAt, transportStates: nil, @@ -126,6 +143,7 @@ struct DAppBrowserTab { uuid: uuid, name: nil, url: url, + metaId: metaId, createdAt: createdAt, renderModifiedAt: renderModifiedAt, transportStates: nil, @@ -139,6 +157,7 @@ struct DAppBrowserTab { uuid: uuid, name: name, url: url, + metaId: metaId, createdAt: createdAt, renderModifiedAt: renderModifiedAt, transportStates: nil, @@ -177,6 +196,7 @@ extension DAppBrowserTab { let uuid: UUID let name: String? let url: URL + let metaId: String let createdAt: Date let renderModifiedAt: Date? let icon: String? diff --git a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager+Singleton.swift b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager+Singleton.swift index ba376e226..7cfbad9ed 100644 --- a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager+Singleton.swift +++ b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager+Singleton.swift @@ -2,8 +2,6 @@ import Foundation import Operation_iOS extension DAppBrowserTabManager { - private static let readWriteQueueLabel = "\(String(describing: DAppBrowserTabManager.self)) sync queue" - static let shared: DAppBrowserTabManager = { let mapper = DAppBrowserTabMapper() let storageFacade = UserDataStorageFacade.shared @@ -22,15 +20,23 @@ extension DAppBrowserTabManager { let operationQueue = OperationManagerFacade.sharedDefaultQueue let logger = Logger.shared + let tabsSubscriptionFactory = PersistentTabLocalSubscriptionFactory( + storageFacade: storageFacade, + operationQueue: operationQueue, + logger: logger + ) + + let walletListLocalSubscriptionFactory = WalletListLocalSubscriptionFactory( + storageFacade: storageFacade, + operationManager: OperationManagerFacade.sharedManager, + logger: logger + ) + return DAppBrowserTabManager( fileRepository: renderFilesRepository, - tabsSubscriptionFactory: PersistentTabLocalSubscriptionFactory( - storageFacade: storageFacade, - operationQueue: operationQueue, - logger: logger - ), + tabsSubscriptionFactory: tabsSubscriptionFactory, + walletListLocalSubscriptionFactory: walletListLocalSubscriptionFactory, repository: AnyDataProviderRepository(coreDataRepository), - eventCenter: EventCenter.shared, operationQueue: operationQueue, logger: logger ) diff --git a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager.swift b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager.swift index 287ba4f17..9212317c5 100644 --- a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager.swift +++ b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/DAppBrowserTabManager.swift @@ -5,16 +5,19 @@ typealias DAppBrowserTabsObservable = Observable private let operationQueue: OperationQueue private let observerQueue: DispatchQueue - private let eventCenter: EventCenterProtocol private let logger: LoggerProtocol + private var metaAccount: MetaAccountModel? + private var browserTabProvider: StreamableProvider? + private var selectedWalletProvider: StreamableProvider? private var transportStates: InMemoryCache = .init() private var observableTabs: DAppBrowserTabsObservable = .init(state: .init()) @@ -22,16 +25,16 @@ final class DAppBrowserTabManager { init( fileRepository: WebViewRenderFilesOperationFactoryProtocol, tabsSubscriptionFactory: PersistentTabLocalSubscriptionFactoryProtocol, + walletListLocalSubscriptionFactory: WalletListLocalSubscriptionFactoryProtocol, repository: AnyDataProviderRepository, - eventCenter: EventCenterProtocol, observerQueue: DispatchQueue = .main, operationQueue: OperationQueue, logger: LoggerProtocol ) { self.repository = repository self.tabsSubscriptionFactory = tabsSubscriptionFactory + self.walletListLocalSubscriptionFactory = walletListLocalSubscriptionFactory self.fileRepository = fileRepository - self.eventCenter = eventCenter self.operationQueue = operationQueue self.observerQueue = observerQueue self.logger = logger @@ -44,12 +47,7 @@ final class DAppBrowserTabManager { private extension DAppBrowserTabManager { func setup() { - eventCenter.add( - observer: self, - dispatchIn: .main - ) - - browserTabProvider = subscribeToBrowserTabs(nil) + selectedWalletProvider = subscribeSelectedWalletProvider() } func clearInMemory() { @@ -171,7 +169,10 @@ private extension DAppBrowserTabManager { .map(\.uuid) let rendersClearWrapper = fileRepository.removeRenders(for: tabIds) - let deleteOperation = repository.deleteAllOperation() + let deleteOperation = repository.saveOperation( + { [] }, + { tabIds.map(\.uuidString) } + ) let mappingOperation = ClosureOperation { _ = try rendersClearWrapper.targetOperation.extractNoCancellableResultData() @@ -225,6 +226,7 @@ private extension DAppBrowserTabManager { uuid: persistenceModel.uuid, name: persistenceModel.name, url: persistenceModel.url, + metaId: persistenceModel.metaId, createdAt: persistenceModel.createdAt, renderModifiedAt: persistenceModel.renderModifiedAt, transportStates: transportStates.fetchValue(for: persistenceModel.uuid), @@ -251,6 +253,26 @@ extension DAppBrowserTabManager: DAppBrowserTabLocalSubscriber, DAppBrowserTabLo } } +// MARK: WalletListLocalStorageSubscriber + +extension DAppBrowserTabManager: WalletListLocalStorageSubscriber, WalletListLocalSubscriptionHandler { + func handleSelectedWallet( + result: Result + ) { + switch result { + case let .success(managedMetaAccount): + observableTabs.state = .init() + metaAccount = managedMetaAccount?.info + + guard let metaAccount else { return } + + browserTabProvider = subscribeToBrowserTabs(metaAccount.metaId) + case let .failure(error): + logger.error("Failed on WalletList local subscription with error: \(error.localizedDescription)") + } + } +} + // MARK: DAppBrowserTabManagerProtocol extension DAppBrowserTabManager: DAppBrowserTabManagerProtocol { @@ -265,6 +287,10 @@ extension DAppBrowserTabManager: DAppBrowserTabManagerProtocol { return .createWithResult(sorted(currentTabs)) } + guard let metaAccount else { + return .createWithResult([]) + } + let fetchTabsOperation = repository.fetchAllOperation(with: RepositoryFetchOptions()) let resultOperaton = ClosureOperation { [weak self] in @@ -274,7 +300,9 @@ extension DAppBrowserTabManager: DAppBrowserTabManagerProtocol { let persistedTabs = try fetchTabsOperation.extractNoCancellableResultData() - let tabs = persistedTabs.map { self.map(persistenceModel: $0) } + let tabs = persistedTabs + .filter { $0.metaId == metaAccount.metaId } + .map { self.map(persistenceModel: $0) } return sorted(tabs) } @@ -368,16 +396,3 @@ extension DAppBrowserTabManager: DAppBrowserTabManagerProtocol { } } } - -// MARK: EventVisitorProtocol - -extension DAppBrowserTabManager: EventVisitorProtocol { - func processSelectedWalletChanged(event _: SelectedWalletSwitched) { - transportStates.removeAllValues() - - observableTabs.state - .fetchAllValues() - .map { $0.clearingTransportStates() } - .forEach { observableTabs.state.store(value: $0, for: $0.uuid) } - } -} diff --git a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/DAppBrowserTabLocalSibscriber.swift b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/DAppBrowserTabLocalSibscriber.swift index eaf316ade..ddd9b8c26 100644 --- a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/DAppBrowserTabLocalSibscriber.swift +++ b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/DAppBrowserTabLocalSibscriber.swift @@ -7,15 +7,15 @@ protocol DAppBrowserTabLocalSubscriber: AnyObject { var tabsLocalSubscriptionHandler: DAppBrowserTabLocalSubscriptionHandler { get } func subscribeToBrowserTabs( - _ identifier: UUID? + _ metaId: MetaAccountModel.Id? ) -> StreamableProvider } extension DAppBrowserTabLocalSubscriber { func subscribeToBrowserTabs( - _ identifier: UUID? + _ metaId: MetaAccountModel.Id? ) -> StreamableProvider { - let provider = tabsSubscriptionFactory.getTabsProvider(identifier) + let provider = tabsSubscriptionFactory.getTabsProvider(metaId) let updateClosure = { [weak self] (changes: [DataProviderChange]) in diff --git a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/PersistentTabLocalSubscriptionFactory.swift b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/PersistentTabLocalSubscriptionFactory.swift index 1c0db2bde..43f0fae45 100644 --- a/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/PersistentTabLocalSubscriptionFactory.swift +++ b/novawallet/Modules/DApp/DAppBrowser/Tabs/DAppBrowserTabManager/PersistentTabLocalSubscriptionFactory/PersistentTabLocalSubscriptionFactory.swift @@ -2,7 +2,7 @@ import Foundation import Operation_iOS protocol PersistentTabLocalSubscriptionFactoryProtocol { - func getTabsProvider(_ identifier: UUID?) -> StreamableProvider + func getTabsProvider(_ metaId: MetaAccountModel.Id?) -> StreamableProvider } final class PersistentTabLocalSubscriptionFactory { @@ -10,7 +10,7 @@ final class PersistentTabLocalSubscriptionFactory { let logger: LoggerProtocol? let operationQueue: OperationQueue - private(set) var providerStore: [UUID: WeakWrapper] = [:] + private(set) var providerStore: [MetaAccountModel.Id: WeakWrapper] = [:] init( storageFacade: StorageFacadeProtocol, @@ -30,12 +30,12 @@ final class PersistentTabLocalSubscriptionFactory { // MARK: PersistentTabLocalSubscriptionFactoryProtocol extension PersistentTabLocalSubscriptionFactory: PersistentTabLocalSubscriptionFactoryProtocol { - func getTabsProvider(_ identifier: UUID?) -> Operation_iOS.StreamableProvider { + func getTabsProvider(_ metaId: MetaAccountModel.Id?) -> Operation_iOS.StreamableProvider { runStoreCleaner() if - let identifier, - let provider = providerStore[identifier]?.target as? StreamableProvider + let metaId, + let provider = providerStore[metaId]?.target as? StreamableProvider { return provider } @@ -43,8 +43,8 @@ extension PersistentTabLocalSubscriptionFactory: PersistentTabLocalSubscriptionF let repository: CoreDataRepository let mapper = DAppBrowserTabMapper() - if let identifier { - let filter = NSPredicate.filterFavoriteDApps(by: identifier.uuidString) + if let metaId { + let filter = NSPredicate.filterDAppBrowserTabs(by: metaId) repository = storageFacade.createRepository( filter: filter, sortDescriptors: [], @@ -58,10 +58,10 @@ extension PersistentTabLocalSubscriptionFactory: PersistentTabLocalSubscriptionF service: storageFacade.databaseService, mapper: AnyCoreDataMapper(repository.dataMapper), predicate: { entity in - if let identifier = identifier { - return entity.identifier == identifier.uuidString + if let metaId { + entity.metaId == metaId } else { - return true + true } } ) @@ -81,8 +81,8 @@ extension PersistentTabLocalSubscriptionFactory: PersistentTabLocalSubscriptionF operationManager: OperationManager(operationQueue: operationQueue) ) - if let identifier { - providerStore[identifier] = WeakWrapper(target: provider) + if let metaId { + providerStore[metaId] = WeakWrapper(target: provider) } return provider diff --git a/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesPresenter.swift b/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesPresenter.swift index 05aa3aceb..1d89ce055 100644 --- a/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesPresenter.swift +++ b/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesPresenter.swift @@ -10,6 +10,8 @@ final class DAppFavoritesPresenter { let localizationManager: LocalizationManagerProtocol let logger: LoggerProtocol + let metaId: MetaAccountModel.Id + private var favorites: [String: DAppFavorite] = [:] private var dAppList: DAppList? @@ -17,12 +19,14 @@ final class DAppFavoritesPresenter { interactor: DAppFavoritesInteractorInputProtocol, wireframe: DAppFavoritesWireframeProtocol, viewModelFactory: DAppListViewModelFactoryProtocol, + metaId: MetaAccountModel.Id, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe self.viewModelFactory = viewModelFactory + self.metaId = metaId self.localizationManager = localizationManager self.logger = logger } @@ -73,9 +77,9 @@ extension DAppFavoritesPresenter: DAppFavoritesPresenterProtocol { guard let dAppList else { return } let tab: DAppBrowserTab? = if let dApp = dAppList.dApps.first(where: { $0.identifier == id }) { - DAppBrowserTab(from: dApp) + DAppBrowserTab(from: dApp, metaId: metaId) } else { - DAppBrowserTab(from: id) + DAppBrowserTab(from: id, metaId: metaId) } guard let tab else { return } diff --git a/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesViewFactory.swift b/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesViewFactory.swift index 0caebff50..691682d86 100644 --- a/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesViewFactory.swift +++ b/novawallet/Modules/DApp/DAppFavorites/DAppFavoritesViewFactory.swift @@ -33,10 +33,13 @@ struct DAppFavoritesViewFactory { dappCategoriesViewModelFactory: categoriesViewModelFactory ) + let wallet: MetaAccountModel = SelectedWalletSettings.shared.value + let presenter = DAppFavoritesPresenter( interactor: interactor, wireframe: wireframe, viewModelFactory: viewModelFactory, + metaId: wallet.metaId, localizationManager: localizationManager, logger: logger ) diff --git a/novawallet/Modules/DApp/DAppList/DAppListPresenter.swift b/novawallet/Modules/DApp/DAppList/DAppListPresenter.swift index 08b612dc2..7ff346306 100644 --- a/novawallet/Modules/DApp/DAppList/DAppListPresenter.swift +++ b/novawallet/Modules/DApp/DAppList/DAppListPresenter.swift @@ -85,12 +85,15 @@ extension DAppListPresenter: DAppListPresenterProtocol { } func selectDApp(with id: String) { - guard case let .success(dAppList) = dAppsResult else { return } + guard + let wallet, + case let .success(dAppList) = dAppsResult + else { return } let tab: DAppBrowserTab? = if let dApp = dAppList.dApps.first(where: { $0.identifier == id }) { - DAppBrowserTab(from: dApp) + DAppBrowserTab(from: dApp, metaId: wallet.metaId) } else if let dApp = favorites?[id] { - DAppBrowserTab(from: dApp.identifier) + DAppBrowserTab(from: dApp.identifier, metaId: wallet.metaId) } else { nil } @@ -157,7 +160,9 @@ extension DAppListPresenter: DAppListInteractorOutputProtocol { extension DAppListPresenter: DAppSearchDelegate { func didCompleteDAppSearchResult(_ result: DAppSearchResult) { - guard let tab = DAppBrowserTab(from: result) else { + guard let wallet else { return } + + guard let tab = DAppBrowserTab(from: result, metaId: wallet.metaId) else { return } diff --git a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsPresenter.swift b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsPresenter.swift index db1ecdb9d..a101a4b3e 100644 --- a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsPresenter.swift +++ b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsPresenter.swift @@ -8,6 +8,8 @@ final class StakingMoreOptionsPresenter { let interactor: StakingMoreOptionsInteractorInputProtocol let logger: LoggerProtocol + let metaId: MetaAccountModel.Id + private var moreOptions: [StakingDashboardItemModel] = [] private var dApps: [DApp] = [] @@ -15,12 +17,14 @@ final class StakingMoreOptionsPresenter { interactor: StakingMoreOptionsInteractorInputProtocol, viewModelFactory: StakingMoreOptionsViewModelFactoryProtocol, wireframe: StakingMoreOptionsWireframeProtocol, + metaId: MetaAccountModel.Id, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { self.interactor = interactor self.viewModelFactory = viewModelFactory self.wireframe = wireframe + self.metaId = metaId self.logger = logger self.localizationManager = localizationManager } @@ -69,7 +73,9 @@ extension StakingMoreOptionsPresenter: StakingMoreOptionsPresenterProtocol { guard let dApp = dApps[safe: index] else { return } - wireframe.showBrowser(from: view, for: dApp) + + let tab = DAppBrowserTab(from: dApp, metaId: metaId) + wireframe.showBrowser(from: view, with: tab) } } diff --git a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsProtocols.swift b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsProtocols.swift index d9a490c47..c76331a5d 100644 --- a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsProtocols.swift +++ b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsProtocols.swift @@ -20,7 +20,10 @@ protocol StakingMoreOptionsInteractorOutputProtocol: AnyObject { } protocol StakingMoreOptionsWireframeProtocol: ErrorPresentable, AlertPresentable, CommonRetryable { - func showBrowser(from view: ControllerBackedProtocol?, for dApp: DApp) + func showBrowser( + from view: ControllerBackedProtocol?, + with tab: DAppBrowserTab + ) func showStartStaking( from view: StakingMoreOptionsViewProtocol?, diff --git a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsViewFactory.swift b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsViewFactory.swift index b6af4480b..910ee1188 100644 --- a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsViewFactory.swift +++ b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsViewFactory.swift @@ -2,7 +2,9 @@ import Foundation import SoraFoundation struct StakingMoreOptionsViewFactory { - static func createView(stateObserver: Observable) -> StakingMoreOptionsViewProtocol? { + static func createView( + stateObserver: Observable + ) -> StakingMoreOptionsViewProtocol? { guard let currencyManager = CurrencyManager.shared else { return nil } @@ -25,10 +27,13 @@ struct StakingMoreOptionsViewFactory { estimatedEarningsFormatter: NumberFormatter.percentBase.localizableResource() ) + let wallet: MetaAccountModel = SelectedWalletSettings.shared.value + let presenter = StakingMoreOptionsPresenter( interactor: interactor, viewModelFactory: viewModelFactory, wireframe: wireframe, + metaId: wallet.metaId, localizationManager: LocalizationManager.shared, logger: Logger.shared ) diff --git a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsWireframe.swift b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsWireframe.swift index cbec82399..1fdddf572 100644 --- a/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsWireframe.swift +++ b/novawallet/Modules/Staking/StakingMoreOptions/StakingMoreOptionsWireframe.swift @@ -1,9 +1,10 @@ import Foundation final class StakingMoreOptionsWireframe: StakingMoreOptionsWireframeProtocol { - func showBrowser(from view: ControllerBackedProtocol?, for dApp: DApp) { - let tab = DAppBrowserTab(from: dApp) - + func showBrowser( + from view: ControllerBackedProtocol?, + with tab: DAppBrowserTab + ) { guard let browserView = DAppBrowserViewFactory.createView(selectedTab: tab) else { return } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 2a475ed74..069157b98 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -495,7 +495,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { guard let dApp = dApps?[index], let url = try? dApp.extractFullUrl(for: referendum.index, governanceType: governanceType), - let tab = DAppBrowserTab(from: url.absoluteString) + let tab = DAppBrowserTab(from: url.absoluteString, metaId: wallet.metaId) else { return }