Updated on 2026-08-14
This commit is contained in:
parent
471343e66b
commit
d9a539b64d
11 changed files with 287 additions and 62 deletions
|
|
@ -20,6 +20,8 @@ import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
|||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardTypeShortText
|
||||
import com.tangem.features.staking.impl.presentation.ui.utils.toDrawableRes
|
||||
import com.tangem.features.staking.impl.presentation.ui.utils.toImageUrl
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
@Composable
|
||||
|
|
@ -42,7 +44,8 @@ internal fun StakingClaimRewardsValidatorContent(
|
|||
caption = item.getAprTextNeutral(),
|
||||
infoTitle = item.formattedFiatAmount,
|
||||
infoSubtitle = item.formattedCryptoAmount,
|
||||
imageUrl = item.target?.image.orEmpty(),
|
||||
imageUrl = item.target?.image.toImageUrl(),
|
||||
iconRes = item.target?.image.toDrawableRes(),
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(index, state.rewards.lastIndex, false)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.clickable
|
|||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
|
|
@ -19,7 +20,10 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
|
|
@ -32,9 +36,9 @@ import androidx.compose.ui.unit.Density
|
|||
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
|
||||
import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerW12
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||
import com.tangem.core.ui.components.inputrow.InputRowDefault
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageInfo
|
||||
import com.tangem.core.ui.components.list.roundedListWithDividersItems
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.*
|
||||
|
|
@ -55,6 +59,7 @@ 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.stub.StakingClickIntentsStub
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardTypeShortText
|
||||
import com.tangem.features.staking.impl.presentation.ui.utils.toImageReference
|
||||
import com.tangem.utils.StringsSigns.DOT
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
|
|
@ -275,16 +280,9 @@ private fun ActiveStakingBlock(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val (icon, iconTint) = balance.type.getIcon()
|
||||
InputRowImageInfo(
|
||||
subtitle = balance.title,
|
||||
caption = balance.subtitle ?: balance.getAprTextNeutral(),
|
||||
infoTitle = balance.formattedFiatAmount.orMaskWithStars(isBalanceHidden),
|
||||
infoSubtitle = balance.formattedCryptoAmount.orMaskWithStars(isBalanceHidden),
|
||||
imageUrl = balance.getImage(),
|
||||
iconRes = icon,
|
||||
iconTint = iconTint,
|
||||
subtitleEndIconRes = R.drawable.ic_staking_pending_transaction.takeIf { balance.isPending },
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable(
|
||||
|
|
@ -295,8 +293,96 @@ private fun ActiveStakingBlock(
|
|||
onAnalytic()
|
||||
onClick(balance)
|
||||
},
|
||||
),
|
||||
)
|
||||
)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
StakingBalanceIcon(
|
||||
balance = balance,
|
||||
icon = icon,
|
||||
iconTint = iconTint,
|
||||
)
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row {
|
||||
Text(
|
||||
text = balance.title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
if (balance.isPending) {
|
||||
Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing4))
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
image = ImageVector.vectorResource(id = R.drawable.ic_staking_pending_transaction),
|
||||
),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(TangemTheme.dimens.size18),
|
||||
)
|
||||
}
|
||||
}
|
||||
val caption = balance.subtitle ?: balance.getAprTextNeutral()
|
||||
Text(
|
||||
text = caption.resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing2),
|
||||
)
|
||||
}
|
||||
|
||||
SpacerW12()
|
||||
|
||||
Column(horizontalAlignment = Alignment.End) {
|
||||
Text(
|
||||
text = balance.formattedFiatAmount.orMaskWithStars(isBalanceHidden).resolveReference(),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
if (balance.formattedCryptoAmount != null) {
|
||||
Text(
|
||||
text = balance.formattedCryptoAmount.orMaskWithStars(isBalanceHidden).resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing2),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.StakingBalanceIcon(balance: BalanceState, icon: Int?, iconTint: Color) {
|
||||
if (balance.hasImage() || icon != null) {
|
||||
StakingTargetIcon(
|
||||
image = if (balance.hasImage()) balance.target?.image.toImageReference() else null,
|
||||
onImageError = if (icon != null) {
|
||||
{
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.spacing36)
|
||||
.clip(TangemTheme.shapes.roundedCornersXLarge)
|
||||
.background(iconTint.copy(alpha = 0.08f)),
|
||||
) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
image = ImageVector.vectorResource(id = icon),
|
||||
),
|
||||
tint = iconTint,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(TangemTheme.dimens.size18),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
{ ValidatorImagePlaceholder() }
|
||||
},
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.spacing36)
|
||||
.clip(TangemTheme.shapes.roundedCornersXLarge),
|
||||
)
|
||||
SpacerW12()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -341,13 +427,12 @@ private fun BalanceType.getIcon() = when (this) {
|
|||
else -> null to TangemTheme.colors.icon.informative
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BalanceState.getImage() = when (type) {
|
||||
private fun BalanceState.hasImage() = when (type) {
|
||||
BalanceType.UNSTAKING,
|
||||
BalanceType.UNSTAKED,
|
||||
BalanceType.LOCKED,
|
||||
-> null
|
||||
else -> target?.image
|
||||
-> false
|
||||
else -> target?.image != null
|
||||
}
|
||||
|
||||
private val textGradientColors = listOf(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.tangem.core.ui.components.inputrow.inner.InputRowAsyncImage
|
||||
import com.tangem.core.ui.extensions.ImageReference
|
||||
|
||||
@Composable
|
||||
internal fun StakingTargetIcon(
|
||||
image: ImageReference?,
|
||||
modifier: Modifier = Modifier,
|
||||
onImageError: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
when (image) {
|
||||
is ImageReference.Url -> {
|
||||
InputRowAsyncImage(
|
||||
imageUrl = image.url,
|
||||
onImageError = onImageError,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
is ImageReference.Res -> {
|
||||
Image(
|
||||
painter = painterResource(image.resId),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
null -> {
|
||||
onImageError?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,16 @@ package com.tangem.features.staking.impl.presentation.ui
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
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
|
||||
|
|
@ -20,7 +24,7 @@ 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.inputrow.InputRowImageSelector
|
||||
import com.tangem.core.ui.components.SpacerW12
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
|
|
@ -35,6 +39,7 @@ import com.tangem.features.staking.impl.presentation.state.StakingStates
|
|||
import com.tangem.features.staking.impl.presentation.state.previewdata.ValidatorStatePreviewData
|
||||
import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardTypeLongText
|
||||
import com.tangem.features.staking.impl.presentation.ui.utils.toImageReference
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
/**
|
||||
|
|
@ -61,47 +66,80 @@ internal fun StakingValidatorListContent(
|
|||
key = { targets[it].address },
|
||||
contentType = { targets[it]::class.java },
|
||||
) { index ->
|
||||
val item = targets[index]
|
||||
|
||||
InputRowImageSelector(
|
||||
subtitle = stringReference(item.name),
|
||||
caption = item.getAprTextNeutral(),
|
||||
imageUrl = item.image.orEmpty(),
|
||||
isSelected = item == state.chosenTarget,
|
||||
onSelect = { clickIntents.onTargetSelect(item) },
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = targets.lastIndex,
|
||||
radius = TangemTheme.dimens.radius12,
|
||||
addDefaultPadding =
|
||||
false,
|
||||
)
|
||||
.background(TangemTheme.colors.background.action),
|
||||
subtitleExtraContent = {
|
||||
ValidatorLabel(item.isStrategicPartner)
|
||||
},
|
||||
selectorContent = { checked, _, _ ->
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier,
|
||||
visible = checked,
|
||||
) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
image = ImageVector.vectorResource(id = R.drawable.ic_check_24),
|
||||
),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
ValidatorListItem(
|
||||
item = targets[index],
|
||||
isSelected = targets[index] == state.chosenTarget,
|
||||
index = index,
|
||||
lastIndex = targets.lastIndex,
|
||||
onSelect = { clickIntents.onTargetSelect(targets[index]) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ValidatorListItem(
|
||||
item: StakingTarget,
|
||||
isSelected: Boolean,
|
||||
index: Int,
|
||||
lastIndex: Int,
|
||||
onSelect: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = lastIndex,
|
||||
radius = TangemTheme.dimens.radius12,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(),
|
||||
onClick = onSelect,
|
||||
)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
StakingTargetIcon(
|
||||
image = item.image.toImageReference(),
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.spacing36)
|
||||
.clip(TangemTheme.shapes.roundedCornersXLarge),
|
||||
)
|
||||
SpacerW12()
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row {
|
||||
Text(
|
||||
text = stringReference(item.name).resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
ValidatorLabel(item.isStrategicPartner)
|
||||
}
|
||||
Text(
|
||||
text = item.getAprTextNeutral().resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing2),
|
||||
)
|
||||
}
|
||||
SpacerW12()
|
||||
AnimatedVisibility(visible = isSelected) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
image = ImageVector.vectorResource(id = R.drawable.ic_check_24),
|
||||
),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For FCA fixes remove coloring for now
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.platform.testTag
|
||||
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
|
||||
|
|
@ -30,7 +29,9 @@ import com.tangem.features.staking.impl.R
|
|||
import com.tangem.features.staking.impl.presentation.state.StakingStates.ValidatorState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardTypeShortText
|
||||
import com.tangem.features.staking.impl.presentation.ui.StakingTargetIcon
|
||||
import com.tangem.features.staking.impl.presentation.ui.ValidatorImagePlaceholder
|
||||
import com.tangem.features.staking.impl.presentation.ui.utils.toImageReference
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
@Composable
|
||||
|
|
@ -63,8 +64,8 @@ internal fun ValidatorBlock(validatorState: StakingStates.ValidatorState, isClic
|
|||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.padding(12.dp),
|
||||
) {
|
||||
InputRowAsyncImage(
|
||||
imageUrl = state.chosenTarget.image.orEmpty(),
|
||||
StakingTargetIcon(
|
||||
image = state.chosenTarget.image.toImageReference(),
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui.utils
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.extensions.ImageReference
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
import com.tangem.domain.staking.model.StakingLocalImageType
|
||||
import com.tangem.domain.staking.model.StakingTargetImage
|
||||
|
||||
fun StakingTargetImage?.toImageReference(): ImageReference? = when (this) {
|
||||
is StakingTargetImage.Url -> url.takeIf { it.isNotBlank() }?.let { ImageReference.Url(it) }
|
||||
is StakingTargetImage.Local -> ImageReference.Res(type.toDrawableRes())
|
||||
null -> null
|
||||
}
|
||||
|
||||
fun StakingTargetImage?.toImageUrl(): String? = (this as? StakingTargetImage.Url)?.url?.takeIf { it.isNotBlank() }
|
||||
|
||||
@DrawableRes
|
||||
fun StakingTargetImage?.toDrawableRes(): Int? = (this as? StakingTargetImage.Local)?.type?.toDrawableRes()
|
||||
|
||||
@DrawableRes
|
||||
fun StakingLocalImageType.toDrawableRes(): Int = when (this) {
|
||||
StakingLocalImageType.P2P_VAULT -> CoreR.drawable.ic_p2p_logo
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue