Updated on 2026-08-14
This commit is contained in:
parent
9836b18ff4
commit
050c7b6106
13 changed files with 369 additions and 222 deletions
|
|
@ -2,12 +2,21 @@ package com.tangem.core.ui.components.account
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -15,7 +24,9 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -36,14 +47,28 @@ enum class AccountIconSize {
|
|||
*/
|
||||
@Composable
|
||||
fun AccountResIcon(@DrawableRes resId: Int, color: Color, size: AccountIconSize, modifier: Modifier = Modifier) {
|
||||
val boxModifier = modifier.selectBoxModifier(size)
|
||||
val iconSize = Modifier.selectIconSize(size)
|
||||
val boxSize by animateDpAsState(
|
||||
targetValue = size.boxSizeInDp(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val boxShapeCornerSize by animateDpAsState(
|
||||
targetValue = size.boxShapeSizeInDp(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val iconSize by animateDpAsState(
|
||||
targetValue = size.iconSizeInDp(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = boxModifier.background(color),
|
||||
modifier = modifier
|
||||
.size(boxSize)
|
||||
.clip(RoundedCornerShape(boxShapeCornerSize))
|
||||
.background(color),
|
||||
) {
|
||||
Icon(
|
||||
modifier = iconSize,
|
||||
modifier = Modifier.size(iconSize),
|
||||
tint = TangemTheme.colors.text.constantWhite,
|
||||
imageVector = ImageVector.vectorResource(id = resId),
|
||||
contentDescription = null,
|
||||
|
|
@ -64,7 +89,14 @@ fun AccountResIcon(@DrawableRes resId: Int, color: Color, size: AccountIconSize,
|
|||
*/
|
||||
@Composable
|
||||
fun AccountCharIcon(char: Char, color: Color, size: AccountIconSize, modifier: Modifier = Modifier) {
|
||||
val boxModifier = modifier.selectBoxModifier(size)
|
||||
val boxSize by animateDpAsState(
|
||||
size.boxSizeInDp(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val boxShapeCornerSize by animateDpAsState(
|
||||
size.boxShapeSizeInDp(),
|
||||
animationSpec = animation(),
|
||||
)
|
||||
val textStyle = when (size) {
|
||||
AccountIconSize.Default -> TangemTheme.typography.h3
|
||||
AccountIconSize.Large -> TangemTheme.typography.h1
|
||||
|
|
@ -72,32 +104,52 @@ fun AccountCharIcon(char: Char, color: Color, size: AccountIconSize, modifier: M
|
|||
AccountIconSize.Small -> TangemTheme.typography.subtitle2
|
||||
AccountIconSize.ExtraSmall -> TangemTheme.typography.caption1
|
||||
}
|
||||
|
||||
val textSize by animateFloatAsState(
|
||||
textStyle.fontSize.value,
|
||||
animationSpec = animation(),
|
||||
)
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = boxModifier.background(color),
|
||||
modifier = modifier
|
||||
.size(boxSize)
|
||||
.clip(RoundedCornerShape(boxShapeCornerSize))
|
||||
.background(color),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.animateContentSize(animationSpec = animation()),
|
||||
text = char.uppercase(),
|
||||
style = textStyle,
|
||||
style = textStyle.copy(fontSize = textSize.sp),
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.selectIconSize(size: AccountIconSize): Modifier = when (size) {
|
||||
AccountIconSize.Default -> this.size(20.dp)
|
||||
AccountIconSize.Large -> this.size(40.dp)
|
||||
AccountIconSize.Medium -> this.size(16.dp)
|
||||
AccountIconSize.Small -> this.size(12.dp)
|
||||
AccountIconSize.ExtraSmall -> this.size(8.dp)
|
||||
private fun <T> animation() = tween<T>(durationMillis = 350)
|
||||
|
||||
private fun AccountIconSize.iconSizeInDp(): Dp = when (this) {
|
||||
AccountIconSize.Default -> 20.dp
|
||||
AccountIconSize.Large -> 40.dp
|
||||
AccountIconSize.Medium -> 16.dp
|
||||
AccountIconSize.Small -> 12.dp
|
||||
AccountIconSize.ExtraSmall -> 8.dp
|
||||
}
|
||||
|
||||
private fun Modifier.selectBoxModifier(size: AccountIconSize): Modifier = when (size) {
|
||||
AccountIconSize.Default -> size(36.dp).clip(RoundedCornerShape(10.dp))
|
||||
AccountIconSize.Large -> size(88.dp).clip(RoundedCornerShape(24.dp))
|
||||
AccountIconSize.Medium -> size(28.dp).clip(RoundedCornerShape(8.dp))
|
||||
AccountIconSize.Small -> size(20.dp).clip(RoundedCornerShape(6.dp))
|
||||
AccountIconSize.ExtraSmall -> size(14.dp).clip(RoundedCornerShape(4.dp))
|
||||
private fun AccountIconSize.boxSizeInDp(): Dp = when (this) {
|
||||
AccountIconSize.Default -> 36.dp
|
||||
AccountIconSize.Large -> 88.dp
|
||||
AccountIconSize.Medium -> 28.dp
|
||||
AccountIconSize.Small -> 20.dp
|
||||
AccountIconSize.ExtraSmall -> 14.dp
|
||||
}
|
||||
|
||||
private fun AccountIconSize.boxShapeSizeInDp(): Dp = when (this) {
|
||||
AccountIconSize.Default -> 10.dp
|
||||
AccountIconSize.Large -> 24.dp
|
||||
AccountIconSize.Medium -> 8.dp
|
||||
AccountIconSize.Small -> 6.dp
|
||||
AccountIconSize.ExtraSmall -> 4.dp
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
|
|
@ -115,7 +167,20 @@ private fun Preview() {
|
|||
|
||||
@Composable
|
||||
private fun Sample() {
|
||||
var sizeState by remember { mutableStateOf(AccountIconSize.ExtraSmall) }
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
AccountResIcon(resId = R.drawable.ic_shirt_24, color = Color.Red, size = sizeState)
|
||||
Button(onClick = {
|
||||
sizeState = when (sizeState) {
|
||||
AccountIconSize.Default -> AccountIconSize.Large
|
||||
AccountIconSize.Large -> AccountIconSize.Medium
|
||||
AccountIconSize.Medium -> AccountIconSize.Small
|
||||
AccountIconSize.Small -> AccountIconSize.ExtraSmall
|
||||
AccountIconSize.ExtraSmall -> AccountIconSize.Default
|
||||
}
|
||||
}) { Text("Change") }
|
||||
|
||||
AccountResIcon(resId = R.drawable.ic_shirt_24, color = Color.Red, size = AccountIconSize.Default)
|
||||
AccountResIcon(resId = R.drawable.ic_rounded_star_24, color = Color.Blue, size = AccountIconSize.Large)
|
||||
AccountResIcon(resId = R.drawable.ic_user_24, color = Color.Magenta, size = AccountIconSize.Medium)
|
||||
|
|
@ -123,6 +188,7 @@ private fun Sample() {
|
|||
AccountResIcon(resId = R.drawable.ic_wallet_24, color = Color.Green, size = AccountIconSize.ExtraSmall)
|
||||
}
|
||||
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
AccountCharIcon(char = 'D', color = Color.Red, size = sizeState)
|
||||
AccountCharIcon(char = 'D', color = Color.Red, size = AccountIconSize.Default)
|
||||
AccountCharIcon(char = 'L', color = Color.Blue, size = AccountIconSize.Large)
|
||||
AccountCharIcon(char = 'M', color = Color.Magenta, size = AccountIconSize.Medium)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import androidx.compose.ui.graphics.ColorFilter
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.account.AccountCharIcon
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.components.account.AccountResIcon
|
||||
import com.tangem.core.ui.components.currency.DefaultCurrencyIcon
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
|
|
@ -66,13 +65,13 @@ internal fun ContentIcon(
|
|||
modifier = modifier,
|
||||
resId = icon.resId,
|
||||
color = icon.color,
|
||||
size = AccountIconSize.Default,
|
||||
size = icon.size,
|
||||
)
|
||||
is CurrencyIconState.CryptoPortfolio.Letter -> AccountCharIcon(
|
||||
modifier = modifier,
|
||||
char = icon.char.resolveReference().first(),
|
||||
color = icon.color,
|
||||
size = AccountIconSize.Default,
|
||||
size = icon.size,
|
||||
)
|
||||
CurrencyIconState.Loading,
|
||||
CurrencyIconState.Locked,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.getGreyScaleColorFilter
|
||||
|
||||
|
|
@ -33,12 +34,20 @@ fun CurrencyIcon(
|
|||
state: CurrencyIconState,
|
||||
modifier: Modifier = Modifier,
|
||||
shouldDisplayNetwork: Boolean = true,
|
||||
withFixedSize: Boolean = true,
|
||||
iconSize: Dp = 36.dp,
|
||||
) {
|
||||
BaseContainer(modifier = modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.conditional(withFixedSize) {
|
||||
size(size = 40.dp)
|
||||
},
|
||||
) {
|
||||
val iconModifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(iconSize)
|
||||
.conditional(withFixedSize) {
|
||||
size(iconSize)
|
||||
}
|
||||
|
||||
when (state) {
|
||||
is CurrencyIconState.Loading -> LoadingIcon(modifier = iconModifier)
|
||||
|
|
@ -132,9 +141,4 @@ private fun BoxScope.ContentIconContainer(
|
|||
modifier = Modifier.align(Alignment.BottomEnd),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private inline fun BaseContainer(modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit) {
|
||||
Box(modifier = modifier.size(size = TangemTheme.dimens.size40), content = content)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import androidx.annotation.DrawableRes
|
|||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
/**
|
||||
|
|
@ -92,17 +93,20 @@ sealed class CurrencyIconState {
|
|||
override val shouldShowCustomBadge: Boolean = false
|
||||
override val topBadgeIconResId: Int? = null
|
||||
abstract val color: Color
|
||||
abstract val size: AccountIconSize
|
||||
|
||||
data class Icon(
|
||||
@DrawableRes val resId: Int,
|
||||
override val color: Color,
|
||||
override val isGrayscale: Boolean,
|
||||
override val size: AccountIconSize = AccountIconSize.Default,
|
||||
) : CryptoPortfolio()
|
||||
|
||||
data class Letter(
|
||||
val char: TextReference,
|
||||
override val color: Color,
|
||||
override val isGrayscale: Boolean,
|
||||
override val size: AccountIconSize = AccountIconSize.Default,
|
||||
) : CryptoPortfolio()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -31,6 +32,7 @@ import com.tangem.core.ui.components.token.state.TokenItemState
|
|||
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.Subtitle2State
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.PromoBannerState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.TitleState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.rememberHapticFeedback
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -65,6 +67,7 @@ fun TokenItem(
|
|||
state: TokenItemState,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
composables: TokenItemComposables? = null,
|
||||
itemPaddingValues: PaddingValues = PaddingValues(horizontal = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
TokenItem(
|
||||
|
|
@ -73,9 +76,16 @@ fun TokenItem(
|
|||
modifier = modifier,
|
||||
reorderableTokenListState = null,
|
||||
itemPaddingValues = itemPaddingValues,
|
||||
composables = composables,
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
class TokenItemComposables(
|
||||
val title: @Composable (Modifier) -> Unit,
|
||||
val icon: @Composable (Modifier) -> Unit,
|
||||
)
|
||||
|
||||
/**
|
||||
* Token item for reorderable list
|
||||
*
|
||||
|
|
@ -88,6 +98,7 @@ fun TokenItem(
|
|||
* @see <a href = "https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=1051-866&t=ew8mbGp2lacuJfFm-4"
|
||||
* >Figma Component</a>
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun TokenItem(
|
||||
state: TokenItemState,
|
||||
|
|
@ -95,6 +106,7 @@ fun TokenItem(
|
|||
reorderableTokenListState: ReorderableLazyListState?,
|
||||
modifier: Modifier = Modifier,
|
||||
itemPaddingValues: PaddingValues = PaddingValues(horizontal = TangemTheme.dimens.spacing12),
|
||||
composables: TokenItemComposables? = null,
|
||||
) {
|
||||
val betweenRowsMargin = TangemTheme.dimens.spacing2
|
||||
|
||||
|
|
@ -104,13 +116,22 @@ fun TokenItem(
|
|||
.tokenClickable(state = state)
|
||||
.padding(itemPaddingValues),
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = state.iconState,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = LayoutId.ICON)
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.testTag(TokenElementsTestTags.TOKEN_ICON),
|
||||
)
|
||||
if (composables != null) {
|
||||
composables.icon.invoke(
|
||||
Modifier
|
||||
.layoutId(layoutId = LayoutId.ICON)
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.testTag(TokenElementsTestTags.TOKEN_ICON),
|
||||
)
|
||||
} else {
|
||||
CurrencyIcon(
|
||||
state = state.iconState,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = LayoutId.ICON)
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.testTag(TokenElementsTestTags.TOKEN_ICON),
|
||||
)
|
||||
}
|
||||
|
||||
YieldSupplyPromoBanner(
|
||||
state = state.promoBannerState,
|
||||
|
|
@ -120,14 +141,24 @@ fun TokenItem(
|
|||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
TokenTitle(
|
||||
state = state.titleState,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = LayoutId.TITLE)
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.padding(bottom = betweenRowsMargin)
|
||||
.testTag(TokenElementsTestTags.TOKEN_TITLE),
|
||||
)
|
||||
if (composables != null) {
|
||||
composables.title.invoke(
|
||||
Modifier
|
||||
.layoutId(layoutId = LayoutId.TITLE)
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.padding(bottom = betweenRowsMargin)
|
||||
.testTag(TokenElementsTestTags.TOKEN_TITLE),
|
||||
)
|
||||
} else {
|
||||
TokenTitle(
|
||||
state = state.titleState,
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = LayoutId.TITLE)
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.padding(bottom = betweenRowsMargin)
|
||||
.testTag(TokenElementsTestTags.TOKEN_TITLE),
|
||||
)
|
||||
}
|
||||
|
||||
TokenFiatAmount(
|
||||
state = state.fiatAmountState,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.components.token.state.TokenItemState.TitleState as TokenTitleState
|
||||
|
||||
@Composable
|
||||
internal fun TokenTitle(state: TokenTitleState?, modifier: Modifier = Modifier) {
|
||||
fun TokenTitle(state: TokenTitleState?, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
is TokenTitleState.Content -> {
|
||||
ContentTitle(state = state, modifier = modifier)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
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.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.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
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.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -18,9 +25,12 @@ import com.tangem.core.ui.components.SpacerW4
|
|||
import com.tangem.core.ui.components.account.AccountCharIcon
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.components.account.AccountResIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.token.TokenItem
|
||||
import com.tangem.core.ui.components.token.TokenItemComposables
|
||||
import com.tangem.core.ui.components.token.internal.TokenTitle
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.components.tokenlist.internal.GroupTitleItem
|
||||
import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM
|
||||
|
|
@ -57,16 +67,80 @@ fun TokenListItem(state: TokensListItemUM, isBalanceHidden: Boolean, modifier: M
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber", "ReusedModifierInstance")
|
||||
@Composable
|
||||
fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
if (state.isExpanded) {
|
||||
ExpandedPortfolioHeader(state = state.tokenItemUM, isCollapsable = state.isCollapsable, modifier = modifier)
|
||||
} else {
|
||||
TokenItem(
|
||||
state = state.tokenItemUM,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifier,
|
||||
)
|
||||
// Box is not needed here, but due to a bug in compose
|
||||
// we use it like a wrapper to properly handle lookahead scope inside this composable
|
||||
Box(modifier) {
|
||||
SharedTransitionLayout {
|
||||
AnimatedContent(
|
||||
state.isExpanded,
|
||||
transitionSpec = {
|
||||
fadeIn(animationSpec = tween(350, delayMillis = 90))
|
||||
.togetherWith(fadeOut(animationSpec = tween(350)))
|
||||
},
|
||||
) { isExpanded ->
|
||||
val animatedContentScope = this
|
||||
val iconSharedContentState = rememberSharedContentState(key = "icon")
|
||||
val titleSharedContentState = rememberSharedContentState(key = "title")
|
||||
val boundsTransform = BoundsTransform { _, _ -> tween(350) }
|
||||
|
||||
val composables =
|
||||
TokenItemComposables(
|
||||
icon = { modifier: Modifier ->
|
||||
val iconState = when (val icon = state.tokenItemUM.iconState) {
|
||||
is CurrencyIconState.CryptoPortfolio.Icon ->
|
||||
icon.copy(
|
||||
size = if (isExpanded) AccountIconSize.ExtraSmall else AccountIconSize.Default,
|
||||
)
|
||||
is CurrencyIconState.CryptoPortfolio.Letter ->
|
||||
icon.copy(
|
||||
size = if (isExpanded) AccountIconSize.ExtraSmall else AccountIconSize.Default,
|
||||
)
|
||||
else -> icon
|
||||
}
|
||||
|
||||
CurrencyIcon(
|
||||
state = iconState,
|
||||
withFixedSize = false,
|
||||
modifier = modifier
|
||||
.sharedBounds(
|
||||
sharedContentState = iconSharedContentState,
|
||||
animatedVisibilityScope = animatedContentScope,
|
||||
boundsTransform = boundsTransform,
|
||||
),
|
||||
)
|
||||
},
|
||||
title = { modifier: Modifier ->
|
||||
TokenTitle(
|
||||
state = state.tokenItemUM.titleState,
|
||||
modifier = modifier
|
||||
.sharedElement(
|
||||
sharedContentState = titleSharedContentState,
|
||||
animatedVisibilityScope = animatedContentScope,
|
||||
boundsTransform = boundsTransform,
|
||||
placeholderSize = SharedTransitionScope.PlaceholderSize.AnimatedSize,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
if (isExpanded) {
|
||||
ExpandedPortfolioHeader(
|
||||
state = state.tokenItemUM,
|
||||
isCollapsable = state.isCollapsable,
|
||||
composables = composables,
|
||||
)
|
||||
} else {
|
||||
TokenItem(
|
||||
state = state.tokenItemUM,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
composables = composables,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,52 +156,89 @@ fun PortfolioTokensListItem(state: PortfolioTokensListItemUM, isBalanceHidden: B
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun ExpandedPortfolioHeader(state: TokenItemState, isCollapsable: Boolean, modifier: Modifier = Modifier) {
|
||||
fun ExpandedPortfolioHeader(
|
||||
state: TokenItemState,
|
||||
isCollapsable: Boolean,
|
||||
composables: TokenItemComposables?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = { state.onItemClick?.invoke(state) })
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing4,
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
vertical = if (composables != null) 8.dp else 4.dp,
|
||||
horizontal = 12.dp,
|
||||
),
|
||||
) {
|
||||
when (val icon = state.iconState) {
|
||||
is CurrencyIconState.CryptoPortfolio.Icon -> AccountResIcon(
|
||||
resId = icon.resId,
|
||||
color = icon.color,
|
||||
size = AccountIconSize.ExtraSmall,
|
||||
)
|
||||
is CurrencyIconState.CryptoPortfolio.Letter -> AccountCharIcon(
|
||||
char = icon.char.resolveReference().first(),
|
||||
color = icon.color,
|
||||
size = AccountIconSize.ExtraSmall,
|
||||
)
|
||||
is CurrencyIconState.CoinIcon,
|
||||
is CurrencyIconState.CustomTokenIcon,
|
||||
is CurrencyIconState.Empty,
|
||||
is CurrencyIconState.FiatIcon,
|
||||
CurrencyIconState.Loading,
|
||||
CurrencyIconState.Locked,
|
||||
is CurrencyIconState.TokenIcon,
|
||||
-> Unit
|
||||
if (composables != null) {
|
||||
composables.icon.invoke(Modifier)
|
||||
} else {
|
||||
when (val icon = state.iconState) {
|
||||
is CurrencyIconState.CryptoPortfolio.Icon -> AccountResIcon(
|
||||
resId = icon.resId,
|
||||
color = icon.color,
|
||||
size = AccountIconSize.ExtraSmall,
|
||||
)
|
||||
is CurrencyIconState.CryptoPortfolio.Letter -> AccountCharIcon(
|
||||
char = icon.char.resolveReference().first(),
|
||||
color = icon.color,
|
||||
size = AccountIconSize.ExtraSmall,
|
||||
)
|
||||
is CurrencyIconState.CoinIcon,
|
||||
is CurrencyIconState.CustomTokenIcon,
|
||||
is CurrencyIconState.Empty,
|
||||
is CurrencyIconState.FiatIcon,
|
||||
CurrencyIconState.Loading,
|
||||
CurrencyIconState.Locked,
|
||||
is CurrencyIconState.TokenIcon,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
||||
SpacerW4()
|
||||
|
||||
when (val titleState = state.titleState) {
|
||||
TokenItemState.TitleState.Loading -> Unit
|
||||
TokenItemState.TitleState.Locked -> Unit
|
||||
is TokenItemState.TitleState.Content -> Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = titleState.text.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.caption1,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
if (composables != null) {
|
||||
composables.title.invoke(Modifier.alignByBaseline())
|
||||
} else {
|
||||
when (val titleState = state.titleState) {
|
||||
TokenItemState.TitleState.Loading -> Unit
|
||||
TokenItemState.TitleState.Locked -> Unit
|
||||
is TokenItemState.TitleState.Content -> Text(
|
||||
text = titleState.text.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.caption1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val text = when (val fiatAmountState = state.fiatAmountState) {
|
||||
is TokenItemState.FiatAmountState.Content -> fiatAmountState.text
|
||||
is TokenItemState.FiatAmountState.TextContent -> fiatAmountState.text
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (isCollapsable) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue