diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index ba01875acf..580686d592 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -23,7 +23,6 @@ import com.tangem.datasource.local.config.environment.EnvironmentConfig import com.tangem.datasource.local.config.issuers.IssuersConfigStorage import com.tangem.datasource.local.logs.AppLogsStore import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.token.UserTokensResponseStore import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.apptheme.GetAppThemeModeUseCase import com.tangem.domain.apptheme.repository.AppThemeModeRepository @@ -138,8 +137,6 @@ interface ApplicationEntryPoint { fun getApiConfigsManager(): ApiConfigsManager - fun getUserTokensResponseStore(): UserTokensResponseStore - fun getUserWalletsListRepository(): UserWalletsListRepository fun getTangemHotSdk(): TangemHotSdk diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index 8cf20b1b8a..8977b105fc 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -39,7 +39,6 @@ import com.tangem.datasource.local.config.environment.EnvironmentConfig import com.tangem.datasource.local.config.issuers.IssuersConfigStorage import com.tangem.datasource.local.logs.AppLogsStore import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.token.UserTokensResponseStore import com.tangem.datasource.utils.NetworkLogsSaveInterceptor import com.tangem.datasource.utils.WireMockRedirectInterceptor import com.tangem.domain.appcurrency.repository.AppCurrencyRepository @@ -218,9 +217,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration. private val apiConfigsManager: ApiConfigsManager get() = entryPoint.getApiConfigsManager() - private val userTokensResponseStore: UserTokensResponseStore - get() = entryPoint.getUserTokensResponseStore() - private val userWalletsListRepository get() = entryPoint.getUserWalletsListRepository() @@ -381,7 +377,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration. settingsManager = settingsManager, uiMessageSender = uiMessageSender, coldUserWalletBuilderFactory = coldUserWalletBuilderFactory, - userTokensResponseStore = userTokensResponseStore, userWalletsListRepository = userWalletsListRepository, tangemHotSdk = tangemHotSdk, trackingContextProxy = trackingContextProxy, diff --git a/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt index 4cbe877c01..1c40e0e8c3 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt @@ -8,7 +8,6 @@ import com.tangem.domain.nft.utils.NFTCleaner import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier -import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module @@ -63,9 +62,7 @@ internal object NFTDomainModule { fun providesGetNFTAvailableNetworksUseCase( nftRepository: NFTRepository, singleAccountListSupplier: SingleAccountListSupplier, - currenciesRepository: CurrenciesRepository, ): GetNFTNetworksUseCase = GetNFTNetworksUseCase( - currenciesRepository = currenciesRepository, nftRepository = nftRepository, singleAccountListSupplier = singleAccountListSupplier, ) diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index d86379f650..861d425898 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -13,7 +13,6 @@ import com.tangem.data.card.TransactionSignerFactory import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.datasource.local.config.issuers.IssuersConfigStorage import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.token.UserTokensResponseStore import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.apptheme.repository.AppThemeModeRepository import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository @@ -71,7 +70,6 @@ data class DaggerGraphState( val uiMessageSender: UiMessageSender? = null, val cardArworksProvider: CardArtworksProvider? = null, val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory? = null, - val userTokensResponseStore: UserTokensResponseStore? = null, val userWalletsListRepository: UserWalletsListRepository? = null, val tangemHotSdk: TangemHotSdk? = null, val trackingContextProxy: TrackingContextProxy? = null, diff --git a/data/account/src/main/kotlin/com/tangem/data/account/producer/DefaultMultiWalletCryptoCurrenciesProducer.kt b/data/account/src/main/kotlin/com/tangem/data/account/producer/DefaultMultiWalletCryptoCurrenciesProducer.kt deleted file mode 100644 index 16fa1c9e44..0000000000 --- a/data/account/src/main/kotlin/com/tangem/data/account/producer/DefaultMultiWalletCryptoCurrenciesProducer.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.tangem.data.account.producer - -import arrow.core.Option -import arrow.core.some -import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory -import com.tangem.datasource.local.token.UserTokensResponseStore -import com.tangem.domain.common.wallets.UserWalletsListRepository -import com.tangem.domain.common.wallets.getSyncStrict -import com.tangem.domain.core.flow.FlowProducerTools -import com.tangem.domain.models.account.DerivationIndex -import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.wallet.isMultiCurrency -import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject -import kotlinx.coroutines.flow.* - -/** - * Default implementation of [MultiWalletCryptoCurrenciesProducer] - * - * @property params params - * @property flowProducerTools tools for producing flows - * @property userWalletsListRepository repository for getting user wallets - * @property userTokensResponseStore store of `UserTokensResponse` - * @property responseCryptoCurrenciesFactory factory for creating [CryptoCurrency] from `UserTokensResponse` - * @property dispatchers dispatchers - * -[REDACTED_AUTHOR] - */ -internal class DefaultMultiWalletCryptoCurrenciesProducer @AssistedInject constructor( - @Assisted val params: MultiWalletCryptoCurrenciesProducer.Params, - override val flowProducerTools: FlowProducerTools, - private val userWalletsListRepository: UserWalletsListRepository, - private val userTokensResponseStore: UserTokensResponseStore, - private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory, - private val dispatchers: CoroutineDispatcherProvider, -) : MultiWalletCryptoCurrenciesProducer { - - override val fallback: Option> = emptySet().some() - - override fun produce(): Flow> { - val userWallet = userWalletsListRepository.getSyncStrict(id = params.userWalletId) - - if (!userWallet.isMultiCurrency) { - error("${this::class.simpleName ?: this::class.toString()} supports only multi-currency wallet") - } - - return userTokensResponseStore.get(userWalletId = params.userWalletId) - .distinctUntilChanged() - .map { response -> - if (response == null) return@map emptySet() - - responseCryptoCurrenciesFactory.createCurrencies( - response = response, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ).toSet() - } - .onEmpty { emit(emptySet()) } - .flowOn(dispatchers.default) - } - - @AssistedFactory - interface Factory : MultiWalletCryptoCurrenciesProducer.Factory { - override fun create( - params: MultiWalletCryptoCurrenciesProducer.Params, - ): DefaultMultiWalletCryptoCurrenciesProducer - } -} \ No newline at end of file diff --git a/data/account/src/test/java/com/tangem/data/account/producer/DefaultMultiWalletCryptoCurrenciesProducerTest.kt b/data/account/src/test/java/com/tangem/data/account/producer/DefaultMultiWalletCryptoCurrenciesProducerTest.kt deleted file mode 100644 index d1df425b53..0000000000 --- a/data/account/src/test/java/com/tangem/data/account/producer/DefaultMultiWalletCryptoCurrenciesProducerTest.kt +++ /dev/null @@ -1,378 +0,0 @@ -package com.tangem.data.account.producer - -import com.google.common.truth.Truth -import com.tangem.blockchain.common.Blockchain -import com.tangem.common.test.domain.card.MockScanResponseFactory -import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory -import com.tangem.common.test.domain.wallet.MockUserWalletFactory -import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory -import com.tangem.datasource.api.tangemTech.models.UserTokensResponse -import com.tangem.datasource.local.token.UserTokensResponseStore -import com.tangem.domain.card.configs.GenericCardConfig -import com.tangem.domain.common.wallets.UserWalletsListRepository -import com.tangem.domain.core.flow.FlowProducerTools -import com.tangem.domain.models.account.DerivationIndex -import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.wallet.UserWallet -import com.tangem.domain.models.wallet.isMultiCurrency -import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer -import com.tangem.test.core.getEmittedValues -import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider -import io.mockk.* -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -/** -[REDACTED_AUTHOR] - */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal class DefaultMultiWalletCryptoCurrenciesProducerTest { - - private val cryptoCurrencyFactory = MockCryptoCurrencyFactory() - - private val params = MultiWalletCryptoCurrenciesProducer.Params(userWalletId = userWallet.walletId) - private val userWalletsListRepository: UserWalletsListRepository = mockk(relaxUnitFun = true) - private val userTokensResponseStore: UserTokensResponseStore = mockk(relaxUnitFun = true) - private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory = mockk() - private val flowProducerTools: FlowProducerTools = mockk() - - private val producer = DefaultMultiWalletCryptoCurrenciesProducer( - params = params, - flowProducerTools = flowProducerTools, - userWalletsListRepository = userWalletsListRepository, - userTokensResponseStore = userTokensResponseStore, - responseCryptoCurrenciesFactory = responseCryptoCurrenciesFactory, - dispatchers = TestingCoroutineDispatcherProvider(), - ) - - @BeforeEach - fun resetMocks() { - clearMocks(userWalletsListRepository, userTokensResponseStore, responseCryptoCurrenciesFactory) - } - - @Test - fun `flow is mapped for user wallet id from params`() = runTest { - // Arrange - val userTokensResponseFlow = flowOf(null) - - val userWalletsFlow = MutableStateFlow(listOf(userWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow - - // Act - val actual = producer.produce().let(::getEmittedValues) - - // Assert - val expected = emptySet() - - Truth.assertThat(actual.size).isEqualTo(1) - Truth.assertThat(actual.first()).isEqualTo(expected) - - verifyOrder { - userWalletsListRepository.userWallets - userTokensResponseStore.get(params.userWalletId) - } - - verify(inverse = true) { - responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any(), accountIndex = any()) - } - } - - @Test - fun `flow will updated if UserTokensResponse is updated`() = runTest { - // Arrange - val userTokensResponseFlow = MutableSharedFlow(replay = 2) - - val userTokensResponse = UserTokensResponse( - group = UserTokensResponse.GroupType.TOKEN, - sort = UserTokensResponse.SortType.MARKETCAP, - tokens = emptyList(), - ) - val cryptoCurrencies = emptySet() - - val updatedUserTokensResponse = UserTokensResponse( - group = UserTokensResponse.GroupType.TOKEN, - sort = UserTokensResponse.SortType.MARKETCAP, - tokens = listOf( - UserTokensResponse.Token( - id = null, - networkId = "bitcoin", - derivationPath = null, - name = "Bitcoin", - symbol = "BTC", - decimals = 8, - contractAddress = null, - addresses = listOf(), - ), - ), - ) - val updatedCryptoCurrencies = setOf( - cryptoCurrencyFactory.createCoin(Blockchain.Bitcoin), - ) - - val userWalletsFlow = MutableStateFlow(listOf(userWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow - - every { - responseCryptoCurrenciesFactory.createCurrencies( - response = userTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } returns cryptoCurrencies.toList() - - every { - responseCryptoCurrenciesFactory.createCurrencies( - response = updatedUserTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } returns updatedCryptoCurrencies.toList() - - val producerFlow = producer.produce() - - // Act 1 (first emit) - userTokensResponseFlow.emit(userTokensResponse) - - val actual1 = getEmittedValues(flow = producerFlow) - - // Assert - val expected1 = cryptoCurrencies - - Truth.assertThat(actual1.size).isEqualTo(1) - Truth.assertThat(actual1.first()).isEqualTo(expected1) - - verifyOrder { - userWalletsListRepository.userWallets - userTokensResponseStore.get(params.userWalletId) - responseCryptoCurrenciesFactory.createCurrencies( - response = userTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } - - // Act 2 (second emit) - userTokensResponseFlow.emit(updatedUserTokensResponse) - - val actual2 = getEmittedValues(flow = producerFlow) - - // Assert - val expected2 = listOf(cryptoCurrencies, updatedCryptoCurrencies) - - Truth.assertThat(actual2.size).isEqualTo(2) - Truth.assertThat(actual2).isEqualTo(expected2) - - verifyOrder { - responseCryptoCurrenciesFactory.createCurrencies( - response = updatedUserTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } - } - - @Test - fun `flow is filtered the same status`() = runTest { - // Arrange - val userTokensResponseFlow = MutableSharedFlow(replay = 2) - - val userTokensResponse = UserTokensResponse( - group = UserTokensResponse.GroupType.TOKEN, - sort = UserTokensResponse.SortType.MARKETCAP, - tokens = emptyList(), - ) - - val cryptoCurrencies = emptySet() - - val userWalletsFlow = MutableStateFlow(listOf(userWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow - - every { - responseCryptoCurrenciesFactory.createCurrencies( - response = userTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } returns cryptoCurrencies.toList() - - val producerFlow = producer.produce() - - // Act 1 (first emit) - userTokensResponseFlow.emit(userTokensResponse) - - val actual1 = getEmittedValues(flow = producerFlow) - - // Assert - val expected1 = cryptoCurrencies - - Truth.assertThat(actual1.size).isEqualTo(1) - Truth.assertThat(actual1.first()).isEqualTo(expected1) - - verifyOrder { - userWalletsListRepository.userWallets - userTokensResponseStore.get(params.userWalletId) - responseCryptoCurrenciesFactory.createCurrencies( - response = userTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } - - // Act 2 (second emit) - userTokensResponseFlow.emit(userTokensResponse) - - val actual2 = getEmittedValues(flow = producerFlow) - - // Assert - val expected2 = expected1 - Truth.assertThat(actual2.size).isEqualTo(1) - Truth.assertThat(actual2.first()).isEqualTo(expected2) - } - - @Disabled - @Test - fun `flow throws exception`() = runTest { - // Arrange - val exception = IllegalStateException() - - val userTokensResponse = UserTokensResponse( - group = UserTokensResponse.GroupType.TOKEN, - sort = UserTokensResponse.SortType.MARKETCAP, - tokens = emptyList(), - ) - - val cryptoCurrencies = emptySet() - - val innerFlow = MutableStateFlow(value = false) - val userTokensResponseFlow = flow { - if (innerFlow.value) { - emit(userTokensResponse) - } else { - throw exception - } - } - .buffer(capacity = 5) - - val userWalletsFlow = MutableStateFlow(listOf(userWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow - - every { - responseCryptoCurrenciesFactory.createCurrencies( - response = userTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } returns cryptoCurrencies.toList() - - val producerFlow = producer.produceWithFallback() - - // Act 1 (fallback) - val actual1 = getEmittedValues(flow = producerFlow) - - // Assert - val expected1 = producer.fallback.getOrNull() - Truth.assertThat(actual1.size).isEqualTo(1) - Truth.assertThat(actual1.first()).isEqualTo(expected1) - - verifyOrder { - userWalletsListRepository.userWallets - userTokensResponseStore.get(params.userWalletId) - } - - // Act 2 (emit) - innerFlow.emit(value = true) - val actual2 = getEmittedValues(flow = producerFlow) - - // Assert - val expected2 = cryptoCurrencies - Truth.assertThat(actual2.size).isEqualTo(1) - Truth.assertThat(actual2.first()).isEqualTo(expected2) - - verifyOrder { - responseCryptoCurrenciesFactory.createCurrencies( - response = userTokensResponse, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } - } - - @Test - fun `flow is empty if store returns empty flow`() = runTest { - // Arrange - val userWalletsFlow = MutableStateFlow(listOf(userWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - every { userTokensResponseStore.get(params.userWalletId) } returns emptyFlow() - - // Act - val actual = producer.produce().let(::getEmittedValues) - - // Assert - val expected = producer.fallback.getOrNull() - Truth.assertThat(actual.size).isEqualTo(1) - Truth.assertThat(actual.first()).isEqualTo(expected) - - verifyOrder { - userWalletsListRepository.userWallets - userTokensResponseStore.get(params.userWalletId) - } - - verify(inverse = true) { - responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any(), accountIndex = any()) - } - } - - @Test - fun `produce throws exception if UserWallet isn't multi-currency wallet`() = runTest { - // Arrange - val mockUserWallet = mockk { - every { walletId } returns userWallet.walletId - every { isMultiCurrency } returns false - } - - val userWalletsFlow = MutableStateFlow(listOf(mockUserWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - - // Act - val actual = runCatching { producer.produce() }.exceptionOrNull() - - // Assert - val expected = IllegalStateException( - "${DefaultMultiWalletCryptoCurrenciesProducer::class.simpleName} supports only multi-currency wallet", - ) - - Truth.assertThat(actual).isInstanceOf(expected::class.java) - Truth.assertThat(actual).hasMessageThat().isEqualTo(expected.message) - - verifyOrder { userWalletsListRepository.userWallets } - - verify(inverse = true) { - userTokensResponseStore.get(any()) - responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any(), accountIndex = any()) - } - } - - private companion object { - - val scanResponse = MockScanResponseFactory.create( - cardConfig = GenericCardConfig(2), - derivedKeys = emptyMap(), - ) - - val userWallet = MockUserWalletFactory.create(scanResponse = scanResponse) - } -} \ No newline at end of file diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensSaver.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensSaver.kt index a1ab6f180b..5796a28601 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensSaver.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/UserTokensSaver.kt @@ -1,14 +1,12 @@ package com.tangem.data.common.currency import com.tangem.data.common.api.safeApiCall -import com.tangem.data.common.tokens.UserTokensBackwardCompatibility import com.tangem.data.common.wallet.WalletServerBinder import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.common.response.ApiResponseError import com.tangem.datasource.api.common.response.isNetworkError import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.models.UserTokensResponse -import com.tangem.datasource.local.token.UserTokensResponseStore import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.getSyncOrNull import com.tangem.domain.models.wallet.UserWallet @@ -23,31 +21,11 @@ import timber.log.Timber class UserTokensSaver( private val tangemTechApi: TangemTechApi, private val userWalletsListRepository: UserWalletsListRepository, - private val userTokensResponseStore: UserTokensResponseStore, private val dispatchers: CoroutineDispatcherProvider, private val addressesEnricher: UserTokensResponseAddressesEnricher, private val walletServerBinder: WalletServerBinder, private val pushTokensRetryerPool: RetryerPool, ) { - private val userTokensBackwardCompatibility = UserTokensBackwardCompatibility() - - suspend fun storeAndPush(userWalletId: UserWalletId, response: UserTokensResponse) { - withContext(dispatchers.default) { - val enrichedResponse = response.enrichIf(userWalletId = userWalletId, condition = true) - - store(userWalletId = userWalletId, response = enrichedResponse, useEnricher = false) - push(userWalletId = userWalletId, response = enrichedResponse, useEnricher = false) - } - } - - suspend fun store(userWalletId: UserWalletId, response: UserTokensResponse, useEnricher: Boolean = true) = - withContext(dispatchers.default) { - val updatedResponse = response - .applyCompatibility() - .enrichIf(userWalletId = userWalletId, condition = useEnricher) - - userTokensResponseStore.store(userWalletId = userWalletId, response = updatedResponse) - } suspend fun push( userWalletId: UserWalletId, @@ -111,10 +89,6 @@ class UserTokensSaver( ) } - private fun UserTokensResponse.applyCompatibility(): UserTokensResponse { - return userTokensBackwardCompatibility.applyCompatibilityAndGetUpdated(userTokensResponse = this) - } - private suspend fun UserTokensResponse.enrichIf( userWalletId: UserWalletId, condition: Boolean, diff --git a/data/common/src/main/kotlin/com/tangem/data/common/di/DataCommonModule.kt b/data/common/src/main/kotlin/com/tangem/data/common/di/DataCommonModule.kt index 2d0f7de535..d30a846e5f 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/di/DataCommonModule.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/di/DataCommonModule.kt @@ -12,7 +12,6 @@ import com.tangem.data.common.wallet.WalletServerBinder import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.token.UserTokensResponseStore import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.demo.models.DemoConfig import com.tangem.domain.walletmanager.WalletManagersFacade @@ -67,7 +66,6 @@ internal object DataCommonModule { fun provideUserTokensSaver( tangemTechApi: TangemTechApi, userWalletsListRepository: UserWalletsListRepository, - userTokensResponseStore: UserTokensResponseStore, dispatchers: CoroutineDispatcherProvider, addressesEnricher: UserTokensResponseAddressesEnricher, walletServerBinder: WalletServerBinder, @@ -75,7 +73,6 @@ internal object DataCommonModule { return UserTokensSaver( tangemTechApi = tangemTechApi, userWalletsListRepository = userWalletsListRepository, - userTokensResponseStore = userTokensResponseStore, dispatchers = dispatchers, addressesEnricher = addressesEnricher, pushTokensRetryerPool = RetryerPool( diff --git a/data/common/src/test/kotlin/com/tangem/data/common/currency/UserTokensSaverTest.kt b/data/common/src/test/kotlin/com/tangem/data/common/currency/UserTokensSaverTest.kt index 4cc3f5aa9f..2a6546928a 100644 --- a/data/common/src/test/kotlin/com/tangem/data/common/currency/UserTokensSaverTest.kt +++ b/data/common/src/test/kotlin/com/tangem/data/common/currency/UserTokensSaverTest.kt @@ -6,7 +6,6 @@ import com.tangem.datasource.api.common.response.ApiResponseError import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.datasource.api.tangemTech.models.WalletType -import com.tangem.datasource.local.token.UserTokensResponseStore import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId @@ -23,14 +22,12 @@ class UserTokensSaverTest { private val tangemTechApi: TangemTechApi = mockk() private val userWalletsListRepository: UserWalletsListRepository = mockk(relaxUnitFun = true) - private val userTokensResponseStore: UserTokensResponseStore = mockk(relaxed = true) private val enricher: UserTokensResponseAddressesEnricher = mockk() private val walletServerBinder: WalletServerBinder = mockk() private val userTokensSaver: UserTokensSaver = UserTokensSaver( tangemTechApi = tangemTechApi, userWalletsListRepository = userWalletsListRepository, - userTokensResponseStore = userTokensResponseStore, dispatchers = TestingCoroutineDispatcherProvider(), addressesEnricher = enricher, walletServerBinder = walletServerBinder, @@ -42,46 +39,11 @@ class UserTokensSaverTest { clearMocks( tangemTechApi, userWalletsListRepository, - userTokensResponseStore, enricher, walletServerBinder, ) } - @Test - fun `GIVEN user wallet id and response WHEN store THEN should store enriched response`() = runTest { - // GIVEN - val userWalletId = UserWalletId("1234567890abcdef") - val response = UserTokensResponse( - version = 0, - group = UserTokensResponse.GroupType.NETWORK, - sort = UserTokensResponse.SortType.BALANCE, - tokens = emptyList(), - ) - - val enrichedResponse = UserTokensResponse( - version = 0, - group = UserTokensResponse.GroupType.NETWORK, - sort = UserTokensResponse.SortType.MANUAL, - tokens = emptyList(), - ) - - coEvery { enricher(userWalletId, response) } returns enrichedResponse - - // WHEN - userTokensSaver.store(userWalletId, response) - - // THEN - coVerifyOrder { - enricher(userWalletId, response) - userTokensResponseStore.store(userWalletId, enrichedResponse) - } - - coVerify(inverse = true) { - tangemTechApi.saveTokens(any(), any()) - } - } - @Test fun `GIVEN user wallet id and response WHEN push AND api call fails THEN should log error and call onFailSend`() = runTest { @@ -133,49 +95,4 @@ class UserTokensSaverTest { assert(onFailSendCalled) { "onFailSend callback should be called when API call fails" } } - - @Test - fun `GIVEN user wallet id and response WHEN storeAndPush THEN should store and push enriched response`() = runTest { - // GIVEN - val userWalletId = UserWalletId("1234567890abcdef") - val userWallet = mockk { - every { this@mockk.walletId } returns userWalletId - every { this@mockk.name } returns "Wallet" - } - - val response = UserTokensResponse( - version = 0, - group = UserTokensResponse.GroupType.NETWORK, - sort = UserTokensResponse.SortType.BALANCE, - tokens = emptyList(), - walletName = userWallet.name, - walletType = WalletType.COLD, - ) - val enrichedResponse = UserTokensResponse( - version = 0, - group = UserTokensResponse.GroupType.NETWORK, - sort = UserTokensResponse.SortType.BALANCE, - tokens = emptyList(), - walletName = userWallet.name, - walletType = WalletType.COLD, - ) - - val userWalletsFlow = MutableStateFlow(listOf(userWallet)) - - every { userWalletsListRepository.userWallets } returns userWalletsFlow - coEvery { enricher(userWalletId, response) } returns enrichedResponse - coEvery { - tangemTechApi.saveTokens(userWalletId.stringValue, enrichedResponse) - } returns ApiResponse.Success(Unit) - - // WHEN - userTokensSaver.storeAndPush(userWalletId, response) - - // THEN - coVerifyOrder { - enricher(userWalletId, response) - userWalletsListRepository.userWallets - tangemTechApi.saveTokens(userWalletId.stringValue, enrichedResponse) - } - } } \ No newline at end of file diff --git a/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTNetworksUseCase.kt b/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTNetworksUseCase.kt index 3332f38965..cc4485938a 100644 --- a/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTNetworksUseCase.kt +++ b/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTNetworksUseCase.kt @@ -1,40 +1,30 @@ package com.tangem.domain.nft import com.tangem.domain.account.supplier.SingleAccountListSupplier -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.account.Account +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.nft.models.NFTNetworks import com.tangem.domain.nft.repository.NFTRepository -import com.tangem.domain.tokens.repository.CurrenciesRepository import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapNotNull class GetNFTNetworksUseCase( - private val currenciesRepository: CurrenciesRepository, private val singleAccountListSupplier: SingleAccountListSupplier, private val nftRepository: NFTRepository, ) { @OptIn(ExperimentalCoroutinesApi::class) - operator fun invoke(portfolioId: PortfolioId): Flow = when (portfolioId) { - is PortfolioId.Account -> { - singleAccountListSupplier(portfolioId.userWalletId) - .mapNotNull { accountList -> - val account = accountList.accounts.find { it.accountId == portfolioId.accountId } + operator fun invoke(accountId: AccountId): Flow { + return singleAccountListSupplier(accountId.userWalletId) + .mapNotNull { accountList -> + val account = accountList.accounts.find { it.accountId == accountId } - (account as? Account.CryptoPortfolio)?.cryptoCurrencies?.toList() - } - .mapLatest { it.toNFTNetworks(portfolioId.userWalletId) } - } - is PortfolioId.Wallet -> { - currenciesRepository - .getWalletCurrenciesUpdates(portfolioId.userWalletId) - .map { cryptoCurrencies -> cryptoCurrencies.toNFTNetworks(portfolioId.userWalletId) } - } + (account as? Account.CryptoPortfolio)?.cryptoCurrencies?.toList() + } + .mapLatest { it.toNFTNetworks(accountId.userWalletId) } } private suspend fun List.toNFTNetworks(userWalletId: UserWalletId): NFTNetworks { diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt index 0cbb637c1c..25d54e0d9f 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt @@ -20,7 +20,6 @@ import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.navigation.inner.InnerRouter import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.domain.models.PortfolioId import com.tangem.features.account.PortfolioFetcher import com.tangem.features.account.PortfolioSelectorComponent import com.tangem.features.account.PortfolioSelectorController @@ -160,13 +159,13 @@ internal class DefaultNFTComponent @AssistedInject constructor( if (portfolioData.isSingleChoice) { val mainAccountId = portfolioData.balances.values.first() .accountsBalance.mainAccount.account.accountId - innerRouter.push(NFTRoute.Receive(portfolioId = PortfolioId(mainAccountId))) + innerRouter.push(NFTRoute.Receive(accountId = mainAccountId)) } else { bottomSheetNavigation.activate(Unit) val selectedAccountId = portfolioSelectorController.selectedAccount .filterNotNull().first() bottomSheetNavigation.dismiss() - innerRouter.push(NFTRoute.Receive(portfolioId = PortfolioId(selectedAccountId))) + innerRouter.push(NFTRoute.Receive(accountId = selectedAccountId)) } }.saveIn(onReceiveClickJob) @@ -176,7 +175,7 @@ internal class DefaultNFTComponent @AssistedInject constructor( ): ComposableContentComponent = NFTReceiveComponent( context = factoryContext, params = NFTReceiveComponent.Params( - portfolioId = route.portfolioId, + accountId = route.accountId, onBackClick = ::onChildBack, ), tokenReceiveComponentFactory = tokenReceiveComponentFactory, diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt index aa810f1b81..9333c371f4 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt @@ -1,10 +1,10 @@ package com.tangem.features.nft.common import com.tangem.core.decompose.navigation.Route -import com.tangem.domain.models.PortfolioId +import com.tangem.domain.models.account.AccountId +import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.nft.models.NFTAsset import com.tangem.domain.nft.models.NFTCollection -import com.tangem.domain.models.wallet.UserWalletId import kotlinx.serialization.Serializable internal sealed class NFTRoute : Route { @@ -15,9 +15,7 @@ internal sealed class NFTRoute : Route { ) : NFTRoute() @Serializable - data class Receive( - val portfolioId: PortfolioId, - ) : NFTRoute() + data class Receive(val accountId: AccountId) : NFTRoute() @Serializable data class Details( diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt index 560eee70b5..d4f36ccb62 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt @@ -13,8 +13,8 @@ import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.TokenReceiveConfig +import com.tangem.domain.models.account.AccountId import com.tangem.features.nft.receive.model.NFTReceiveModel import com.tangem.features.nft.receive.ui.NFTReceive import com.tangem.features.tokenreceive.TokenReceiveComponent @@ -57,7 +57,7 @@ internal class NFTReceiveComponent @AssistedInject constructor( ) data class Params( - val portfolioId: PortfolioId, + val accountId: AccountId, val onBackClick: () -> Unit, ) } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt index 6a32daa0a5..f96d50af08 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt @@ -18,7 +18,6 @@ import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.account.producer.SingleAccountProducer import com.tangem.domain.account.supplier.SingleAccountSupplier import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.TokenReceiveConfig import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.network.Network @@ -88,14 +87,12 @@ internal class NFTReceiveModel @Inject constructor( } private fun loadPortfolioName() = modelScope.launch(dispatchers.default) { - val appBarSubtitle = when (val portfolioId = params.portfolioId) { - is PortfolioId.Wallet -> loadWalletName(portfolioId.userWalletId) - is PortfolioId.Account -> if (isAccountsModeEnabledUseCase.invokeSync()) { - loadAccountName(portfolioId.accountId) - } else { - loadWalletName(portfolioId.userWalletId) - } + val appBarSubtitle = if (isAccountsModeEnabledUseCase.invokeSync()) { + loadAccountName(params.accountId) + } else { + loadWalletName(params.accountId.userWalletId) } + _state.update { it.copy(appBarSubtitle = appBarSubtitle) } } @@ -121,7 +118,7 @@ internal class NFTReceiveModel @Inject constructor( private fun subscribeToNFTAvailableNetworks() { combine( - flow = getNFTNetworksUseCase(params.portfolioId), + flow = getNFTNetworksUseCase(params.accountId), flow2 = searchManager.query.distinctUntilChanged(), ) { networks, query -> filterNFTAvailableNetworksUseCase(networks, query) @@ -173,7 +170,7 @@ internal class NFTReceiveModel @Inject constructor( analyticsEventHandler.send(NFTAnalyticsEvent.Receive.BlockchainChosen(network.name)) val networkStatus = getNFTNetworkStatusUseCase.invoke( - userWalletId = params.portfolioId.userWalletId, + userWalletId = params.accountId.userWalletId, network = network, ) ?: return@launch @@ -198,7 +195,7 @@ internal class NFTReceiveModel @Inject constructor( private suspend fun configureReceiveAddresses(addresses: NetworkAddress, network: Network): TokenReceiveConfig { val cryptoCurrency = getNFTCurrencyUseCase.invoke(network) return receiveAddressesFactory.createForNft( - userWalletId = params.portfolioId.userWalletId, + userWalletId = params.accountId.userWalletId, addresses = addresses, network = network, nft = cryptoCurrency,