Updated on 2026-08-14

This commit is contained in:
Tangem 2024-08-28 18:08:43 +05:00
parent c10f747de8
commit 52ea08c979
10 changed files with 393 additions and 2 deletions

View file

@ -1,8 +1,9 @@
package com.tangem.features.staking.impl.di
import com.tangem.common.routing.AppRouter
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.features.staking.impl.navigation.DefaultStakingRouter
import com.tangem.features.staking.api.navigation.StakingRouter
import com.tangem.features.staking.impl.navigation.DefaultStakingRouter
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -18,9 +19,10 @@ internal object StakingRouterModule {
@Provides
@ActivityScoped
fun provideStakingRouter(urlOpener: UrlOpener): StakingRouter {
fun provideStakingRouter(urlOpener: UrlOpener, router: AppRouter): StakingRouter {
return DefaultStakingRouter(
urlOpener = urlOpener,
router = router,
)
}
}

View file

@ -1,15 +1,33 @@
package com.tangem.features.staking.impl.navigation
import androidx.fragment.app.Fragment
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.staking.impl.presentation.StakingFragment
internal class DefaultStakingRouter(
private val urlOpener: UrlOpener,
private val router: AppRouter,
) : InnerStakingRouter {
override fun getEntryFragment(): Fragment = StakingFragment.create()
override fun openUrl(url: String) {
urlOpener.openUrl(url)
}
override fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency) {
router.pop { isSuccess ->
if (isSuccess) {
router.push(
AppRoute.CurrencyDetails(
userWalletId = userWalletId,
currency = currency,
),
)
}
}
}
}

View file

@ -1,8 +1,12 @@
package com.tangem.features.staking.impl.navigation
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.staking.api.navigation.StakingRouter
interface InnerStakingRouter : StakingRouter {
fun openUrl(url: String)
fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency)
}

View file

@ -0,0 +1,186 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.feeScreen.checkAndCalculateSubtractedAmount
import com.tangem.common.ui.feeScreen.checkFeeCoverage
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.common.ui.notifications.NotificationsFactory.addDustWarningNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addExceedBalanceNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addExceedsBalanceNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addExistentialWarningNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addFeeCoverageNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addFeeUnreachableNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountErrorNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification
import com.tangem.common.ui.notifications.NotificationsFactory.addValidateTransactionNotifications
import com.tangem.domain.appcurrency.model.AppCurrency
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.presentation.state.FeeState
import com.tangem.features.staking.impl.presentation.state.StakingStates
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.lib.crypto.BlockchainUtils
import com.tangem.utils.Provider
import com.tangem.utils.extensions.orZero
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.toImmutableList
import java.math.BigDecimal
@Suppress("LongParameterList")
internal class AddStakingNotificationsTransformer(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
private val currencyWarning: CryptoCurrencyWarning?,
private val validatorError: Throwable?,
private val feeError: GetFeeError?,
private val currencyCheck: CryptoCurrencyCheck,
private val isSubtractAvailable: Boolean,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val appCurrency = appCurrencyProvider()
val balance = cryptoCurrencyStatus.value.amount.orZero()
val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
val amountState = prevState.amountState as? AmountState.Data ?: return prevState
val feeState = confirmationState.feeState as? FeeState.Content ?: return prevState
val amountValue = amountState.amountTextField.cryptoAmount.value.orZero()
val feeValue = feeState.fee?.amount?.value.orZero()
val reduceAmountBy = confirmationState.reduceAmountBy.orZero()
val isFeeCoverage = checkFeeCoverage(
amountValue = amountValue,
feeValue = feeValue,
balance = balance,
isSubtractAvailable = isSubtractAvailable,
reduceAmountBy = reduceAmountBy,
)
val sendingAmount = checkAndCalculateSubtractedAmount(
isAmountSubtractAvailable = isSubtractAvailable,
cryptoCurrencyStatus = cryptoCurrencyStatusProvider(),
amountValue = amountValue,
feeValue = feeValue,
reduceAmountBy = reduceAmountBy,
)
val notifications = buildList {
// errors
addErrorNotifications(
prevState = prevState,
feeError = feeError,
sendingAmount = sendingAmount,
onReload = { prevState.clickIntents.loadFee(confirmationState.pendingActions) },
feeValue = feeValue,
)
// warnings
addWarningNotifications(
prevState = prevState,
amountState = amountState,
feeState = feeState,
sendingAmount = sendingAmount,
isFeeCoverage = isFeeCoverage,
)
addAll(confirmationState.notifications)
}.toImmutableList()
return prevState.copy(
confirmationState = confirmationState.copy(
notifications = notifications.toImmutableList(),
),
)
}
private fun MutableList<NotificationUM>.addErrorNotifications(
prevState: StakingUiState,
onReload: () -> Unit,
feeError: GetFeeError?,
sendingAmount: BigDecimal,
feeValue: BigDecimal,
) {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val cryptoCurrency = cryptoCurrencyStatus.currency
val network = cryptoCurrency.network
if (feeError != null) {
addFeeUnreachableNotification(
feeError = feeError,
tokenName = cryptoCurrencyStatusProvider().currency.name,
onReload = onReload,
)
}
addExceedBalanceNotification(
feeAmount = feeValue,
sendingAmount = sendingAmount,
isSubtractionAvailable = isSubtractAvailable,
cryptoCurrencyStatus = cryptoCurrencyStatus,
)
addExceedsBalanceNotification(
cryptoCurrencyWarning = currencyWarning,
cryptoCurrencyStatus = cryptoCurrencyStatus,
shouldMergeFeeNetworkName = BlockchainUtils.isArbitrum(network.backendId),
onClick = prevState.clickIntents::openTokenDetails,
onAnalyticsEvent = { /* [REDACTED_TODO_COMMENT] */ },
)
if (!BlockchainUtils.isCardano(network.id.value)) {
addDustWarningNotification(
dustValue = currencyCheck.dustValue,
feeValue = feeValue,
sendingAmount = sendingAmount,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCryptoCurrencyStatus,
)
}
addTransactionLimitErrorNotification(
utxoLimit = currencyCheck.utxoAmountLimit,
cryptoCurrency = cryptoCurrency,
onReduceClick = prevState.clickIntents::onAmountReduceToClick,
)
addReserveAmountErrorNotification(
reserveAmount = currencyCheck.reserveAmount,
sendingAmount = sendingAmount,
cryptoCurrency = cryptoCurrency,
isAccountFunded = false,
)
}
private fun MutableList<NotificationUM>.addWarningNotifications(
prevState: StakingUiState,
amountState: AmountState.Data,
feeState: FeeState.Content,
sendingAmount: BigDecimal,
isFeeCoverage: Boolean,
) {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val appCurrency = appCurrencyProvider()
val cryptoCurrency = cryptoCurrencyStatus.currency
addExistentialWarningNotification(
existentialDeposit = currencyCheck.existentialDeposit,
feeAmount = feeState.fee?.amount?.value.orZero(),
receivedAmount = sendingAmount,
cryptoCurrencyStatus = cryptoCurrencyStatus,
onReduceClick = prevState.clickIntents::onAmountReduceByClick,
)
addFeeCoverageNotification(
isFeeCoverage = isFeeCoverage,
amountField = amountState.amountTextField,
sendingValue = sendingAmount,
appCurrency = appCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
)
// blockchain specific
addValidateTransactionNotifications(
dustValue = currencyCheck.dustValue.orZero(),
fee = feeState.fee,
validationError = validatorError,
cryptoCurrency = cryptoCurrency,
onReduceClick = prevState.clickIntents::onAmountReduceToClick,
)
}
}

View file

@ -0,0 +1,19 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer.ReduceByData
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountReduceByStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: ReduceByData,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
amountState = AmountReduceByTransformer(cryptoCurrencyStatus, value).transform(prevState.amountState),
)
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.AmountReduceToTransformer
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal
internal class AmountReduceToStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: BigDecimal,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
amountState = AmountReduceToTransformer(cryptoCurrencyStatus, value).transform(prevState.amountState),
)
}
}