diff --git a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt index f98c7d2bd2..92e80ff6db 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt @@ -6,6 +6,7 @@ import com.tangem.domain.staking.repositories.StakingErrorResolver import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.staking.repositories.StakingTransactionHashRepository import com.tangem.domain.staking.single.SingleYieldBalanceFetcher +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.walletmanager.WalletManagersFacade import dagger.Module import dagger.Provides @@ -216,4 +217,10 @@ internal object StakingDomainModule { fun provideStakingIdFactory(walletManagersFacade: WalletManagersFacade): StakingIdFactory { return StakingIdFactory(walletManagersFacade = walletManagersFacade) } + + @Provides + @Singleton + fun provideStakingApyFlowUseCase(stakingRepository: StakingRepository): StakingApyFlowUseCase { + return StakingApyFlowUseCase(stakingRepository) + } } \ No newline at end of file diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index a5d7fe36e0..0c5042c6d8 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -7,6 +7,7 @@ import com.tangem.core.ui.components.icons.IconTint import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.components.marketprice.utils.PriceChangeConverter import com.tangem.core.ui.components.token.state.TokenItemState +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList @@ -16,15 +17,14 @@ import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.percent import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.StatusSource -import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.yieldSupplyKey import com.tangem.domain.models.currency.yieldSupplyNotAllAmountSupplied import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.converter.Converter -import com.tangem.utils.extensions.isZero import com.tangem.utils.extensions.orZero import kotlinx.collections.immutable.toImmutableList import java.math.BigDecimal @@ -40,12 +40,13 @@ import java.math.BigDecimal */ class TokenItemStateConverter( private val appCurrency: AppCurrency, - private val apyMap: Map = emptyMap(), + private val yieldModuleApyMap: Map = emptyMap(), + private val stakingApyMap: Map = emptyMap(), private val iconStateProvider: (CryptoCurrencyStatus) -> CurrencyIconState = { CryptoCurrencyToIconStateConverter().convert(it) }, private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = { - createTitleState(it, apyMap) + createTitleState(it, yieldModuleApyMap, stakingApyMap) }, private val subtitleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.SubtitleState? = { createSubtitleState(it, appCurrency) @@ -154,7 +155,8 @@ class TokenItemStateConverter( private fun createTitleState( currencyStatus: CryptoCurrencyStatus, - apyMap: Map, + yieldModuleApyMap: Map, + stakingApyMap: Map, ): TokenItemState.TitleState { return when (val value = currencyStatus.value) { is CryptoCurrencyStatus.Loading, @@ -169,13 +171,11 @@ class TokenItemStateConverter( is CryptoCurrencyStatus.NoQuote, is CryptoCurrencyStatus.NoAccount, -> { - val earnApyText = resolveEarnApy(currencyStatus, apyMap)?.let { apy -> - resourceReference( - R.string.yield_module_earn_badge, - wrappedList(apy), - ) - } - val isActive = currencyStatus.value.yieldSupplyStatus?.isActive ?: false + val (earnApyText, isActive) = resolveEarnApy( + cryptoCurrencyStatus = currencyStatus, + yieldModuleApyMap = yieldModuleApyMap, + stakingApyMap = stakingApyMap, + ) TokenItemState.TitleState.Content( text = stringReference(currencyStatus.currency.name), hasPending = value.hasCurrentNetworkTransactions, @@ -186,12 +186,36 @@ class TokenItemStateConverter( } } - private fun resolveEarnApy(cryptoCurrencyStatus: CryptoCurrencyStatus, apyMap: Map): String? { - if (apyMap.isEmpty()) return null + private fun resolveEarnApy( + cryptoCurrencyStatus: CryptoCurrencyStatus, + yieldModuleApyMap: Map, + stakingApyMap: Map, + ): Pair { + val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token + if (token != null && yieldModuleApyMap.isNotEmpty()) { + val yieldSupplyApy = yieldModuleApyMap[token.yieldSupplyKey()] + if (yieldSupplyApy != null) { + val isActive = cryptoCurrencyStatus.value.yieldSupplyStatus?.isActive ?: false + return resourceReference( + R.string.yield_module_earn_badge, + wrappedList(yieldSupplyApy), + ) to isActive + } + } - val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token ?: return null + if (stakingApyMap.isNotEmpty()) { + val stakingKey = cryptoCurrencyStatus.currency.stakingKey() + val stakingApy = stakingApyMap[stakingKey]?.format { percent(withPercentSign = false) } + if (stakingApy != null) { + val hasStakedBalance = cryptoCurrencyStatus.value.yieldBalance is YieldBalance.Data + return resourceReference( + R.string.yield_module_earn_badge, + wrappedList(stakingApy), + ) to hasStakedBalance + } + } - return apyMap[token.yieldSupplyKey()] + return null to false } private fun createSubtitleState( @@ -255,14 +279,6 @@ class TokenItemStateConverter( tint = IconTint.Warning, ).let(::add) } - if (!status.getStakedBalance().isZero()) { - add( - TokenItemState.FiatAmountState.Content.IconUM( - iconRes = R.drawable.ic_staking_24, - tint = IconTint.Accent, - ), - ) - } if (status.value.sources.total == StatusSource.ONLY_CACHE) { add( TokenItemState.FiatAmountState.Content.IconUM( @@ -308,5 +324,9 @@ class TokenItemStateConverter( } fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = sources.total == StatusSource.CACHE + + private fun CryptoCurrency.stakingKey(): String { + return "${network.backendId}_$symbol" + } } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt index 685f7696ee..f762f3b848 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/TokenTitle.kt @@ -3,11 +3,7 @@ package com.tangem.core.ui.components.token.internal import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -85,14 +81,14 @@ private fun CurrencyNameText(name: String, isAvailable: Boolean, modifier: Modif private fun YieldSupplyApyLabel(apy: TextReference?, isActive: Boolean, modifier: Modifier = Modifier) { AnimatedVisibility(visible = apy != null, modifier = modifier) { Box( - modifier = if (isActive) { - modifier.background( - color = TangemTheme.colors.text.accent.copy(alpha = 0.1f), - shape = TangemTheme.shapes.roundedCornersSmall2, - ) - } else { - modifier - }, + modifier = Modifier.background( + color = if (isActive) { + TangemTheme.colors.text.accent.copy(alpha = 0.1f) + } else { + TangemTheme.colors.control.unchecked + }, + shape = TangemTheme.shapes.roundedCornersSmall2, + ), ) { Text( text = apy?.resolveReference().orEmpty(), @@ -100,7 +96,7 @@ private fun YieldSupplyApyLabel(apy: TextReference?, isActive: Boolean, modifier color = if (isActive) { TangemTheme.colors.text.accent } else { - TangemTheme.colors.text.tertiary + TangemTheme.colors.text.secondary }, modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp), ) diff --git a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalPercentFormat.kt b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalPercentFormat.kt index 84e5870e68..8d22eff0a6 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalPercentFormat.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/format/bigdecimal/BigDecimalPercentFormat.kt @@ -7,6 +7,7 @@ import java.util.Locale class BigDecimalPercentFormat( val isWithoutSign: Boolean = true, + val withPercentSign: Boolean = true, val locale: Locale = Locale.getDefault(), ) : BigDecimalFormat { override fun invoke(value: BigDecimal): String = default()(value) @@ -16,24 +17,30 @@ class BigDecimalPercentFormat( fun BigDecimalFormatScope.percent( withoutSign: Boolean = true, + withPercentSign: Boolean = true, locale: Locale = Locale.getDefault(), ): BigDecimalPercentFormat { return BigDecimalPercentFormat( isWithoutSign = withoutSign, locale = locale, + withPercentSign = withPercentSign, ) } // == Formatters == private fun BigDecimalPercentFormat.default(): BigDecimalFormat = BigDecimalFormat { value -> - val formatter = NumberFormat.getPercentInstance(locale).apply { + val formatter = if (withPercentSign) { + NumberFormat.getPercentInstance(locale) + } else { + NumberFormat.getNumberInstance(locale) + }.apply { maximumFractionDigits = 2 minimumFractionDigits = 2 roundingMode = RoundingMode.HALF_UP } - val valueToFormat = if (isWithoutSign) value.abs() else value + val finalValue = if (withPercentSign) valueToFormat else valueToFormat.movePointRight(2) - formatter.format(valueToFormat) + formatter.format(finalValue) } \ No newline at end of file diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index e279943212..f6341c0957 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -500,7 +500,7 @@ internal class DefaultStakingRepository( ) } - private fun getEnabledYields(): Flow> { + override fun getEnabledYields(): Flow> { return stakingYieldsStore.get().map { YieldConverter.convertListIgnoreErrors( input = it, diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt index efbbae2c38..7e360eb780 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/repositories/StakingRepository.kt @@ -22,6 +22,8 @@ interface StakingRepository { suspend fun fetchEnabledYields() + fun getEnabledYields(): Flow> + suspend fun getEntryInfo(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): StakingEntryInfo suspend fun getYield(cryptoCurrencyId: CryptoCurrency.ID, symbol: String): Yield diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt new file mode 100644 index 0000000000..5138158704 --- /dev/null +++ b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt @@ -0,0 +1,37 @@ +package com.tangem.domain.staking.usecase + +import com.tangem.domain.staking.model.stakekit.Yield +import com.tangem.domain.staking.repositories.StakingRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import java.math.BigDecimal + +/** + * Emits a map of APY values per currency for staking. + * + * Return map: + * - key: currency staking key (network.backendId + "_" + symbol) + * - value: APY as string + */ +class StakingApyFlowUseCase(private val stakingRepository: StakingRepository) { + + operator fun invoke(): Flow> { + return stakingRepository.getEnabledYields() + .map { yields -> + yields.associate { yield -> + val key = "${yield.token.network.name.lowercase()}_${yield.token.symbol}" + val apy = calculateApy(yield) + key to apy + } + } + } + + private fun calculateApy(yield: Yield): BigDecimal { + val rates = yield.validators.mapNotNull { it.rewardInfo?.rate } + return if (rates.isNotEmpty()) { + rates.maxOf { it } + } else { + yield.apy + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt index 0aee41a87b..5eb6975247 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt @@ -8,6 +8,7 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase @@ -44,6 +45,7 @@ internal class MultiWalletContentLoader( private val currenciesRepository: CurrenciesRepository, private val accountDependencies: AccountDependencies, private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase, + private val stakingApyFlowUseCase: StakingApyFlowUseCase, ) : WalletContentLoader(id = userWallet.walletId) { override fun create(): List { @@ -60,6 +62,7 @@ internal class MultiWalletContentLoader( runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, accountDependencies = accountDependencies, yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase, + stakingApyFlowUseCase = stakingApyFlowUseCase, ).let(::add) WalletNFTListSubscriber( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt index 2def028fe4..63d8447f57 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt @@ -8,6 +8,7 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase @@ -42,6 +43,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor( private val currenciesRepository: CurrenciesRepository, private val accountDependencies: AccountDependencies, private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase, + private val stakingApyFlowUseCase: StakingApyFlowUseCase, ) { fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): WalletContentLoader { @@ -65,6 +67,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor( currenciesRepository = currenciesRepository, accountDependencies = accountDependencies, yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase, + stakingApyFlowUseCase = stakingApyFlowUseCase, ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt index 4bbae24b19..7b01ba0107 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt @@ -4,6 +4,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents @@ -34,6 +35,7 @@ internal class SingleWalletWithTokenContentLoader( private val getStoryContentUseCase: GetStoryContentUseCase, private val accountDependencies: AccountDependencies, private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase, + private val stakingApyFlowUseCase: StakingApyFlowUseCase, ) : WalletContentLoader(id = userWallet.walletId) { override fun create(): List { @@ -49,6 +51,7 @@ internal class SingleWalletWithTokenContentLoader( runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, accountDependencies = accountDependencies, yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase, + stakingApyFlowUseCase = stakingApyFlowUseCase, ).let(::add) MultiWalletWarningsSubscriber( userWallet = userWallet, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt index 743e1bf3c8..4c178e1136 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt @@ -5,6 +5,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents @@ -35,6 +36,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( private val getStoryContentUseCase: GetStoryContentUseCase, private val accountDependencies: AccountDependencies, private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase, + private val stakingApyFlowUseCase: StakingApyFlowUseCase, ) { fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader { @@ -54,6 +56,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase, accountDependencies = accountDependencies, yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase, + stakingApyFlowUseCase = stakingApyFlowUseCase, ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt index 9b15ca02a0..5255206967 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt @@ -10,6 +10,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.converte import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TokenListStateConverter import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons import timber.log.Timber +import java.math.BigDecimal internal class SetTokenListTransformer( private val params: TokenConverterParams, @@ -17,6 +18,7 @@ internal class SetTokenListTransformer( private val appCurrency: AppCurrency, private val clickIntents: WalletClickIntents, private val yieldSupplyApyMap: Map = emptyMap(), + private val stakingApyMap: Map = emptyMap(), ) : WalletStateTransformer(userWallet.walletId) { override fun transform(prevState: WalletState): WalletState { @@ -59,7 +61,8 @@ internal class SetTokenListTransformer( selectedWallet = userWallet, appCurrency = appCurrency, clickIntents = clickIntents, - apyMap = yieldSupplyApyMap, + yieldModuleApyMap = yieldSupplyApyMap, + stakingApyMap = stakingApyMap, ).convert(value = this) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt index eee1c4776a..9134b2295d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt @@ -27,6 +27,7 @@ import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.mutate import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList +import java.math.BigDecimal import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.OrganizeTokensButtonConfig as WalletOrganizeTokensButtonConfig internal class TokenListStateConverter( @@ -34,7 +35,8 @@ internal class TokenListStateConverter( private val params: TokenConverterParams, private val selectedWallet: UserWallet, private val clickIntents: WalletClickIntents, - private val apyMap: Map, + private val yieldModuleApyMap: Map, + private val stakingApyMap: Map, ) : Converter { private val onTokenClick: (accountId: AccountId?, currencyStatus: CryptoCurrencyStatus) -> Unit = @@ -49,7 +51,8 @@ internal class TokenListStateConverter( private fun tokenStatusConverter(accountId: AccountId? = null) = TokenItemStateConverter( appCurrency = appCurrency, - apyMap = apyMap, + yieldModuleApyMap = yieldModuleApyMap, + stakingApyMap = stakingApyMap, onItemClick = { _, status -> onTokenClick(accountId, status) }, onItemLongClick = { _, status -> onTokenLongClick(accountId, status) }, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt index 80068f621c..328d3a5cbe 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt @@ -16,6 +16,7 @@ import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase 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.TokenListAnalyticsSender @@ -25,12 +26,14 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetToken import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams import com.tangem.utils.coroutines.JobHolder +import com.tangem.utils.coroutines.combine6 import com.tangem.utils.coroutines.saveIn import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import timber.log.Timber +import java.math.BigDecimal @Suppress("LongParameterList") internal abstract class BasicTokenListSubscriber : WalletSubscriber() { @@ -43,6 +46,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { protected abstract val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase protected abstract val accountDependencies: AccountDependencies protected abstract val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase + protected abstract val stakingApyFlowUseCase: StakingApyFlowUseCase private val sendAnalyticsJobHolder = JobHolder() private val onTokenListReceivedJobHolder = JobHolder() @@ -81,12 +85,14 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { }, flow2 = appCurrencyFlow(), flow3 = yieldSupplyApyFlow(), - transform = { maybeTokenList, appCurrency, yieldSupplyApyMap -> + flow4 = stakingApyFlow(), + transform = { maybeTokenList, appCurrency, yieldSupplyApyMap, stakingApyMap -> singleAccountTransform( maybeTokenList = maybeTokenList, appCurrency = appCurrency, portfolioId = PortfolioId(userWallet.walletId), yieldSupplyApyMap = yieldSupplyApyMap, + stakingApyMap = stakingApyMap, ) }, ) @@ -97,6 +103,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { appCurrency: AppCurrency, portfolioId: PortfolioId, yieldSupplyApyMap: Map, + stakingApyMap: Map, ) { val tokenList = maybeTokenList.getOrElse( ifLoading = { maybeContent -> @@ -124,6 +131,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { params = TokenConverterParams.Wallet(portfolioId, tokenList), appCurrency = appCurrency, yieldSupplyApyMap = yieldSupplyApyMap, + stakingApyMap = stakingApyMap, ) walletWithFundsChecker.check(tokenList) @@ -143,8 +151,8 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { } } - private fun createAccountListFlow(coroutineScope: CoroutineScope): Flow<*> = combine( - flow = accountListFlow(coroutineScope) + private fun createAccountListFlow(coroutineScope: CoroutineScope): Flow<*> = combine6( + flow1 = accountListFlow(coroutineScope) .onEach { accountStatusList -> coroutineScope.launch { sendTokenListAnalytics( @@ -165,7 +173,8 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet), flow4 = accountDependencies.isAccountsModeEnabledUseCase(), flow5 = yieldSupplyApyFlow(), - transform = { accountList, appCurrency, expandedAccounts, isAccountMode, yieldSupplyApyMap -> + flow6 = stakingApyFlow(), + transform = { accountList, appCurrency, expandedAccounts, isAccountMode, yieldSupplyApyMap, stakingApyMap -> val accountFlattenTokensList = accountList.flattenTokens() val accountFlattenCurrencies = accountFlattenTokensList .map { it.flattenCurrencies() } @@ -180,6 +189,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { appCurrency, PortfolioId(mainAccount.account.accountId), yieldSupplyApyMap, + stakingApyMap, ) when { @@ -198,7 +208,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { ) false -> { val convertParams = TokenConverterParams.Account(accountList, expandedAccounts) - updateContent(convertParams, appCurrency, yieldSupplyApyMap) + updateContent(convertParams, appCurrency, yieldSupplyApyMap, stakingApyMap) accountFlattenTokensList .map { tokenList -> coroutineScope.launch { walletWithFundsChecker.check(tokenList) } } .joinAll() @@ -232,6 +242,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { params: TokenConverterParams, appCurrency: AppCurrency, yieldSupplyApyMap: Map, + stakingApyMap: Map, ) { stateHolder.update( SetTokenListTransformer( @@ -240,6 +251,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { appCurrency = appCurrency, clickIntents = clickIntents, yieldSupplyApyMap = yieldSupplyApyMap, + stakingApyMap = stakingApyMap, ), ) } @@ -255,4 +267,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() { private fun yieldSupplyApyFlow(): Flow> = yieldSupplyApyFlowUseCase() .distinctUntilChanged() + + private fun stakingApyFlow(): Flow> = stakingApyFlowUseCase() + .distinctUntilChanged() } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt index f56709b1d7..f64dafc766 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletTokenListSubscriber.kt @@ -10,6 +10,7 @@ import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.error.TokenListError @@ -36,6 +37,7 @@ internal class MultiWalletTokenListSubscriber( override val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, override val accountDependencies: AccountDependencies, override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase, + override val stakingApyFlowUseCase: StakingApyFlowUseCase, ) : BasicTokenListSubscriber() { override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt index 6866fdbf8f..15892dd13b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletWithTokenListSubscriber.kt @@ -7,6 +7,7 @@ import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase @@ -31,6 +32,7 @@ internal class SingleWalletWithTokenListSubscriber( override val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, override val accountDependencies: AccountDependencies, override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase, + override val stakingApyFlowUseCase: StakingApyFlowUseCase, ) : BasicTokenListSubscriber() { override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow {