From b1cfd6ff505db9c3f588af289369e06b2a69244e Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 10 Jul 2026 13:47:36 +0200 Subject: [PATCH] Updated on 2026-08-14 --- .../UpdateStakingNotificationTransformer.kt | 48 +++++++++---- ...pdateStakingNotificationTransformerTest.kt | 67 +++++++++++++------ .../YieldSupplyToEarnBlockConverter.kt | 8 ++- 3 files changed, 86 insertions(+), 37 deletions(-) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformer.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformer.kt index 12dc90644f..21a31432a6 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformer.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformer.kt @@ -4,11 +4,7 @@ import androidx.compose.ui.text.SpanStyle import com.tangem.common.getRewardStakingBalance import com.tangem.common.getTotalStakingBalance import com.tangem.common.ui.earn.EarnBlockUM -import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.orMaskWithStars -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringReference -import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.extensions.* import com.tangem.core.ui.format.bigdecimal.* import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.appcurrency.model.AppCurrency @@ -20,10 +16,12 @@ import com.tangem.domain.staking.model.StakingEntryInfo import com.tangem.domain.staking.model.StakingOption import com.tangem.domain.staking.model.common.RewardInfo import com.tangem.domain.staking.model.common.RewardType +import com.tangem.domain.staking.model.optionOrNull import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM import com.tangem.features.tokendetails.impl.R import com.tangem.lib.crypto.BlockchainUtils.isStakingRewardUnavailable +import com.tangem.utils.StringsSigns import com.tangem.utils.isNullOrZero import com.tangem.utils.transformer.Transformer import java.math.BigDecimal @@ -217,6 +215,7 @@ internal class UpdateStakingNotificationTransformer( ) } + @Suppress("LongMethod") private fun getRewardSubtitle( status: CryptoCurrencyStatus, stakingRewardAmount: BigDecimal?, @@ -267,13 +266,23 @@ internal class UpdateStakingNotificationTransformer( } RewardBlockType.RewardsRequirementsError, RewardBlockType.Rewards, - -> resourceReference( - R.string.staking_details_rewards_to_claim, - wrappedList( - stakingRewardAmount.format { fiat(appCurrency.code, appCurrency.symbol) } - .orMaskWithStars(isBalanceHidden), - ), - ) + -> { + val rewardAmount = stakingRewardAmount.format { fiat(appCurrency.code, appCurrency.symbol) } + .orMaskWithStars(isBalanceHidden) + val rateReference = rewardRateReference() + if (rateReference != null) { + combinedReference( + rateReference, + stringReference(" ${StringsSigns.DOT} "), + stringReference(rewardAmount), + ) + } else { + resourceReference( + R.string.staking_details_rewards_to_claim, + wrappedList(rewardAmount), + ) + } + } } val isAccent = rewardBlockType == RewardBlockType.Rewards || @@ -285,6 +294,21 @@ internal class UpdateStakingNotificationTransformer( tone = if (isAccent) EarnBlockUM.SubtitleUM.Tone.Accent else EarnBlockUM.SubtitleUM.Tone.Disabled, ) } + + private fun rewardRateReference(): TextReference? { + val rewardInfo = stakingAvailability.optionOrNull?.displayRewardInfo ?: return null + val rateTypeResId = when (rewardInfo.type) { + RewardType.APR -> CoreResR.string.staking_details_apr + RewardType.APY, + RewardType.UNKNOWN, + -> CoreResR.string.staking_details_apy + } + return combinedReference( + stringReference(rewardInfo.rate.format { percent() }), + stringReference(" "), + resourceReference(rateTypeResId), + ) + } } private fun StakingBalance.Data?.hasPendingBalances(): Boolean = when (this) { diff --git a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformerTest.kt b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformerTest.kt index 09d0c4833b..7e312e66ee 100644 --- a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformerTest.kt +++ b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateStakingNotificationTransformerTest.kt @@ -11,29 +11,21 @@ import com.tangem.domain.models.StatusSource import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.Network -import com.tangem.domain.models.staking.BalanceItem +import com.tangem.domain.models.staking.* import com.tangem.domain.models.staking.BalanceType -import com.tangem.domain.models.staking.StakingBalance -import com.tangem.domain.models.staking.StakingID -import com.tangem.domain.models.staking.YieldBalanceItem -import com.tangem.domain.models.staking.YieldToken import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.staking.model.StakingEntryInfo import com.tangem.domain.staking.model.StakingOption -import com.tangem.utils.StringsSigns.THREE_STARS import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents -import com.tangem.feature.tokendetails.presentation.tokendetails.state.AddFundsUM -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockUM -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsTopAppBarUM +import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsTopAppBarUM.TitleState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TransferUM -import com.tangem.feature.tokendetails.presentation.tokendetails.state.ZeroBalanceActionsUM +import com.tangem.utils.StringsSigns.THREE_STARS import io.mockk.every import io.mockk.mockk import kotlinx.collections.immutable.persistentListOf import org.junit.jupiter.api.Test import java.math.BigDecimal +import com.tangem.core.res.R as CoreResR class UpdateStakingNotificationTransformerTest { @@ -194,8 +186,40 @@ class UpdateStakingNotificationTransformerTest { assertThat(rewardFormatArg(subtitle.text)).isNotEqualTo(THREE_STARS) } - private fun rewardFormatArg(text: TextReference): Any? = - (text as TextReference.Res).formatArgs.data.firstOrNull() + @Test + fun `GIVEN rewards to claim AND rate known WHEN transform THEN subtitle shows rate and reward amount`() { + // Arrange + val status = buildStatus( + networkRawId = "ethereum", + symbol = "ETH", + isCoin = false, + stakingBalance = stakeKitBalance(staked = BigDecimal("100"), rewards = BigDecimal("5")), + ) + val transformer = createTransformer( + availability = availableOption(BigDecimal("4.2")), + entryInfo = StakingEntryInfo(tokenSymbol = "ETH"), + status = status, + isBalanceHidden = false, + ) + + // Act + val result = transformer.transform(initialState()) + + // Assert + val content = result.earnBlockState as EarnBlockUM.Content + val subtitle = content.subtitleUM as EarnBlockUM.SubtitleUM.Text + val combined = subtitle.text as TextReference.Combined + val rateLabel = combined.refs.data.first() as TextReference.Combined + val apyLabel = rateLabel.refs.data.filterIsInstance().first() + assertThat(apyLabel.id).isEqualTo(CoreResR.string.staking_details_apy) + assertThat((combined.refs.data.last() as TextReference.Str).value).isNotEqualTo(THREE_STARS) + } + + private fun rewardFormatArg(text: TextReference): Any? = when (text) { + is TextReference.Res -> text.formatArgs.data.firstOrNull() + is TextReference.Combined -> (text.refs.data.last() as? TextReference.Str)?.value + else -> null + } private fun createTransformer( availability: StakingAvailability, @@ -265,17 +289,16 @@ class UpdateStakingNotificationTransformerTest { ) private fun availableOption(apy: BigDecimal): StakingAvailability.Available { - val option = mockk(relaxed = true) { - every { this@mockk.apy } returns apy - } - return StakingAvailability.Available(option = option) + return StakingAvailability.Available(option = stakingOption(apy)) } private fun fullOption(apy: BigDecimal): StakingAvailability.Full { - val option = mockk(relaxed = true) { - every { this@mockk.apy } returns apy - } - return StakingAvailability.Full(option = option) + return StakingAvailability.Full(option = stakingOption(apy)) + } + + /** Deterministic concrete [StakingOption] whose [displayRewardInfo] resolves to [apy] with an APY rate. */ + private fun stakingOption(apy: BigDecimal): StakingOption.P2PEthPool = mockk(relaxed = true) { + every { this@mockk.apy } returns apy } private fun buildStatusWithStake(stakedAmount: BigDecimal): CryptoCurrencyStatus { diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt index 17290cc94f..ed13583cad 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt @@ -6,6 +6,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM +import com.tangem.utils.StringsSigns import com.tangem.utils.converter.Converter import com.tangem.core.res.R as CoreResR import com.tangem.core.ui.R as CoreUiR @@ -80,9 +81,10 @@ internal class YieldSupplyToEarnBlockConverter : Converter