Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-26 13:47:44 +03:00
parent 050c7b6106
commit 064279f370
3 changed files with 69 additions and 34 deletions

View file

@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
@ -21,10 +22,14 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.components.token.state.TokenItemState.TitleState as TokenTitleState
@Composable
fun TokenTitle(state: TokenTitleState?, modifier: Modifier = Modifier) {
fun TokenTitle(
state: TokenTitleState?,
modifier: Modifier = Modifier,
textStyle: TextStyle = TangemTheme.typography.subtitle2,
) {
when (state) {
is TokenTitleState.Content -> {
ContentTitle(state = state, modifier = modifier)
ContentTitle(state = state, modifier = modifier, textStyle = textStyle)
}
is TokenTitleState.Loading -> {
RectangleShimmer(modifier = modifier.placeholderSize(), radius = TangemTheme.dimens.radius4)
@ -37,7 +42,7 @@ fun TokenTitle(state: TokenTitleState?, modifier: Modifier = Modifier) {
}
@Composable
private fun ContentTitle(state: TokenTitleState.Content, modifier: Modifier = Modifier) {
private fun ContentTitle(state: TokenTitleState.Content, textStyle: TextStyle, modifier: Modifier = Modifier) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing6),
@ -50,6 +55,7 @@ private fun ContentTitle(state: TokenTitleState.Content, modifier: Modifier = Mo
CurrencyNameText(
name = state.text.resolveReference(),
isAvailable = state.isAvailable,
textStyle = textStyle,
modifier = Modifier.weight(weight = 1f, fill = false),
)
@ -71,14 +77,14 @@ private fun ContentTitle(state: TokenTitleState.Content, modifier: Modifier = Mo
}
@Composable
private fun CurrencyNameText(name: String, isAvailable: Boolean, modifier: Modifier = Modifier) {
private fun CurrencyNameText(name: String, isAvailable: Boolean, textStyle: TextStyle, modifier: Modifier = Modifier) {
Text(
text = name,
modifier = modifier,
color = if (isAvailable) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.tertiary,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
style = TangemTheme.typography.subtitle2,
style = textStyle,
)
}

View file

@ -1,25 +1,23 @@
package com.tangem.core.ui.components.tokenlist
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.BoundsTransform
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.SharedTransitionScope
import androidx.compose.animation.*
import androidx.compose.animation.SharedTransitionScope.ResizeMode.Companion.scaleToBounds
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SpacerW4
import com.tangem.core.ui.components.account.AccountCharIcon
@ -67,7 +65,7 @@ fun TokenListItem(state: TokensListItemUM, isBalanceHidden: Boolean, modifier: M
}
}
@Suppress("MagicNumber", "ReusedModifierInstance")
@Suppress("MagicNumber", "ReusedModifierInstance", "LongMethod")
@Composable
fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
// Box is not needed here, but due to a bug in compose
@ -86,7 +84,7 @@ fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolea
val titleSharedContentState = rememberSharedContentState(key = "title")
val boundsTransform = BoundsTransform { _, _ -> tween(350) }
val composables =
val composables = remember {
TokenItemComposables(
icon = { modifier: Modifier ->
val iconState = when (val icon = state.tokenItemUM.iconState) {
@ -113,24 +111,51 @@ fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolea
)
},
title = { modifier: Modifier ->
val textStyle = if (isExpanded) {
TangemTheme.typography.caption1
} else {
TangemTheme.typography.subtitle2
}
val textSize by animateFloatAsState(
targetValue = textStyle.fontSize.value,
animationSpec = tween(350),
)
TokenTitle(
state = state.tokenItemUM.titleState,
textStyle = textStyle.copy(fontSize = textSize.sp),
modifier = modifier
.sharedElement(
.sharedBounds(
sharedContentState = titleSharedContentState,
animatedVisibilityScope = animatedContentScope,
boundsTransform = boundsTransform,
placeholderSize = SharedTransitionScope.PlaceholderSize.AnimatedSize,
resizeMode = scaleToBounds(ContentScale.Fit, Alignment.CenterStart),
),
)
},
)
}
if (isExpanded) {
ExpandedPortfolioHeader(
state = state.tokenItemUM,
isCollapsable = state.isCollapsable,
composables = composables,
balanceTextModifier = Modifier
.animateEnterExit(
enter = fadeIn(tween(350)) +
slideInHorizontally(
tween(350),
initialOffsetX = { fullWidth -> fullWidth * 2 },
),
exit = fadeOut(
tween(350),
) + slideOutHorizontally(
tween(350),
targetOffsetX = { fullWidth -> fullWidth * 2 },
),
),
)
} else {
TokenItem(
@ -163,6 +188,7 @@ fun ExpandedPortfolioHeader(
isCollapsable: Boolean,
composables: TokenItemComposables?,
modifier: Modifier = Modifier,
balanceTextModifier: Modifier = Modifier,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
@ -227,18 +253,16 @@ fun ExpandedPortfolioHeader(
else -> null
}
AnimatedVisibility(text != null) {
Text(
text = text.orEmpty(),
modifier = Modifier
.alignByBaseline()
.padding(horizontal = 8.dp),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.caption1,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
}
Text(
text = text.orEmpty(),
modifier = balanceTextModifier
.alignByBaseline()
.padding(horizontal = 8.dp),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.caption1,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
}
if (isCollapsable) {

View file

@ -113,6 +113,7 @@ internal fun LazyListScope.portfolioTokensList(
)
}
@Suppress("MagicNumber")
private fun LazyListScope.portfolioItem(
portfolio: TokensListItemUM.Portfolio,
modifier: Modifier,
@ -140,7 +141,7 @@ private fun LazyListScope.portfolioItem(
lastIndexProxy = lastIndex
return@LaunchedEffect
}
delay(timeMillis = (50 * tokens.size).toLong())
delay(timeMillis = minOf(50 * tokens.size, 350).toLong())
lastIndexProxy = 0
}
@ -168,19 +169,23 @@ private fun SlideInItemVisibility(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
val maxDelay = 250
val delayEnter = minOf(50 * currentIndex, maxDelay)
val delayExit = minOf(50 * (lastIndex - currentIndex - 1), maxDelay)
AnimatedVisibility(
modifier = modifier,
visible = visible,
enter = fadeIn(
tween(100, delayMillis = 50 * currentIndex),
tween(100, delayMillis = delayEnter),
) + expandVertically(
tween(100, delayMillis = 50 * currentIndex),
tween(100, delayMillis = delayEnter),
expandFrom = Alignment.Top,
),
exit = fadeOut(
tween(100, delayMillis = 50 * (lastIndex - currentIndex - 1)),
tween(100, delayMillis = delayExit),
) + shrinkVertically(
tween(100, delayMillis = 50 * (lastIndex - currentIndex - 1)),
tween(100, delayMillis = delayExit),
shrinkTowards = Alignment.Top,
),
) {