Updated on 2026-08-14
This commit is contained in:
parent
2d8d9453bd
commit
f916d7394b
21 changed files with 559 additions and 153 deletions
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.features.staking.impl.presentation.state
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.staking.model.BalanceType
|
||||
import com.tangem.domain.staking.model.Yield
|
||||
|
||||
sealed class InnerYieldBalanceState {
|
||||
data class Data(
|
||||
val rewardsCrypto: String,
|
||||
val rewardsFiat: String,
|
||||
val isRewardsToClaim: Boolean,
|
||||
val balance: List<BalanceGroupedState>,
|
||||
) : InnerYieldBalanceState()
|
||||
|
||||
data object Empty : InnerYieldBalanceState()
|
||||
}
|
||||
|
||||
data class BalanceGroupedState(
|
||||
val items: List<BalanceState>,
|
||||
val type: BalanceType,
|
||||
val footer: TextReference?,
|
||||
val title: TextReference,
|
||||
)
|
||||
|
||||
data class BalanceState(
|
||||
val validator: Yield.Validator,
|
||||
val cryptoAmount: TextReference,
|
||||
val fiatAmount: TextReference,
|
||||
val rawCurrencyId: String?,
|
||||
)
|
||||
|
|
@ -53,6 +53,7 @@ internal sealed class StakingStates {
|
|||
val warmupPeriod: String,
|
||||
val rewardSchedule: String,
|
||||
val onInfoClick: (InfoType) -> Unit,
|
||||
val yieldBalance: InnerYieldBalanceState,
|
||||
) : InitialInfoState()
|
||||
|
||||
data class Empty(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.previewdata
|
||||
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.staking.model.BalanceType
|
||||
import com.tangem.domain.staking.model.Yield
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceGroupedState
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
|
||||
internal object InitialStakingStatePreview {
|
||||
val defaultState = StakingStates.InitialInfoState.Data(
|
||||
isPrimaryButtonEnabled = true,
|
||||
available = "15 SOL",
|
||||
onStake = "0 SOL",
|
||||
aprRange = stringReference("2.54-5.12%"),
|
||||
unbondingPeriod = "3d",
|
||||
minimumRequirement = "12 SOL",
|
||||
rewardClaiming = "Auto",
|
||||
warmupPeriod = "Days",
|
||||
rewardSchedule = "Block",
|
||||
onInfoClick = {},
|
||||
yieldBalance = InnerYieldBalanceState.Empty,
|
||||
)
|
||||
|
||||
val stateWithYield = defaultState.copy(
|
||||
yieldBalance = InnerYieldBalanceState.Data(
|
||||
rewardsFiat = "100 $",
|
||||
rewardsCrypto = "100 SOL",
|
||||
isRewardsToClaim = false,
|
||||
balance = listOf(
|
||||
BalanceGroupedState(
|
||||
type = BalanceType.STAKED,
|
||||
title = stringReference("Staked"),
|
||||
footer = null,
|
||||
items = listOf(
|
||||
BalanceState(
|
||||
cryptoAmount = stringReference("100 SOL"),
|
||||
fiatAmount = stringReference("100 $"),
|
||||
rawCurrencyId = null,
|
||||
validator = Yield.Validator(
|
||||
address = "address",
|
||||
status = "status",
|
||||
name = "Binance",
|
||||
image = null,
|
||||
website = null,
|
||||
apr = "5".toBigDecimal(),
|
||||
commission = null,
|
||||
stakedBalance = null,
|
||||
votingPower = null,
|
||||
preferred = false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -9,17 +9,19 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.BalanceType
|
||||
import com.tangem.domain.staking.model.Yield
|
||||
import com.tangem.domain.staking.model.YieldBalance
|
||||
import com.tangem.domain.staking.model.YieldBalanceItem
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStep
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.ValidatorState
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData
|
||||
import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.isNullOrZero
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -55,15 +57,20 @@ internal class SetInitialDataStateTransformer(
|
|||
|
||||
private fun createInitialInfoState(): StakingStates.InitialInfoState.Data {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance
|
||||
|
||||
return StakingStates.InitialInfoState.Data(
|
||||
isPrimaryButtonEnabled = true,
|
||||
available = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoCurrencyStatus.value.amount,
|
||||
cryptoAmount = cryptoCurrencyStatus.value.amount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
onStake = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = (yieldBalance as? YieldBalance.Data)?.getTotalStakingBalance().orZero(),
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
onStake = "0 SOL", // TODO staking add after adding /balances request
|
||||
aprRange = getAprRange(),
|
||||
unbondingPeriod = yield.metadata.cooldownPeriod.days.toString(),
|
||||
minimumRequirement = yield.metadata.minimumStake.toString(),
|
||||
|
|
@ -71,6 +78,7 @@ internal class SetInitialDataStateTransformer(
|
|||
warmupPeriod = yield.metadata.warmupPeriod.days.toString(),
|
||||
rewardSchedule = yield.metadata.rewardSchedule,
|
||||
onInfoClick = clickIntents::onInfoClick,
|
||||
yieldBalance = getStakedBalances(cryptoCurrencyStatus),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -108,6 +116,96 @@ internal class SetInitialDataStateTransformer(
|
|||
return resourceReference(R.string.common_range, wrappedList(formattedMinApr, formattedMaxApr))
|
||||
}
|
||||
|
||||
private fun getStakedBalances(cryptoCurrencyStatus: CryptoCurrencyStatus): InnerYieldBalanceState {
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance
|
||||
return if (yieldBalance is YieldBalance.Data) {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
val cryptoRewardsValue = yieldBalance.getRewardStakingBalance()
|
||||
val fiatRewardsValue = cryptoCurrencyStatus.value.fiatRate?.times(cryptoRewardsValue)
|
||||
val groupedBalances = getGroupedBalance(yieldBalance.balance, cryptoCurrencyStatus, appCurrency)
|
||||
|
||||
InnerYieldBalanceState.Data(
|
||||
rewardsCrypto = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = cryptoRewardsValue,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
),
|
||||
rewardsFiat = BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = fiatRewardsValue,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
),
|
||||
isRewardsToClaim = !cryptoRewardsValue.isNullOrZero(),
|
||||
balance = groupedBalances,
|
||||
)
|
||||
} else {
|
||||
InnerYieldBalanceState.Empty
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGroupedBalance(
|
||||
balance: YieldBalanceItem,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
appCurrency: AppCurrency,
|
||||
) = balance.items
|
||||
.sortedByDescending { it.type }
|
||||
.groupBy { it.type }
|
||||
.mapNotNull { item ->
|
||||
val (title, footer) = getValidatorBalanceInto(item.key)
|
||||
|
||||
val balances = item.value.mapNotNull { balance ->
|
||||
val validator = yield.validators.firstOrNull {
|
||||
balance.validatorAddress?.contains(it.address, ignoreCase = true) == true
|
||||
}
|
||||
val cryptoAmount = balance.amount * balance.pricePerShare
|
||||
val fiatAmount = cryptoCurrencyStatus.value.fiatRate?.times(cryptoAmount)
|
||||
|
||||
validator?.let {
|
||||
BalanceState(
|
||||
validator = validator,
|
||||
cryptoAmount = stringReference(
|
||||
BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = balance.amount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
),
|
||||
),
|
||||
fiatAmount = stringReference(
|
||||
BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = fiatAmount,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
),
|
||||
),
|
||||
rawCurrencyId = balance.rawCurrencyId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
title?.let {
|
||||
BalanceGroupedState(
|
||||
items = balances,
|
||||
type = item.key,
|
||||
footer = footer,
|
||||
title = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getValidatorBalanceInto(type: BalanceType) = when (type) {
|
||||
BalanceType.PREPARING,
|
||||
BalanceType.STAKED,
|
||||
-> resourceReference(R.string.staking_active) to resourceReference(R.string.staking_active_footer)
|
||||
BalanceType.UNSTAKING,
|
||||
BalanceType.UNLOCKING,
|
||||
BalanceType.UNSTAKED,
|
||||
-> resourceReference(R.string.staking_unstaked) to resourceReference(R.string.staking_unstaked_footer)
|
||||
BalanceType.AVAILABLE,
|
||||
BalanceType.LOCKED,
|
||||
BalanceType.UNKNOWN,
|
||||
BalanceType.REWARDS,
|
||||
-> null to null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val EQUALITY_THRESHOLD = BigDecimal(1E-10)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
|
|
@ -11,36 +13,64 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
import com.tangem.core.ui.components.inputrow.InputRowDefault
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageInfo
|
||||
import com.tangem.core.ui.components.rows.CornersToRound
|
||||
import com.tangem.core.ui.components.rows.RoundableCornersRow
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceGroupedState
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.previewdata.InitialStakingStatePreview
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.InfoType
|
||||
import com.tangem.utils.Strings.DOT
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
@Composable
|
||||
internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState) {
|
||||
if (state !is StakingStates.InitialInfoState.Data) return
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
modifier = Modifier // Do not put fillMaxSize() in here
|
||||
.background(TangemTheme.colors.background.tertiary)
|
||||
.padding(TangemTheme.dimens.spacing16)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
MetricsBlock(state)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
AnimatedVisibility(state.yieldBalance == InnerYieldBalanceState.Empty) {
|
||||
MetricsBlock(state)
|
||||
}
|
||||
StakingDetailsRows(state)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
AnimatedContent(targetState = state.yieldBalance, label = "Rewards block visibility animation") {
|
||||
if (it is InnerYieldBalanceState.Data) {
|
||||
StakingRewardBlock(
|
||||
rewardCrypto = it.rewardsCrypto,
|
||||
rewardFiat = it.rewardsFiat,
|
||||
isRewardsToClaim = it.isRewardsToClaim,
|
||||
)
|
||||
}
|
||||
}
|
||||
AnimatedContent(targetState = state.yieldBalance, label = "Rewards block visibility animation") {
|
||||
if (it is InnerYieldBalanceState.Data) {
|
||||
ActiveStakingBlock(it.balance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +82,7 @@ private fun MetricsBlock(state: StakingStates.InitialInfoState.Data) {
|
|||
color = TangemTheme.colors.background.primary,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens.radius12),
|
||||
)
|
||||
.padding(16.dp)
|
||||
.padding(TangemTheme.dimens.spacing12)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
|
|
@ -60,7 +90,7 @@ private fun MetricsBlock(state: StakingStates.InitialInfoState.Data) {
|
|||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(TangemTheme.dimens.size8))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
|
|
@ -108,53 +138,117 @@ private fun MetricsBlock(state: StakingStates.InitialInfoState.Data) {
|
|||
|
||||
@Composable
|
||||
internal fun StakingDetailsRows(state: StakingStates.InitialInfoState.Data) {
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_available),
|
||||
endText = state.available,
|
||||
cornersToRound = CornersToRound.TOP_2,
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_on_stake),
|
||||
endText = state.onStake,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_apy),
|
||||
endText = state.aprRange.resolveReference(),
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.APY) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_unbonding_period),
|
||||
endText = state.unbondingPeriod,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.UNBOUNDING_PERIOD) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_minimum_requirement),
|
||||
endText = state.minimumRequirement,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_reward_claiming),
|
||||
endText = state.rewardClaiming,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.REWARD_CLAIMING) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_warmup_period),
|
||||
endText = state.warmupPeriod,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.WARMUP_PERIOD) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_reward_schedule),
|
||||
endText = state.rewardSchedule,
|
||||
cornersToRound = CornersToRound.BOTTOM_2,
|
||||
iconClick = { state.onInfoClick(InfoType.REWARD_SCHEDULE) },
|
||||
Column {
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_available),
|
||||
endText = state.available,
|
||||
cornersToRound = CornersToRound.TOP_2,
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_on_stake),
|
||||
endText = state.onStake,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_apy),
|
||||
endText = state.aprRange.resolveReference(),
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.APY) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_unbonding_period),
|
||||
endText = state.unbondingPeriod,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.UNBOUNDING_PERIOD) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_minimum_requirement),
|
||||
endText = state.minimumRequirement,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_reward_claiming),
|
||||
endText = state.rewardClaiming,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.REWARD_CLAIMING) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_warmup_period),
|
||||
endText = state.warmupPeriod,
|
||||
cornersToRound = CornersToRound.ZERO,
|
||||
iconClick = { state.onInfoClick(InfoType.WARMUP_PERIOD) },
|
||||
)
|
||||
InitialInfoContentRow(
|
||||
startText = stringResource(id = R.string.staking_details_reward_schedule),
|
||||
endText = state.rewardSchedule,
|
||||
cornersToRound = CornersToRound.BOTTOM_2,
|
||||
iconClick = { state.onInfoClick(InfoType.REWARD_SCHEDULE) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StakingRewardBlock(rewardCrypto: String, rewardFiat: String, isRewardsToClaim: Boolean) {
|
||||
val (text, textColor) = if (isRewardsToClaim) {
|
||||
annotatedReference(
|
||||
buildAnnotatedString {
|
||||
append("+")
|
||||
appendSpace()
|
||||
append(rewardFiat)
|
||||
appendSpace()
|
||||
append(DOT)
|
||||
appendSpace()
|
||||
append(rewardCrypto)
|
||||
},
|
||||
) to TangemTheme.colors.text.primary1
|
||||
} else {
|
||||
resourceReference(R.string.staking_details_no_rewards_to_claim) to TangemTheme.colors.text.tertiary
|
||||
}
|
||||
InputRowDefault(
|
||||
title = resourceReference(R.string.staking_rewards),
|
||||
text = text,
|
||||
iconRes = R.drawable.ic_chevron_right_24,
|
||||
textColor = textColor,
|
||||
modifier = Modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.action),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActiveStakingBlock(groupes: List<BalanceGroupedState>) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
groupes.forEach { group ->
|
||||
FooterContainer(
|
||||
footer = group.footer?.resolveReference(),
|
||||
modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.action),
|
||||
) {
|
||||
group.items.forEachIndexed { index, balance ->
|
||||
InputRowImageInfo(
|
||||
title = group.title.takeIf { index == 0 },
|
||||
subtitle = stringReference(balance.validator.name),
|
||||
caption = stringReference(
|
||||
BigDecimalFormatter.formatPercent(balance.validator.apr.orZero(), true),
|
||||
),
|
||||
infoTitle = balance.fiatAmount,
|
||||
infoSubtitle = balance.cryptoAmount,
|
||||
imageUrl = balance.validator.image.orEmpty(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InitialInfoContentRow(
|
||||
startText: String,
|
||||
|
|
@ -191,18 +285,8 @@ private fun StakingInitialInfoContent_Preview(
|
|||
private class StakingInitialInfoContentPreviewProvider : PreviewParameterProvider<StakingStates.InitialInfoState.Data> {
|
||||
override val values: Sequence<StakingStates.InitialInfoState.Data>
|
||||
get() = sequenceOf(
|
||||
StakingStates.InitialInfoState.Data(
|
||||
isPrimaryButtonEnabled = true,
|
||||
available = "15 SOL",
|
||||
onStake = "0 SOL",
|
||||
aprRange = stringReference("2.54-5.12%"),
|
||||
unbondingPeriod = "3d",
|
||||
minimumRequirement = "12 SOL",
|
||||
rewardClaiming = "Auto",
|
||||
warmupPeriod = "Days",
|
||||
rewardSchedule = "Block",
|
||||
onInfoClick = {},
|
||||
),
|
||||
InitialStakingStatePreview.defaultState,
|
||||
InitialStakingStatePreview.stateWithYield,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -25,6 +25,7 @@ import com.tangem.core.ui.components.buttons.common.TangemButton
|
|||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStep
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
|
|
@ -49,12 +50,9 @@ internal fun StakingNavigationButtons(uiState: StakingUiState, modifier: Modifie
|
|||
@Composable
|
||||
private fun StakingNavigationButton(uiState: StakingUiState, modifier: Modifier = Modifier) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
val confirmState = uiState.confirmStakingState
|
||||
val isSuccess = (confirmState as? StakingStates.ConfirmStakingState.Data)?.isSuccess ?: false
|
||||
val isStaking = (confirmState as? StakingStates.ConfirmStakingState.Data)?.isStaking ?: false
|
||||
|
||||
val isButtonsVisible = uiState.currentStep != StakingStep.Success
|
||||
val isStakingState = uiState.currentStep == StakingStep.Success && !isSuccess && !isStaking
|
||||
val isButtonsVisible = isPrevButtonVisible(uiState.currentStep)
|
||||
val isStakingState = uiState.currentStep == StakingStep.Confirm
|
||||
|
||||
val (buttonTextId, buttonClick) = getButtonData(
|
||||
currentState = uiState,
|
||||
|
|
@ -103,15 +101,32 @@ private fun StakingNavigationButton(uiState: StakingUiState, modifier: Modifier
|
|||
|
||||
private fun getButtonData(currentState: StakingUiState): Pair<Int, () -> Unit> {
|
||||
return when (currentState.currentStep) {
|
||||
StakingStep.InitialInfo,
|
||||
StakingStep.InitialInfo -> {
|
||||
val initialState = currentState.initialInfoState as? StakingStates.InitialInfoState.Data
|
||||
if (initialState?.yieldBalance is InnerYieldBalanceState.Data) {
|
||||
R.string.staking_stake_more to currentState.clickIntents::onNextClick
|
||||
} else {
|
||||
R.string.common_next to currentState.clickIntents::onNextClick
|
||||
}
|
||||
}
|
||||
StakingStep.Amount,
|
||||
StakingStep.Confirm,
|
||||
StakingStep.Success,
|
||||
-> R.string.common_next to currentState.clickIntents::onNextClick
|
||||
StakingStep.Confirm -> R.string.common_stake to currentState.clickIntents::onNextClick
|
||||
StakingStep.Validators -> R.string.common_continue to currentState.clickIntents::onNextClick
|
||||
StakingStep.Success -> R.string.common_close to currentState.clickIntents::onBackClick
|
||||
}
|
||||
}
|
||||
|
||||
private fun isPrevButtonVisible(step: StakingStep): Boolean = when (step) {
|
||||
StakingStep.InitialInfo,
|
||||
StakingStep.Confirm,
|
||||
StakingStep.Success,
|
||||
-> false
|
||||
StakingStep.Amount,
|
||||
StakingStep.Validators,
|
||||
-> true
|
||||
}
|
||||
|
||||
private fun isButtonEnabled(uiState: StakingUiState): Boolean {
|
||||
return when (uiState.currentStep) {
|
||||
StakingStep.InitialInfo -> uiState.initialInfoState.isPrimaryButtonEnabled
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue