Updated on 2026-08-14
This commit is contained in:
parent
72d9b99348
commit
de3bdb3cb0
18 changed files with 138 additions and 49 deletions
|
|
@ -65,4 +65,6 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
|
|||
fun onFailedTxEmailClick(errorMessage: String)
|
||||
|
||||
fun openTokenDetails(cryptoCurrency: CryptoCurrency)
|
||||
|
||||
fun showPrimaryClickAlert()
|
||||
}
|
||||
|
|
@ -295,13 +295,13 @@ internal class StakingModel @Inject constructor(
|
|||
)
|
||||
updateNotifications()
|
||||
},
|
||||
onStakingFeeError = {
|
||||
stateController.update(AddStakingErrorTransformer())
|
||||
updateNotifications(GetFeeError.UnknownError)
|
||||
onStakingFeeError = { stakingFeeError ->
|
||||
stateController.update(AddStakingErrorTransformer)
|
||||
updateNotifications(stakingError = stakingFeeError)
|
||||
},
|
||||
onFeeError = { error ->
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError)
|
||||
stateController.update(AddStakingErrorTransformer())
|
||||
stateController.update(AddStakingErrorTransformer)
|
||||
updateNotifications(error)
|
||||
},
|
||||
onApprovalFee = { fee ->
|
||||
|
|
@ -646,7 +646,7 @@ internal class StakingModel @Inject constructor(
|
|||
}.saveIn(approvalJobHolder)
|
||||
}
|
||||
|
||||
private fun updateNotifications(feeError: GetFeeError? = null) {
|
||||
private fun updateNotifications(feeError: GetFeeError? = null, stakingError: StakingError? = null) {
|
||||
modelScope.launch {
|
||||
val confirmationState = value.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
val feeState = confirmationState?.feeState as? FeeState.Content
|
||||
|
|
@ -687,6 +687,7 @@ internal class StakingModel @Inject constructor(
|
|||
currencyCheck = currencyStatus,
|
||||
isSubtractAvailable = isAmountSubtractAvailable,
|
||||
feeError = feeError,
|
||||
stakingError = stakingError,
|
||||
yield = yield,
|
||||
),
|
||||
)
|
||||
|
|
@ -839,6 +840,14 @@ internal class StakingModel @Inject constructor(
|
|||
innerRouter.openTokenDetails(userWalletId, cryptoCurrency)
|
||||
}
|
||||
|
||||
override fun showPrimaryClickAlert() {
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(
|
||||
StakingAlertUM.StakeMoreClickUnavailable(cryptoCurrencyStatus.currency),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun setupApprovalNeeded() {
|
||||
stakingApproval = isApproveNeededUseCase(cryptoCurrencyStatus.currency).fold(
|
||||
ifRight = { approval ->
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@ internal object StakingNotification {
|
|||
buttonState = buttonState,
|
||||
onCloseClick = onCloseClick,
|
||||
) {
|
||||
data class StakedPositionNotFoundError(val message: String) : StakingNotification.Error(
|
||||
data class StakedPositionNotFoundError(val message: String) : Error(
|
||||
title = stringReference(message),
|
||||
subtitle = stringReference(message),
|
||||
)
|
||||
|
||||
data class Common(val subtitle: TextReference) : StakingNotification.Error(
|
||||
data class Common(val subtitle: TextReference) : Error(
|
||||
title = resourceReference(R.string.common_error),
|
||||
subtitle = subtitle,
|
||||
)
|
||||
|
||||
data class CardanoMinimumBalance(
|
||||
data class MinimumAmountNotReachedError(
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference,
|
||||
) : StakingNotification.Error(
|
||||
) : Error(
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
)
|
||||
|
|
@ -54,9 +54,9 @@ internal object StakingNotification {
|
|||
data class TransactionInProgress(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
) : StakingNotification.Warning(title = title, subtitle = description)
|
||||
) : Warning(title = title, subtitle = description)
|
||||
|
||||
data object LowStakedBalance : StakingNotification.Warning(
|
||||
data object LowStakedBalance : Warning(
|
||||
title = resourceReference(R.string.staking_notification_low_staked_balance_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_low_staked_balance_text),
|
||||
)
|
||||
|
|
@ -75,12 +75,12 @@ internal object StakingNotification {
|
|||
) {
|
||||
data class EarnRewards(
|
||||
val subtitleText: TextReference,
|
||||
) : StakingNotification.Info(
|
||||
) : Info(
|
||||
title = resourceReference(R.string.staking_notification_earn_rewards_title),
|
||||
subtitle = subtitleText,
|
||||
)
|
||||
|
||||
data object StakeEntireBalance : StakingNotification.Info(
|
||||
data object StakeEntireBalance : Info(
|
||||
title = resourceReference(R.string.common_network_fee_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_stake_entire_balance_text),
|
||||
)
|
||||
|
|
@ -88,7 +88,7 @@ internal object StakingNotification {
|
|||
data class Unstake(
|
||||
val cooldownPeriodDays: Int,
|
||||
@StringRes val subtitleRes: Int,
|
||||
) : StakingNotification.Info(
|
||||
) : Info(
|
||||
title = resourceReference(R.string.common_unstake),
|
||||
subtitle = resourceReference(
|
||||
subtitleRes,
|
||||
|
|
@ -105,7 +105,7 @@ internal object StakingNotification {
|
|||
data class Ordinary(
|
||||
val title: TextReference,
|
||||
val text: TextReference,
|
||||
) : StakingNotification.Info(
|
||||
) : Info(
|
||||
title = title,
|
||||
subtitle = text,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.common.ui.alerts.models.AlertUM
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.staking.impl.R
|
||||
|
||||
@Immutable
|
||||
|
|
@ -48,4 +49,16 @@ internal sealed class StakingAlertUM : AlertUM {
|
|||
override val message: TextReference = resourceReference(id = R.string.staking_error_no_validators_message)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
|
||||
data class StakeMoreClickUnavailable(
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
) : StakingAlertUM() {
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = resourceReference(
|
||||
id = R.string.staking_stake_more_button_unavailability_reason,
|
||||
wrappedList(cryptoCurrency.name, cryptoCurrency.symbol),
|
||||
)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
}
|
||||
|
|
@ -74,4 +74,6 @@ internal object StakingClickIntentsStub : StakingClickIntents {
|
|||
override fun openTokenDetails(cryptoCurrency: CryptoCurrency) {}
|
||||
|
||||
override fun onActiveStakeAnalytic() {}
|
||||
|
||||
override fun showPrimaryClickAlert() {}
|
||||
}
|
||||
|
|
@ -1,39 +1,20 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
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
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class AddStakingErrorTransformer(
|
||||
private val error: StakingError? = null,
|
||||
) : Transformer<StakingUiState> {
|
||||
internal object AddStakingErrorTransformer : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val confirmationState =
|
||||
prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
|
||||
|
||||
val notifications = buildList {
|
||||
addAll(confirmationState.notifications)
|
||||
error?.let { add(convertToNotification(it)) }
|
||||
}.toPersistentList()
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = confirmationState.copy(
|
||||
notifications = notifications,
|
||||
feeState = FeeState.Error,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertToNotification(error: StakingError): NotificationUM {
|
||||
return StakingNotification.Error.Common(
|
||||
subtitle = stringReference(error.toString()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -47,15 +47,22 @@ internal class SetButtonsStateTransformer(
|
|||
val isCompleted = innerConfirmState == InnerConfirmationStakingState.COMPLETED
|
||||
|
||||
val isIconVisible = isConfirmation && !isCompleted
|
||||
val isPrimaryButtonDisabled = prevState.isPrimaryButtonDisabled()
|
||||
return NavigationButton(
|
||||
textReference = prevState.getButtonText(),
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
isSecondary = false,
|
||||
isDimmed = isPrimaryButtonDisabled,
|
||||
isIconVisible = isIconVisible,
|
||||
showProgress = isInProgress,
|
||||
isEnabled = prevState.isButtonEnabled(),
|
||||
onClick = { prevState.onPrimaryClick() },
|
||||
).takeIf { prevState.isPrimaryButtonVisible() }
|
||||
onClick = {
|
||||
if (isPrimaryButtonDisabled) {
|
||||
prevState.clickIntents.showPrimaryClickAlert()
|
||||
} else {
|
||||
prevState.onPrimaryClick()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPrevButton(prevState: StakingUiState): NavigationButton? {
|
||||
|
|
@ -186,12 +193,12 @@ internal class SetButtonsStateTransformer(
|
|||
-> true
|
||||
}
|
||||
|
||||
private fun StakingUiState.isPrimaryButtonVisible(): Boolean {
|
||||
private fun StakingUiState.isPrimaryButtonDisabled(): Boolean {
|
||||
val initialState = initialInfoState as? StakingStates.InitialInfoState.Data
|
||||
val hasNotStaking = initialState?.yieldBalance == InnerYieldBalanceState.Empty
|
||||
val isCardano = BlockchainUtils.isCardano(cryptoCurrencyBlockchainId)
|
||||
|
||||
return hasNotStaking || !(isCardano && currentStep == StakingStep.InitialInfo)
|
||||
return !hasNotStaking && isCardano && currentStep == StakingStep.InitialInfo
|
||||
}
|
||||
|
||||
private fun StakingUiState.isButtonEnabled(): Boolean {
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ internal class AmountRequirementStateTransformer(
|
|||
val isExceedsMaxRequirement = if (maximum?.isPositive() == true) {
|
||||
maximum?.compareTo(amount) == -1
|
||||
} else {
|
||||
cryptoCurrencyStatus.value.amount?.compareTo(amount) == 1
|
||||
cryptoCurrencyStatus.value.amount?.compareTo(amount) == -1
|
||||
}
|
||||
|
||||
val errorText = when {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ import com.tangem.common.ui.notifications.NotificationsFactory.addRentExemptionN
|
|||
import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountErrorNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification
|
||||
import com.tangem.core.ui.extensions.networkIconResId
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.StakingErrors
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -39,6 +42,7 @@ internal class AddStakingNotificationsTransformer(
|
|||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
private val currencyWarning: CryptoCurrencyWarning?,
|
||||
private val feeError: GetFeeError?,
|
||||
private val stakingError: StakingError?,
|
||||
private val currencyCheck: CryptoCurrencyCheck,
|
||||
private val isSubtractAvailable: Boolean,
|
||||
private val yield: Yield,
|
||||
|
|
@ -93,6 +97,9 @@ internal class AddStakingNotificationsTransformer(
|
|||
onReload = prevState.clickIntents::getFee,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
addStakingErrorNotifications(
|
||||
stakingError = stakingError,
|
||||
)
|
||||
// warnings
|
||||
addWarningNotifications(
|
||||
prevState = prevState,
|
||||
|
|
@ -128,6 +135,22 @@ internal class AddStakingNotificationsTransformer(
|
|||
)
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addStakingErrorNotifications(stakingError: StakingError?) {
|
||||
when (stakingError) {
|
||||
is StakingError.StakeKitApiError -> {
|
||||
if (stakingError.message != StakingErrors.MinimumAmountNotReachedError.message) {
|
||||
add(
|
||||
StakingNotification.Error.Common(subtitle = stringReference(stakingError.toString())),
|
||||
)
|
||||
}
|
||||
}
|
||||
null -> Unit
|
||||
else -> add(
|
||||
StakingNotification.Error.Common(subtitle = stringReference(stakingError.toString())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addErrorNotifications(
|
||||
prevState: StakingUiState,
|
||||
onReload: () -> Unit,
|
||||
|
|
@ -193,7 +216,7 @@ internal class AddStakingNotificationsTransformer(
|
|||
) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
cryptoCurrencyStatus.currency
|
||||
|
||||
addRentExemptionNotification(
|
||||
rentWarning = currencyCheck.rentWarning,
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ internal class StakingInfoNotificationsFactory(
|
|||
val balance = cryptoCurrencyStatus.value.amount.orZero()
|
||||
if (isCardano && balance - feeValue < MINIMUM_STAKE_BALANCE) {
|
||||
add(
|
||||
StakingNotification.Error.CardanoMinimumBalance(
|
||||
StakingNotification.Error.MinimumAmountNotReachedError(
|
||||
title = resourceReference(R.string.staking_notification_minimum_balance_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_minimum_stake_ada_text),
|
||||
),
|
||||
|
|
@ -189,7 +189,7 @@ internal class StakingInfoNotificationsFactory(
|
|||
val balance = cryptoCurrencyStatus.value.amount.orZero()
|
||||
if (isCardano && balance - feeValue < MINIMUM_RESTAKE_BALANCE) {
|
||||
add(
|
||||
StakingNotification.Error.CardanoMinimumBalance(
|
||||
StakingNotification.Error.MinimumAmountNotReachedError(
|
||||
title = resourceReference(R.string.staking_notification_minimum_restake_ada_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_minimum_restake_ada_text),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ internal fun StakingActionType?.getPendingActionTitle(): TextReference = when (t
|
|||
StakingActionType.REVOTE -> resourceReference(R.string.staking_revote)
|
||||
StakingActionType.REBOND -> resourceReference(R.string.staking_rebond)
|
||||
StakingActionType.MIGRATE -> resourceReference(R.string.staking_migrate)
|
||||
StakingActionType.STAKE -> resourceReference(R.string.common_stake)
|
||||
StakingActionType.STAKE -> resourceReference(R.string.staking_restake)
|
||||
StakingActionType.UNSTAKE -> resourceReference(R.string.common_unstake)
|
||||
StakingActionType.UNKNOWN -> TextReference.EMPTY
|
||||
null -> TextReference.EMPTY
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue