Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-16 16:25:07 +05:00
parent 1aee51dc3b
commit 8167dab4f0
16 changed files with 223 additions and 101 deletions

View file

@ -296,7 +296,7 @@ internal class ChildFactory @Inject constructor(
context = context,
params = StakingComponent.Params(
userWalletId = route.userWalletId,
cryptoCurrencyId = route.cryptoCurrencyId,
cryptoCurrency = route.cryptoCurrency,
yieldId = route.yieldId,
),
componentFactory = stakingComponentFactory,

View file

@ -192,9 +192,9 @@ sealed class AppRoute(val path: String) : Route {
@Serializable
data class Staking(
val userWalletId: UserWalletId,
val cryptoCurrencyId: CryptoCurrency.ID,
val cryptoCurrency: CryptoCurrency,
val yieldId: String,
) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrencyId.value}/$yieldId")
) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrency.id.value}/$yieldId")
@Serializable
data class PushNotification(

View file

@ -21,7 +21,7 @@ import com.tangem.core.ui.utils.getGreyScaleColorFilter
* @param onImageError composable to show if image loading failed
*/
@Composable
internal fun InputRowAsyncImage(
fun InputRowAsyncImage(
imageUrl: String,
modifier: Modifier = Modifier,
isGrayscale: Boolean = false,

View file

@ -53,7 +53,7 @@ fun SelectorRowItem(
val textStyle = if (isSelected && showSelectedAppearance) {
TangemTheme.typography.subtitle2
} else {
TangemTheme.typography.body2
TangemTheme.typography.body1
}
Box(
modifier = modifier

View file

@ -172,7 +172,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
router.push(
AppRoute.Staking(
userWalletId = cryptoCurrencyData.userWallet.walletId,
cryptoCurrencyId = cryptoCurrencyData.status.currency.id,
cryptoCurrency = cryptoCurrencyData.status.currency,
yieldId = yield.id,
),
)

View file

@ -9,7 +9,7 @@ interface StakingComponent : ComposableContentComponent {
data class Params(
val userWalletId: UserWalletId,
val cryptoCurrencyId: CryptoCurrency.ID,
val cryptoCurrency: CryptoCurrency,
val yieldId: String,
)

View file

@ -67,6 +67,8 @@ dependencies {
implementation(projects.domain.feedback)
implementation(projects.domain.feedback.models)
implementation(projects.domain.notifications.models)
implementation(projects.domain.account)
implementation(projects.domain.account.status)
/** Common */
implementation(projects.common.ui)

View file

@ -93,7 +93,7 @@ internal class DefaultStakingDeepLinkHandler @AssistedInject constructor(
appRouter.push(
AppRoute.Staking(
userWalletId = selectedUserWalletId,
cryptoCurrencyId = cryptoCurrency.id,
cryptoCurrency = cryptoCurrency,
yieldId = yield.id,
),
)

View file

@ -24,6 +24,9 @@ import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.haptic.VibratorHapticManager
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.core.ui.message.DialogMessage
import com.tangem.features.staking.impl.R
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@ -34,6 +37,7 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.BlockchainErrorInfo
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.staking.*
@ -52,11 +56,7 @@ import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
import com.tangem.domain.staking.utils.getValidatorsCount
import com.tangem.domain.tokens.*
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase
import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.transaction.usecase.*
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.staking.api.StakingComponent
@ -78,9 +78,9 @@ import com.tangem.features.staking.impl.presentation.state.transformers.confirma
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.ton.CompleteInitializeBottomSheetTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeErrorToTonInitializeBottomSheetTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeToTonInitializeBottomSheetTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.ton.ShowTonInitializeBottomSheetTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeErrorToTonInitializeBottomSheetTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.validator.ValidatorSelectChangeTransformer
import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount
import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
@ -139,12 +139,15 @@ internal class StakingModel @Inject constructor(
private val getFeeUseCase: GetFeeUseCase,
private val getNetworkAddressesUseCase: GetNetworkAddressesUseCase,
private val getActionRequirementAmountUseCase: GetActionRequirementAmountUseCase,
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
private val paramsInterceptorHolder: ParamsInterceptorHolder,
private val shareManager: ShareManager,
private val urlOpener: UrlOpener,
@DelayedWork private val coroutineScope: CoroutineScope,
private val innerRouter: InnerStakingRouter,
private val messageSender: UiMessageSender,
private val accountsFeatureToggles: AccountsFeatureToggles,
appRouter: AppRouter,
) : Model(), StakingClickIntents {
@ -159,7 +162,7 @@ internal class StakingModel @Inject constructor(
analyticsEventsHandler = analyticsEventHandler,
)
private val cryptoCurrencyId: CryptoCurrency.ID = params.cryptoCurrencyId
private val cryptoCurrencyId: CryptoCurrency.ID = params.cryptoCurrency.id
private val userWalletId: UserWalletId = params.userWalletId
private val yield: Yield = runBlocking {
getYieldUseCase(params.yieldId).getOrElse {
@ -172,6 +175,8 @@ internal class StakingModel @Inject constructor(
private var stakingActions: List<StakingAction> = emptyList()
private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null
private var minimumTransactionAmount: EnterAmountBoundary? = null
private val isBalanceHiddenFlow: StateFlow<Boolean>
field = MutableStateFlow(false)
private var tonAccountInitializeTransaction: TransactionData.Uncompiled? = null
@ -237,6 +242,9 @@ internal class StakingModel @Inject constructor(
private var isAnyTokenStaked: Boolean = false
private val allowanceTaskScheduler = SingleTaskScheduler<BigDecimal>()
private var isAccountsModeEnabled: Boolean = true
private var account: Account.CryptoPortfolio? = null
private val transactionsInProgress: CopyOnWriteArrayList<StakingTransaction> = CopyOnWriteArrayList()
private var actionsJobHolder: JobHolder = JobHolder()
@ -247,7 +255,6 @@ internal class StakingModel @Inject constructor(
init {
subscribeOnSelectedAppCurrency()
subscribeOnBalanceHiding()
subscribeOnCurrencyStatusUpdates()
stateController.initializeWithUserWallet(userWallet)
}
@ -297,6 +304,9 @@ internal class StakingModel @Inject constructor(
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
userWalletProvider = Provider { userWallet },
appCurrencyProvider = Provider { appCurrency },
isBalanceHidden = isBalanceHiddenFlow.value,
isAccountsModeEnabled = isAccountsModeEnabled,
account = account,
).let(::add)
AmountMaxValueStateTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatus,
@ -1012,10 +1022,12 @@ internal class StakingModel @Inject constructor(
)
},
ifRight = {
stateController.update(CompleteInitializeBottomSheetTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatus,
minimumTransactionAmount = minimumTransactionAmount,
))
stateController.update(
CompleteInitializeBottomSheetTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatus,
minimumTransactionAmount = minimumTransactionAmount,
),
)
balanceUpdater.partialUpdateWithDelay()
stateController.update(DismissBottomSheetStateTransformer)
@ -1045,72 +1057,89 @@ internal class StakingModel @Inject constructor(
}
private fun subscribeOnCurrencyStatusUpdates() {
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
userWalletId = userWalletId,
currencyId = cryptoCurrencyId,
isSingleWalletWithTokens = false,
)
.conflate()
.distinctUntilChanged()
.filter {
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
}
.onEach { maybeStatus ->
maybeStatus.fold(
ifRight = { status ->
if (!isInitialInfoAnalyticSent) {
isInitialInfoAnalyticSent = true
val balances = status.value.yieldBalance as? YieldBalance.Data
paramsInterceptorHolder.addParamsInterceptor(
interceptor = StakingParamsInterceptor(status.currency.symbol),
if (accountsFeatureToggles.isFeatureEnabled) {
getAccountCurrencyStatusUseCase(
userWalletId = params.userWalletId,
currency = params.cryptoCurrency,
).conflate().distinctUntilChanged()
.filter {
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
}.onEach { (maybeAccount, maybeStatus) ->
isAccountsModeEnabled = isAccountsModeEnabledUseCase.invokeSync()
account = maybeAccount
onDataLoaded(maybeStatus)
}.flowOn(dispatchers.main)
.launchIn(modelScope)
} else {
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
userWalletId = userWalletId,
currencyId = cryptoCurrencyId,
isSingleWalletWithTokens = false,
).conflate().distinctUntilChanged()
.filter {
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
}
.onEach { maybeStatus ->
maybeStatus.fold(
ifRight = { onDataLoaded(it) },
ifLeft = { error ->
stakingEventFactory.createGenericErrorAlert(error.toString())
stateController.update(
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
)
analyticsEventHandler.send(
StakingAnalyticsEvent.StakingInfoScreenOpened(
validatorsCount = balances?.getValidatorsCount() ?: 0,
),
)
}
},
)
}.flowOn(dispatchers.main)
.launchIn(modelScope)
}
}
feeCryptoCurrencyStatus =
getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull()
minimumTransactionAmount =
getMinimumTransactionAmountSyncUseCase(userWalletId, status).getOrNull()?.let {
EnterAmountBoundary(
amount = it,
fiatRate = status.value.fiatRate.orZero(),
)
}
cryptoCurrencyStatus = status
private suspend fun onDataLoaded(status: CryptoCurrencyStatus) {
if (value.currentStep != StakingStep.InitialInfo) return
val isAccountInitializedNew = checkAccountInitializedUseCase.invoke(
userWalletId = userWalletId,
network = cryptoCurrencyStatus.currency.network,
).getOrElse {
Timber.e(it)
false
}
if (isAccountInitializedNew && !isAccountInitialized) {
isAccountInitialized = true
updateNotifications()
}
isAccountInitialized = isAccountInitializedNew
if (!isInitialInfoAnalyticSent) {
isInitialInfoAnalyticSent = true
val balances = status.value.yieldBalance as? YieldBalance.Data
paramsInterceptorHolder.addParamsInterceptor(
interceptor = StakingParamsInterceptor(status.currency.symbol),
)
analyticsEventHandler.send(
StakingAnalyticsEvent.StakingInfoScreenOpened(
validatorsCount = balances?.getValidatorsCount() ?: 0,
),
)
}
setupApprovalNeeded()
setupIsAnyTokenStaked()
checkIfSubtractAvailable()
subscribeOnActionsUpdates(status)
subscribeOnStepChanges(status)
},
ifLeft = { error ->
stakingEventFactory.createGenericErrorAlert(error.toString())
stateController.update(
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
)
},
feeCryptoCurrencyStatus =
getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull()
minimumTransactionAmount =
getMinimumTransactionAmountSyncUseCase(userWalletId, status).getOrNull()?.let {
EnterAmountBoundary(
amount = it,
fiatRate = status.value.fiatRate.orZero(),
)
}
.flowOn(dispatchers.main)
.launchIn(modelScope)
cryptoCurrencyStatus = status
val isAccountInitializedNew = checkAccountInitializedUseCase.invoke(
userWalletId = userWalletId,
network = cryptoCurrencyStatus.currency.network,
).getOrElse {
Timber.e(it)
false
}
if (isAccountInitializedNew && !isAccountInitialized) {
isAccountInitialized = true
updateNotifications()
}
isAccountInitialized = isAccountInitializedNew
setupApprovalNeeded()
setupIsAnyTokenStaked()
checkIfSubtractAvailable()
subscribeOnActionsUpdates(status)
subscribeOnStepChanges(status)
subscribeOnBalanceHiding()
}
private fun subscribeOnBalanceHiding() {
@ -1118,7 +1147,14 @@ internal class StakingModel @Inject constructor(
.conflate()
.distinctUntilChanged()
.onEach {
stateController.update(transformer = HideBalanceStateTransformer(it.isBalanceHidden))
isBalanceHiddenFlow.value = it.isBalanceHidden
stateController.update(
transformer = HideBalanceStateTransformer(
isBalanceHidden = it.isBalanceHidden,
cryptoCurrencyStatus = cryptoCurrencyStatus,
appCurrency = appCurrency,
),
)
}
.flowOn(dispatchers.main)
.launchIn(modelScope)
@ -1193,6 +1229,9 @@ internal class StakingModel @Inject constructor(
userWalletProvider = Provider { userWallet },
appCurrencyProvider = Provider { appCurrency },
balancesToShowProvider = Provider { balancesToShow },
isAccountsModeEnabled = isAccountsModeEnabled,
account = account,
isBalanceHidden = isBalanceHiddenFlow.value,
),
SetConfirmationStateEmptyTransformer,
)
@ -1227,6 +1266,9 @@ internal class StakingModel @Inject constructor(
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
userWalletProvider = Provider { userWallet },
appCurrencyProvider = Provider { appCurrency },
isAccountsModeEnabled = isAccountsModeEnabled,
isBalanceHidden = isBalanceHiddenFlow.value,
account = account,
),
AmountChangeStateTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatus,

View file

@ -1,13 +1,40 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.common.ui.amountScreen.converters.field.AmountBoundaryUpdateTransformer
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class HideBalanceStateTransformer(
private val isBalanceHidden: Boolean,
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val appCurrency: AppCurrency,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(isBalanceHidden = isBalanceHidden)
val cryptoBalanceValue = cryptoCurrencyStatus.value
val (amount, fiatAmount) = if (prevState.actionType !is StakingActionCommonType.Enter) {
prevState.balanceState?.cryptoAmount to prevState.balanceState?.fiatAmount
} else {
cryptoBalanceValue.amount to cryptoBalanceValue.fiatAmount
}
val maxEnterAmount = EnterAmountBoundary(
amount = amount,
fiatAmount = fiatAmount,
fiatRate = cryptoBalanceValue.fiatRate,
)
return prevState.copy(
isBalanceHidden = isBalanceHidden,
amountState = AmountBoundaryUpdateTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatus,
maxEnterAmount = maxEnterAmount,
appCurrency = appCurrency,
isBalanceHidden = isBalanceHidden,
).transform(prevState.amountState),
)
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.amountScreen.converters.AmountAccountConverter
import com.tangem.common.ui.amountScreen.converters.AmountStateConverter
import com.tangem.common.ui.amountScreen.models.AmountParameters
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
@ -8,6 +9,7 @@ import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIco
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
@ -17,20 +19,28 @@ import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.Provider
import com.tangem.utils.transformer.Transformer
@Suppress("LongParameterList")
internal class SetAmountDataTransformer(
private val clickIntents: StakingClickIntents,
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
private val userWalletProvider: Provider<UserWallet>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val isBalanceHidden: Boolean,
private val isAccountsModeEnabled: Boolean,
private val account: Account.CryptoPortfolio?,
) : Transformer<StakingUiState> {
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
override fun transform(prevState: StakingUiState): StakingUiState {
val title = if (prevState.actionType is StakingActionCommonType.Exit) {
resourceReference(R.string.staking_staked_amount)
} else {
stringReference(userWalletProvider().name)
val accountTitleUM = when (prevState.actionType) {
is StakingActionCommonType.Exit -> AccountTitleUM.Text(resourceReference(R.string.staking_staked_amount))
is StakingActionCommonType.Enter -> AmountAccountConverter(
isAccountsMode = isAccountsModeEnabled,
walletTitle = stringReference(userWalletProvider().name),
prefixText = resourceReference(R.string.common_from),
).convert(account)
else -> AccountTitleUM.Text(resourceReference(R.string.common_amount))
}
val cryptoBalanceValue = cryptoCurrencyStatusProvider().value
val (amount, fiatAmount) = if (prevState.actionType !is StakingActionCommonType.Enter) {
@ -51,11 +61,11 @@ internal class SetAmountDataTransformer(
maxEnterAmount = maxEnterAmount,
appCurrency = appCurrencyProvider(),
cryptoCurrencyStatus = cryptoCurrencyStatusProvider(),
isBalanceHidden = false,
accountTitleUM = AccountTitleUM.Text(title),
isBalanceHidden = isBalanceHidden,
accountTitleUM = accountTitleUM,
).convert(
AmountParameters(
title = title,
title = stringReference(userWalletProvider().name),
value = "",
),
),

View file

@ -2,7 +2,7 @@ package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.remove
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.amountScreen.converters.AmountAccountConverter
import com.tangem.common.ui.amountScreen.converters.AmountStateConverter
import com.tangem.common.ui.amountScreen.models.AmountParameters
import com.tangem.common.ui.amountScreen.models.AmountState
@ -15,6 +15,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto
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.account.Account
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.staking.BalanceItem
import com.tangem.domain.models.wallet.UserWallet
@ -46,6 +47,9 @@ internal class SetInitialDataStateTransformer(
private val userWalletProvider: Provider<UserWallet>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val balancesToShowProvider: Provider<List<BalanceItem>>,
private val isAccountsModeEnabled: Boolean,
private val account: Account.CryptoPortfolio?,
private val isBalanceHidden: Boolean,
) : Transformer<StakingUiState> {
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
@ -234,8 +238,12 @@ internal class SetInitialDataStateTransformer(
appCurrency = appCurrencyProvider(),
iconStateConverter = iconStateConverter,
maxEnterAmount = maxEnterAmount,
isBalanceHidden = false,
accountTitleUM = AccountTitleUM.Text(stringReference(userWalletProvider().name)),
isBalanceHidden = isBalanceHidden,
accountTitleUM = AmountAccountConverter(
isAccountsMode = isAccountsModeEnabled,
walletTitle = stringReference(userWalletProvider().name),
prefixText = resourceReference(R.string.common_from),
).convert(account),
).convert(
AmountParameters(
title = stringReference(userWalletProvider().name),

View file

@ -48,6 +48,7 @@ internal fun StakingFeeBlock(feeState: FeeState) {
text = stringResourceSafe(R.string.common_network_fee_title),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing4),
)
Box(modifier = Modifier.padding(top = TangemTheme.dimens.spacing8)) {

View file

@ -3,15 +3,23 @@ package com.tangem.features.staking.impl.presentation.ui.block
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.components.inputrow.InputRowImageInfo
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.inputrow.inner.InputRowAsyncImage
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.format.bigdecimal.percent
@ -42,13 +50,37 @@ internal fun ValidatorBlock(validatorState: StakingStates.ValidatorState, isClic
)
.testTag(StakingSendDetailsScreenTestTags.VALIDATOR_BLOCK),
) {
InputRowImageInfo(
title = resourceReference(R.string.staking_validator),
subtitle = stringReference(state.chosenValidator.name),
infoTitle = state.getInfoTitleNeutral(),
imageUrl = state.chosenValidator.image.orEmpty(),
onImageError = { ValidatorImagePlaceholder() },
Text(
text = stringResourceSafe(R.string.staking_validator),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.padding(start = 12.dp, top = 12.dp, end = 12.dp, bottom = 4.dp),
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(12.dp),
) {
InputRowAsyncImage(
imageUrl = validatorState.chosenValidator.image.orEmpty(),
onImageError = { ValidatorImagePlaceholder() },
modifier = Modifier
.size(24.dp)
.clip(TangemTheme.shapes.roundedCornersXLarge),
)
Text(
text = validatorState.chosenValidator.name,
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
SpacerWMax()
Text(
text = validatorState.getInfoTitleNeutral().resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.tertiary,
)
}
}
}

View file

@ -41,7 +41,7 @@ internal class DefaultTokenDetailsRouter @Inject constructor(
router.push(
AppRoute.Staking(
userWalletId = userWalletId,
cryptoCurrencyId = cryptoCurrency.id,
cryptoCurrency = cryptoCurrency,
yieldId = yieldId,
),
)

View file

@ -507,7 +507,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
appRouter.push(
AppRoute.Staking(
userWalletId = userWalletId,
cryptoCurrencyId = cryptoCurrency.id,
cryptoCurrency = cryptoCurrency,
yieldId = yield?.id ?: return@launch,
),
)