diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt index 618c5730c3..38197dbb07 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt @@ -1,11 +1,17 @@ package com.tangem.feature.wallet.presentation.wallet.domain import arrow.core.Either +import arrow.core.right import com.tangem.core.decompose.di.ModelScoped +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles +import com.tangem.domain.account.status.producer.SingleAccountStatusProducer +import com.tangem.domain.account.status.supplier.SingleAccountStatusSupplier import com.tangem.domain.card.CardTypesResolver import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.StatusSource +import com.tangem.domain.models.account.AccountId +import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.settings.IsReadyToShowRateAppUseCase @@ -22,8 +28,11 @@ import kotlinx.coroutines.flow.* import javax.inject.Inject @ModelScoped +@Suppress("LongParameterList") internal class GetSingleWalletWarningsFactory @Inject constructor( + private val accountsFeatureToggles: AccountsFeatureToggles, private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, + private val singleAccountStatusSupplier: SingleAccountStatusSupplier, private val isDemoCardUseCase: IsDemoCardUseCase, private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, private val isNeedToBackupUseCase: IsNeedToBackupUseCase, @@ -40,7 +49,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor( val cardTypesResolver = userWallet.scanResponse.cardTypesResolver return combine( - flow = getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWallet.walletId), + flow = getPrimaryCurrencyStatusFlow(userWallet), flow2 = isReadyToShowRateAppUseCase().conflate(), flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(), flow4 = getWalletsUseCase().conflate(), @@ -217,6 +226,29 @@ internal class GetSingleWalletWarningsFactory @Inject constructor( } } + private fun getPrimaryCurrencyStatusFlow( + userWallet: UserWallet, + ): Flow> { + return if (accountsFeatureToggles.isFeatureEnabled) { + getAccountStatusFlow(userWallet).mapNotNull { accountStatus -> + accountStatus.flattenCurrencies().firstOrNull() + } + .distinctUntilChanged() + .conflate() + .map { it.right() } + } else { + getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWallet.walletId) + } + } + + private fun getAccountStatusFlow(userWallet: UserWallet): Flow { + val accountId = AccountId.forMainCryptoPortfolio(userWalletId = userWallet.walletId) + + return singleAccountStatusSupplier(SingleAccountStatusProducer.Params(accountId)) + .distinctUntilChanged() + .conflate() + } + private companion object { const val NOTE_MIGRATION_URL = "https://tangem.com/en/?promocode=Note10" const val MAX_REMAINING_SIGNATURES_COUNT = 10 diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt index cf2fb14a9d..1d1034f852 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/WalletContentLoaderFactory.kt @@ -1,6 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders import com.tangem.core.decompose.di.ModelScoped +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.isMultiCurrency @@ -12,7 +13,9 @@ import javax.inject.Inject internal class WalletContentLoaderFactory @Inject constructor( private val multiWalletContentLoaderFactory: MultiWalletContentLoaderFactory, private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoaderFactory, + private val accountsFeatureToggles: AccountsFeatureToggles, private val singleWalletContentLoaderFactory: SingleWalletContentLoaderFactory, + private val singleWalletContentLoaderV2Factory: SingleWalletContentLoaderV2.Factory, private val visaWalletContentLoaderFactory: VisaWalletContentLoaderFactory, ) { @@ -32,7 +35,11 @@ internal class WalletContentLoaderFactory @Inject constructor( visaWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh) } userWallet is UserWallet.Cold && !userWallet.isMultiCurrency -> { - singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh) + if (accountsFeatureToggles.isFeatureEnabled) { + singleWalletContentLoaderV2Factory.create(userWallet, isRefresh) + } else { + singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh) + } } else -> null } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt index f4d089e864..bf2e694a7b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoader.kt @@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.onramp.GetOnrampTransactionsUseCase import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase @@ -9,10 +10,8 @@ import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase -import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents -import com.tangem.feature.wallet.presentation.account.AccountDependencies import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -36,7 +35,6 @@ internal class SingleWalletContentLoader( private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val analyticsEventHandler: AnalyticsEventHandler, private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, - private val accountDependencies: AccountDependencies, ) : WalletContentLoader(id = userWallet.walletId) { override fun create(): List { @@ -55,7 +53,6 @@ internal class SingleWalletContentLoader( clickIntents = clickIntents, getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase, getCryptoCurrencyActionsUseCase = getCryptoCurrencyActionsUseCase, - accountDependencies = accountDependencies, ), SingleWalletNotificationsSubscriber( userWallet = userWallet, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt index e5fe7a2155..33937f2ec2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderFactory.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.onramp.GetOnrampTransactionsUseCase import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase @@ -10,10 +11,8 @@ import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase -import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents -import com.tangem.feature.wallet.presentation.account.AccountDependencies import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -21,6 +20,7 @@ import javax.inject.Inject @ModelScoped @Suppress("LongParameterList") +@Deprecated("Use SingleWalletContentLoaderV2.Factory instead") internal class SingleWalletContentLoaderFactory @Inject constructor( private val stateHolder: WalletStateController, private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, @@ -35,14 +35,12 @@ internal class SingleWalletContentLoaderFactory @Inject constructor( private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, private val analyticsEventHandler: AnalyticsEventHandler, private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, - private val accountDependencies: AccountDependencies, ) { fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader { return SingleWalletContentLoader( userWallet = userWallet, clickIntents = clickIntents, - accountDependencies = accountDependencies, isRefresh = isRefresh, stateHolder = stateHolder, getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderV2.kt new file mode 100644 index 0000000000..ad0f01c797 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletContentLoaderV2.kt @@ -0,0 +1,96 @@ +package com.tangem.feature.wallet.presentation.wallet.loaders.implementors + +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2 +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.onramp.GetOnrampTransactionsUseCase +import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase +import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase +import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase +import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase +import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents +import com.tangem.feature.wallet.presentation.account.AccountDependencies +import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender +import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.subscribers.* +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +@Suppress("LongParameterList") +internal class SingleWalletContentLoaderV2 @AssistedInject constructor( + @Assisted private val userWallet: UserWallet.Cold, + @Assisted private val isRefresh: Boolean, + private val clickIntents: WalletClickIntents, + private val stateHolder: WalletStateController, + private val getCryptoCurrencyActionsUseCaseV2: GetCryptoCurrencyActionsUseCaseV2, + private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory, + private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase, + private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, + private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase, + private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, + private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase, + private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase, + private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase, + private val analyticsEventHandler: AnalyticsEventHandler, + private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, + private val accountDependencies: AccountDependencies, +) : WalletContentLoader(id = userWallet.walletId) { + + override fun create(): List = listOf( + PrimaryCurrencySubscriberV2( + userWallet = userWallet, + singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier, + getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase, + stateController = stateHolder, + analyticsEventHandler = analyticsEventHandler, + setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase, + ), + SingleWalletButtonsSubscriberV2( + userWallet = userWallet, + singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier, + stateController = stateHolder, + clickIntents = clickIntents, + getCryptoCurrencyActionsUseCaseV2 = getCryptoCurrencyActionsUseCaseV2, + ), + SingleWalletNotificationsSubscriber( + userWallet = userWallet, + stateHolder = stateHolder, + clickIntents = clickIntents, + getSingleWalletWarningsFactory = getSingleWalletWarningsFactory, + walletWarningsAnalyticsSender = walletWarningsAnalyticsSender, + ), + WalletDropDownItemsSubscriber( + stateHolder = stateHolder, + shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, + clickIntents = clickIntents, + ), + SingleWalletExpressStatusesSubscriberV2( + userWallet = userWallet, + singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier, + getOnrampTransactionsUseCase = getOnrampTransactionsUseCase, + getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase, + onrampRemoveTransactionUseCase = onrampRemoveTransactionUseCase, + stateController = stateHolder, + clickIntents = clickIntents, + analyticsEventHandler = analyticsEventHandler, + ), + TxHistorySubscriberV2( + userWallet = userWallet, + singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier, + txHistoryItemsCountUseCase = txHistoryItemsCountUseCase, + txHistoryItemsUseCase = txHistoryItemsUseCase, + isRefresh = isRefresh, + stateController = stateHolder, + clickIntents = clickIntents, + ), + ) + + @AssistedFactory + interface Factory { + fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): SingleWalletContentLoaderV2 + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicSingleWalletSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicSingleWalletSubscriber.kt new file mode 100644 index 0000000000..a89f459bdc --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicSingleWalletSubscriber.kt @@ -0,0 +1,34 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import com.tangem.domain.models.account.AccountId +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.mapNotNull + +/** + * Basic implementation of [WalletSubscriber] for single wallet. + * +[REDACTED_AUTHOR] + */ +internal abstract class BasicSingleWalletSubscriber : BasicWalletSubscriber() { + + /** Account ID for the main crypto portfolio of the user wallet */ + val accountId: AccountId + get() = AccountId.forMainCryptoPortfolio(userWalletId = userWallet.walletId) + + /** + * Provides a flow of the primary [CryptoCurrencyStatus] for the associated user wallet. + * + * @return A [Flow] emitting the primary [CryptoCurrencyStatus] of the wallet, distinct and conflated. + */ + protected fun getPrimaryCurrencyStatusFlow(): Flow { + return getMainAccountStatusFlow() + .mapNotNull { accountStatus -> + accountStatus.flattenCurrencies().firstOrNull() + } + .distinctUntilChanged() + .conflate() + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicWalletSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicWalletSubscriber.kt new file mode 100644 index 0000000000..9254f90e44 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicWalletSubscriber.kt @@ -0,0 +1,56 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import com.tangem.domain.account.models.AccountStatusList +import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.models.account.AccountStatus +import com.tangem.domain.models.wallet.UserWallet +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.mapNotNull + +/** + * Basic implementation of [WalletSubscriber] for wallet. + * +[REDACTED_AUTHOR] + */ +internal abstract class BasicWalletSubscriber : WalletSubscriber() { + + /** User wallet associated with this subscriber */ + abstract val userWallet: UserWallet + + /** Supplier to get the account status for the wallet */ + abstract val singleAccountStatusListSupplier: SingleAccountStatusListSupplier + + /** + * Provides a flow of [AccountStatusList] for the associated user wallet. + * + * @return A [Flow] emitting the [AccountStatusList] of the wallet, distinct and conflated. + */ + protected fun getAccountStatusListFlow(): Flow { + return singleAccountStatusListSupplier( + params = SingleAccountStatusListProducer.Params(userWallet.walletId), + ) + .distinctUntilChanged() + .conflate() + } + + /** + * Provides a flow of [AccountStatus] for the associated user wallet. + * + * @return A [Flow] emitting the [AccountStatus] of the wallet, distinct and conflated. + */ + protected fun getMainAccountStatusFlow(): Flow { + return getAccountStatusListFlow() + .mapNotNull { accountStatusList -> + accountStatusList.accountStatuses.find { accountStatus -> + when (accountStatus) { + is AccountStatus.CryptoPortfolio -> accountStatus.account.isMainAccount + } + } + } + .distinctUntilChanged() + .conflate() + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt index 4532a34ec2..6f564c38a2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.* import timber.log.Timber import java.math.BigDecimal +@Deprecated("Use PrimaryCurrencySubscriberV2 instead") internal class PrimaryCurrencySubscriber( private val userWallet: UserWallet, private val stateHolder: WalletStateController, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriberV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriberV2.kt new file mode 100644 index 0000000000..e6b137a056 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriberV2.kt @@ -0,0 +1,91 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import com.tangem.common.extensions.isZero +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase +import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetPrimaryCurrencyTransformer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.onEach +import java.math.BigDecimal + +internal class PrimaryCurrencySubscriberV2( + override val userWallet: UserWallet, + override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, + private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, + private val stateController: WalletStateController, + private val analyticsEventHandler: AnalyticsEventHandler, + private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase, +) : BasicSingleWalletSubscriber() { + + override fun create(coroutineScope: CoroutineScope): Flow<*> { + return combine( + flow = getPrimaryCurrencyStatusFlow(), + flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(), + transform = ::Pair, + ) + .onEach { (status, appCurrency) -> + updateContent(status, appCurrency) + sendAnalyticsEvent(status) + checkWalletWithFunds(status) + } + } + + private fun updateContent(status: CryptoCurrencyStatus, appCurrency: AppCurrency) { + stateController.update( + SetPrimaryCurrencyTransformer( + status = status, + userWallet = userWallet, + appCurrency = appCurrency, + ), + ) + } + + private fun sendAnalyticsEvent(status: CryptoCurrencyStatus) { + val fiatAmount = status.value.fiatAmount + val cardBalanceState = when (status.value) { + is CryptoCurrencyStatus.Loaded, + is CryptoCurrencyStatus.NoAccount, + is CryptoCurrencyStatus.NoAmount, + -> createCardBalanceState(fiatAmount) + is CryptoCurrencyStatus.NoQuote -> AnalyticsParam.CardBalanceState.NoRate + is CryptoCurrencyStatus.Unreachable, + -> AnalyticsParam.CardBalanceState.BlockchainError + is CryptoCurrencyStatus.MissedDerivation, + is CryptoCurrencyStatus.Loading, + is CryptoCurrencyStatus.Custom, + -> null + } + + cardBalanceState?.let { + // do not send tokens count for single currency wallet + analyticsEventHandler.send( + event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded( + balance = it, + tokensCount = null, + ), + ) + } + } + + private fun createCardBalanceState(fiatAmount: BigDecimal?): AnalyticsParam.CardBalanceState? { + return when { + fiatAmount == null -> null + fiatAmount.isZero() -> AnalyticsParam.CardBalanceState.Empty + else -> AnalyticsParam.CardBalanceState.Full + } + } + + private suspend fun checkWalletWithFunds(status: CryptoCurrencyStatus) { + if (status.value.amount?.isZero() == false) setWalletWithFundsFoundUseCase() + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt index 830f1f9b69..af71e2d23f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt @@ -7,20 +7,19 @@ import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents -import com.tangem.feature.wallet.presentation.account.AccountDependencies import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetCryptoCurrencyActionsTransformer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* +@Deprecated("Use SingleWalletButtonsSubscriberV2 instead") internal class SingleWalletButtonsSubscriber( private val userWallet: UserWallet, private val stateHolder: WalletStateController, private val clickIntents: WalletClickIntents, private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase, - private val accountDependencies: AccountDependencies, ) : WalletSubscriber() { override fun create(coroutineScope: CoroutineScope): Flow { @@ -31,11 +30,10 @@ internal class SingleWalletButtonsSubscriber( } } .onEach { actions -> - val portfolioId = when (accountDependencies.accountsFeatureToggles.isFeatureEnabled) { - true -> TODO("account") // get main account id for single wallet - false -> PortfolioId(userWallet.walletId) - } - updateContent(actions, portfolioId) + updateContent( + tokenActionsState = actions, + portfolioId = PortfolioId(userWallet.walletId), + ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriberV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriberV2.kt new file mode 100644 index 0000000000..85d65823fb --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriberV2.kt @@ -0,0 +1,46 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2 +import com.tangem.domain.models.PortfolioId +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.tokens.model.TokenActionsState +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetCryptoCurrencyActionsTransformer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.onEach + +internal class SingleWalletButtonsSubscriberV2( + override val userWallet: UserWallet, + override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, + private val stateController: WalletStateController, + private val clickIntents: WalletClickIntents, + private val getCryptoCurrencyActionsUseCaseV2: GetCryptoCurrencyActionsUseCaseV2, +) : BasicSingleWalletSubscriber() { + + @OptIn(ExperimentalCoroutinesApi::class) + override fun create(coroutineScope: CoroutineScope): Flow { + return getPrimaryCurrencyStatusFlow() + .flatMapLatest { + getCryptoCurrencyActionsUseCaseV2(accountId = accountId, currency = it.currency) + } + .onEach { + updateContent(tokenActionsState = it, portfolioId = PortfolioId(userWallet.walletId)) + } + } + + private fun updateContent(tokenActionsState: TokenActionsState, portfolioId: PortfolioId) { + stateController.update( + SetCryptoCurrencyActionsTransformer( + tokenActionsState = tokenActionsState, + userWallet = userWallet, + clickIntents = clickIntents, + portfolioId = portfolioId, + ), + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt index a2d9cbdd89..d417654a2f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriber.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.* import timber.log.Timber @Suppress("LongParameterList") +@Deprecated("Use SingleWalletExpressStatusesSubscriberV2 instead") internal class SingleWalletExpressStatusesSubscriber( private val userWallet: UserWallet, private val stateHolder: WalletStateController, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriberV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriberV2.kt new file mode 100644 index 0000000000..59581e98ce --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletExpressStatusesSubscriberV2.kt @@ -0,0 +1,84 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.onramp.GetOnrampTransactionsUseCase +import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase +import com.tangem.domain.onramp.model.cache.OnrampTransaction +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetExpressStatusesTransformer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.* + +@Suppress("LongParameterList") +internal class SingleWalletExpressStatusesSubscriberV2( + override val userWallet: UserWallet, + override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, + private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase, + private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, + private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase, + private val stateController: WalletStateController, + private val clickIntents: WalletClickIntents, + private val analyticsEventHandler: AnalyticsEventHandler, +) : BasicSingleWalletSubscriber() { + + @OptIn(ExperimentalCoroutinesApi::class) + override fun create(coroutineScope: CoroutineScope): Flow<*> { + val getOnrampTransactionsFlow = getPrimaryCurrencyStatusFlow().flatMapLatest { currencyStatus -> + getOnrampTransactionsUseCase( + userWalletId = userWallet.walletId, + cryptoCurrencyId = currencyStatus.currency.id, + ) + .map { currencyStatus to it } + } + + return combine( + flow = getOnrampTransactionsFlow, + flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(), + transform = ::toTriple, + ) + .onEach { (status, maybeTransaction, appCurrency) -> + maybeTransaction.fold( + ifRight = { onrampTxs -> + onrampTxs.clearHiddenTerminal() + stateController.update( + SetExpressStatusesTransformer( + userWalletId = userWallet.walletId, + onrampTxs = onrampTxs, + clickIntents = clickIntents, + cryptoCurrencyStatus = status, + appCurrency = appCurrency, + analyticsEventHandler = analyticsEventHandler, + ), + ) + }, + ifLeft = { + stateController.update( + SetExpressStatusesTransformer( + userWalletId = userWallet.walletId, + onrampTxs = listOf(), + clickIntents = clickIntents, + cryptoCurrencyStatus = status, + appCurrency = appCurrency, + analyticsEventHandler = analyticsEventHandler, + ), + ) + }, + ) + } + } + + private fun toTriple(firstPair: Pair, second: C): Triple { + return Triple(firstPair.first, firstPair.second, second) + } + + private suspend fun List.clearHiddenTerminal() { + this + .filter { it.status.isHidden && it.status.isTerminal } + .forEach { onrampRemoveTransactionUseCase(txId = it.txId) } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt index e5deefbf1f..b9c65f6340 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriber.kt @@ -30,6 +30,7 @@ typealias MaybeTxHistoryCount = Either typealias MaybeTxHistoryItems = Either>> @Suppress("LongParameterList") +@Deprecated("Use TxHistorySubscriberV2 instead") internal class TxHistorySubscriber( private val userWallet: UserWallet.Cold, private val isRefresh: Boolean, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriberV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriberV2.kt new file mode 100644 index 0000000000..23e7c78681 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TxHistorySubscriberV2.kt @@ -0,0 +1,111 @@ +package com.tangem.feature.wallet.presentation.wallet.subscribers + +import androidx.paging.PagingData +import androidx.paging.cachedIn +import androidx.paging.map +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.card.common.util.cardTypesResolver +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.network.TxInfo +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase +import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase +import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountErrorTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsErrorTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TxHistoryItemStateConverter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map + +@Suppress("LongParameterList") +internal class TxHistorySubscriberV2( + override val userWallet: UserWallet.Cold, + override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, + private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, + private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase, + private val isRefresh: Boolean, + private val stateController: WalletStateController, + private val clickIntents: WalletClickIntents, +) : BasicSingleWalletSubscriber() { + + override fun create(coroutineScope: CoroutineScope): Flow> { + return flow { + getPrimaryCurrencyStatusFlow().collectLatest { status -> + val maybeTxHistoryItemCount = txHistoryItemsCountUseCase( + userWalletId = userWallet.walletId, + currency = status.currency, + ) + + setLoadingTxHistoryState(maybeTxHistoryItemCount, status) + + maybeTxHistoryItemCount.onRight { + val maybeTxHistoryItems = txHistoryItemsUseCase( + userWalletId = userWallet.walletId, + currency = status.currency, + refresh = isRefresh, + ).map { it.cachedIn(coroutineScope) } + + setLoadedTxHistoryState(maybeTxHistoryItems) + } + } + } + } + + private fun setLoadingTxHistoryState(maybeTxHistoryItemCount: MaybeTxHistoryCount, status: CryptoCurrencyStatus) { + stateController.update( + maybeTxHistoryItemCount.fold( + ifLeft = { + SetTxHistoryCountErrorTransformer( + userWallet = userWallet, + error = it, + pendingTransactions = status.value.pendingTransactions, + clickIntents = clickIntents, + ) + }, + ifRight = { + SetTxHistoryCountTransformer( + userWalletId = userWallet.walletId, + transactionsCount = it, + clickIntents = clickIntents, + ) + }, + ), + ) + } + + private fun setLoadedTxHistoryState(maybeTxHistoryItems: MaybeTxHistoryItems) { + stateController.update( + maybeTxHistoryItems.fold( + ifLeft = { + SetTxHistoryItemsErrorTransformer( + userWalletId = userWallet.walletId, + error = it, + clickIntents = clickIntents, + ) + }, + ifRight = { itemsFlow -> + val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain() + val itemConverter = TxHistoryItemStateConverter( + symbol = blockchain.currency, + decimals = blockchain.decimals(), + clickIntents = clickIntents, + ) + + SetTxHistoryItemsTransformer( + userWallet = userWallet, + flow = itemsFlow.map { items -> + items.map(itemConverter::convert) + }, + clickIntents = clickIntents, + ) + }, + ), + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt index 01df7c3340..ad89c3d6b7 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/WalletDropDownItemsSubscriber.kt @@ -5,7 +5,9 @@ import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWalletCardDropDownItemsTransformer import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.onEach internal class WalletDropDownItemsSubscriber( private val stateHolder: WalletStateController, @@ -13,18 +15,15 @@ internal class WalletDropDownItemsSubscriber( private val clickIntents: WalletClickIntents, ) : WalletSubscriber() { override fun create(coroutineScope: CoroutineScope): Flow<*> { - return flow { - shouldSaveUserWalletsUseCase.invoke() - .distinctUntilChanged() - .onEach { - stateHolder.update( - SetWalletCardDropDownItemsTransformer( - dropdownEnabled = it, - clickIntents = clickIntents, - ), - ) - } - .launchIn(coroutineScope) - } + return shouldSaveUserWalletsUseCase.invoke() + .distinctUntilChanged() + .onEach { + stateHolder.update( + SetWalletCardDropDownItemsTransformer( + dropdownEnabled = it, + clickIntents = clickIntents, + ), + ) + } } } \ No newline at end of file