Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-28 19:03:16 +05:00
parent e6bd9fdabe
commit 5f3a5989bc
7 changed files with 180 additions and 114 deletions

View file

@ -59,7 +59,6 @@ internal object StakingNotification {
subtitle = subtitle,
buttonsState = buttonsState,
onCloseClick = onCloseClick,
) {
data class EarnRewards(
val subtitleText: TextReference,
@ -68,6 +67,11 @@ internal object StakingNotification {
subtitle = subtitleText,
)
data object StakeEntireBalance : StakingNotification.Info(
title = resourceReference(R.string.common_network_fee_title),
subtitle = resourceReference(R.string.staking_notification_stake_entire_balance_text),
)
data class Unstake(
val cooldownPeriodDays: Int,
@StringRes val subtitleRes: Int,

View file

@ -1,4 +1,4 @@
package com.tangem.features.staking.impl.presentation.state.transformers
package com.tangem.features.staking.impl.presentation.state.transformers.notifications
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.notifications.NotificationUM
@ -11,21 +11,14 @@ import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountE
import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addValidateTransactionNotifications
import com.tangem.core.ui.extensions.networkIconResId
import com.tangem.core.ui.extensions.pluralReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.staking.model.stakekit.BalanceType
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.FeeState
import com.tangem.features.staking.impl.presentation.state.StakingNotification
import com.tangem.features.staking.impl.presentation.state.StakingStates
@ -33,8 +26,6 @@ import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount
import com.tangem.features.staking.impl.presentation.state.utils.checkFeeCoverage
import com.tangem.lib.crypto.BlockchainUtils
import com.tangem.lib.crypto.BlockchainUtils.isCosmos
import com.tangem.lib.crypto.BlockchainUtils.isTron
import com.tangem.utils.Provider
import com.tangem.utils.extensions.orZero
import com.tangem.utils.transformer.Transformer
@ -53,6 +44,13 @@ internal class AddStakingNotificationsTransformer(
private val isSubtractAvailable: Boolean,
private val yield: Yield,
) : Transformer<StakingUiState> {
private val stakingInfoNotificationsFactory = StakingInfoNotificationsFactory(
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
yield = yield,
isSubtractAvailable = isSubtractAvailable,
)
override fun transform(prevState: StakingUiState): StakingUiState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val balance = cryptoCurrencyStatus.value.amount.orZero()
@ -105,7 +103,12 @@ internal class AddStakingNotificationsTransformer(
isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement),
)
addInfoNotifications(prevState)
stakingInfoNotificationsFactory.addInfoNotifications(
notifications = this,
prevState = prevState,
sendingAmount = sendingAmount,
feeValue = feeValue,
)
}.toImmutableList()
return prevState.copy(
@ -241,105 +244,4 @@ internal class AddStakingNotificationsTransformer(
add(notification)
}
}
private fun MutableList<NotificationUM>.addInfoNotifications(prevState: StakingUiState) {
when (prevState.actionType) {
StakingActionCommonType.Enter -> addEnterInfoNotifications()
StakingActionCommonType.Exit -> addExitInfoNotifications()
is StakingActionCommonType.Pending -> addPendingInfoNotifications(prevState)
}
}
private fun MutableList<NotificationUM>.addExitInfoNotifications() {
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
if (cooldownPeriodDays != null) {
add(
StakingNotification.Info.Unstake(
cooldownPeriodDays = cooldownPeriodDays,
subtitleRes = if (isCosmos(cryptoCurrencyStatusProvider().currency.network.id.value)) {
R.string.staking_notification_unstake_cosmos_text
} else {
R.string.staking_notification_unstake_text
},
),
)
}
}
private fun MutableList<NotificationUM>.addEnterInfoNotifications() {
addTronRevoteNotification()
}
private fun MutableList<NotificationUM>.addPendingInfoNotifications(prevState: StakingUiState) {
val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
val pendingActionType = confirmationState?.pendingAction?.type
val (titleReference, textReference) = when (pendingActionType) {
StakingActionType.CLAIM_REWARDS -> {
resourceReference(R.string.common_claim) to
resourceReference(R.string.staking_notification_claim_rewards_text)
}
StakingActionType.RESTAKE_REWARDS -> {
resourceReference(R.string.staking_restake) to
resourceReference(R.string.staking_notification_restake_rewards_text)
}
StakingActionType.WITHDRAW -> {
resourceReference(R.string.staking_withdraw) to
resourceReference(R.string.staking_notification_withdraw_text)
}
StakingActionType.UNLOCK_LOCKED -> {
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
if (cooldownPeriodDays != null) {
resourceReference(R.string.staking_unlocked_locked) to resourceReference(
R.string.staking_notification_unlock_text,
wrappedList(
pluralReference(
id = R.plurals.common_days,
count = cooldownPeriodDays,
formatArgs = wrappedList(cooldownPeriodDays),
),
),
)
} else {
null to null
}
}
StakingActionType.VOTE_LOCKED -> {
resourceReference(R.string.staking_revote) to
resourceReference(R.string.staking_notifications_revote_tron_text)
}
StakingActionType.RESTAKE -> {
resourceReference(R.string.staking_restake) to
resourceReference(R.string.staking_notification_restake_text)
}
else -> null to null
}
if (titleReference != null && textReference != null) {
add(
StakingNotification.Info.Ordinary(
title = titleReference,
text = textReference,
),
)
}
}
private fun MutableList<NotificationUM>.addTronRevoteNotification() {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value)
val hasStakedBalance = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.balance
?.items?.any {
it.type == BalanceType.PREPARING ||
it.type == BalanceType.STAKED ||
it.type == BalanceType.LOCKED
} == true
if (isTron && hasStakedBalance) {
add(
StakingNotification.Info.Ordinary(
title = resourceReference(R.string.staking_revote),
text = resourceReference(R.string.staking_notifications_revote_tron_text),
),
)
}
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.features.staking.impl.presentation.state.transformers
package com.tangem.features.staking.impl.presentation.state.transformers.notifications
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.features.staking.impl.presentation.state.StakingStates

View file

@ -0,0 +1,152 @@
package com.tangem.features.staking.impl.presentation.state.transformers.notifications
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.ui.extensions.pluralReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.staking.model.stakekit.BalanceType
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.StakingNotification
import com.tangem.features.staking.impl.presentation.state.StakingStates
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.lib.crypto.BlockchainUtils.isCosmos
import com.tangem.lib.crypto.BlockchainUtils.isTron
import com.tangem.utils.Provider
import com.tangem.utils.extensions.orZero
import java.math.BigDecimal
internal class StakingInfoNotificationsFactory(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
private val yield: Yield,
private val isSubtractAvailable: Boolean,
) {
fun addInfoNotifications(
notifications: MutableList<NotificationUM>,
prevState: StakingUiState,
sendingAmount: BigDecimal,
feeValue: BigDecimal,
) = with(notifications) {
when (prevState.actionType) {
StakingActionCommonType.Enter -> addEnterInfoNotifications(sendingAmount, feeValue)
StakingActionCommonType.Exit -> addExitInfoNotifications()
is StakingActionCommonType.Pending -> addPendingInfoNotifications(prevState)
}
}
private fun MutableList<NotificationUM>.addExitInfoNotifications() {
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
if (cooldownPeriodDays != null) {
add(
StakingNotification.Info.Unstake(
cooldownPeriodDays = cooldownPeriodDays,
subtitleRes = if (isCosmos(cryptoCurrencyStatusProvider().currency.network.id.value)) {
R.string.staking_notification_unstake_cosmos_text
} else {
R.string.staking_notification_unstake_text
},
),
)
}
}
private fun MutableList<NotificationUM>.addEnterInfoNotifications(
sendingAmount: BigDecimal,
feeValue: BigDecimal,
) {
addTronRevoteNotification()
addStakingEntireBalanceNotification(sendingAmount, feeValue)
}
private fun MutableList<NotificationUM>.addPendingInfoNotifications(prevState: StakingUiState) {
val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
val pendingActionType = confirmationState?.pendingAction?.type
val (titleReference, textReference) = when (pendingActionType) {
StakingActionType.CLAIM_REWARDS -> {
resourceReference(R.string.common_claim) to
resourceReference(R.string.staking_notification_claim_rewards_text)
}
StakingActionType.RESTAKE_REWARDS -> {
resourceReference(R.string.staking_restake) to
resourceReference(R.string.staking_notification_restake_rewards_text)
}
StakingActionType.WITHDRAW -> {
resourceReference(R.string.staking_withdraw) to
resourceReference(R.string.staking_notification_withdraw_text)
}
StakingActionType.UNLOCK_LOCKED -> {
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
if (cooldownPeriodDays != null) {
resourceReference(R.string.staking_unlocked_locked) to resourceReference(
R.string.staking_notification_unlock_text,
wrappedList(
pluralReference(
id = R.plurals.common_days,
count = cooldownPeriodDays,
formatArgs = wrappedList(cooldownPeriodDays),
),
),
)
} else {
null to null
}
}
StakingActionType.VOTE_LOCKED -> {
resourceReference(R.string.staking_revote) to
resourceReference(R.string.staking_notifications_revote_tron_text)
}
StakingActionType.RESTAKE -> {
resourceReference(R.string.staking_restake) to
resourceReference(R.string.staking_notification_restake_text)
}
else -> null to null
}
if (titleReference != null && textReference != null) {
add(
StakingNotification.Info.Ordinary(
title = titleReference,
text = textReference,
),
)
}
}
private fun MutableList<NotificationUM>.addTronRevoteNotification() {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value)
val hasStakedBalance = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.balance
?.items?.any {
it.type == BalanceType.PREPARING ||
it.type == BalanceType.STAKED ||
it.type == BalanceType.LOCKED
} == true
if (isTron && hasStakedBalance) {
add(
StakingNotification.Info.Ordinary(
title = resourceReference(R.string.staking_revote),
text = resourceReference(R.string.staking_notifications_revote_tron_text),
),
)
}
}
private fun MutableList<NotificationUM>.addStakingEntireBalanceNotification(
sendingAmount: BigDecimal,
feeValue: BigDecimal,
) {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val balance = cryptoCurrencyStatus.value.amount.orZero()
val isEntireBalance = sendingAmount.plus(feeValue) == balance
if (isEntireBalance && isSubtractAvailable) {
add(StakingNotification.Info.StakeEntireBalance)
}
}
}

View file

@ -61,6 +61,8 @@ import com.tangem.features.staking.impl.presentation.state.helpers.StakingTransa
import com.tangem.features.staking.impl.presentation.state.transformers.*
import com.tangem.features.staking.impl.presentation.state.transformers.amount.*
import com.tangem.features.staking.impl.presentation.state.transformers.approval.*
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.AddStakingNotificationsTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.DismissStakingNotificationsStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.validator.ValidatorSelectChangeTransformer
import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction