Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-29 16:17:50 +03:00
parent 7d32dc04b2
commit f9ccdb0982
4 changed files with 116 additions and 82 deletions

View file

@ -17,7 +17,6 @@ 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.BuildConfig
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SpacerW4
import com.tangem.core.ui.components.account.AccountCharIcon
@ -33,9 +32,9 @@ 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
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.conditional
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.ProvideSharedTransitionScope
/**
* Multi-currency content item
@ -69,7 +68,7 @@ fun TokenListItem(state: TokensListItemUM, isBalanceHidden: Boolean, modifier: M
@Suppress("MagicNumber", "ReusedModifierInstance", "LongMethod")
@Composable
fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
SharedTransitionLayout(modifier) {
ProvideSharedTransitionScope(modifier) {
val iconSharedContentState = rememberSharedContentState(key = "icon_${state.id}")
val titleSharedContentState = rememberSharedContentState(key = "title_${state.id}")
val boundsTransform = BoundsTransform { _, _ -> tween(350) }
@ -101,13 +100,11 @@ fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolea
state = iconState,
withFixedSize = false,
modifier = modifier
.conditional(BuildConfig.DEBUG.not()) {
sharedBounds(
sharedContentState = iconSharedContentState,
animatedVisibilityScope = animatedContentScope,
boundsTransform = boundsTransform,
)
},
.sharedBounds(
sharedContentState = iconSharedContentState,
animatedVisibilityScope = animatedContentScope,
boundsTransform = boundsTransform,
),
)
},
title = { modifier: Modifier ->
@ -126,14 +123,12 @@ fun PortfolioListItem(state: TokensListItemUM.Portfolio, isBalanceHidden: Boolea
state = state.tokenItemUM.titleState,
textStyle = textStyle.copy(fontSize = textSize.sp),
modifier = modifier
.conditional(BuildConfig.DEBUG.not()) {
sharedBounds(
sharedContentState = titleSharedContentState,
animatedVisibilityScope = animatedContentScope,
boundsTransform = boundsTransform,
resizeMode = scaleToBounds(ContentScale.Fit, Alignment.CenterStart),
)
},
.sharedBounds(
sharedContentState = titleSharedContentState,
animatedVisibilityScope = animatedContentScope,
boundsTransform = boundsTransform,
resizeMode = scaleToBounds(ContentScale.Fit, Alignment.CenterStart),
),
)
},
)

View file

@ -0,0 +1,36 @@
package com.tangem.core.ui.utils
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.SharedTransitionScope
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
@Composable
fun TangemSharedTransitionLayout(
modifier: Modifier = Modifier,
content: @Composable SharedTransitionScope.() -> Unit,
) {
SharedTransitionLayout(modifier) {
val sharedTransitionScope = this
CompositionLocalProvider(
LocalSharedTransitionScope provides sharedTransitionScope,
) {
content()
}
}
}
@Composable
fun ProvideSharedTransitionScope(modifier: Modifier = Modifier, content: @Composable SharedTransitionScope.() -> Unit) {
val sharedTransitionScope = LocalSharedTransitionScope.current
Box(modifier) {
sharedTransitionScope.content()
}
}
private val LocalSharedTransitionScope = staticCompositionLocalOf<SharedTransitionScope> {
error("No SharedTransitionScope provided")
}

View file

@ -65,6 +65,7 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.MainScreenTestTags
import com.tangem.core.ui.test.MarketTooltipTestTags
import com.tangem.core.ui.utils.TangemSharedTransitionLayout
import com.tangem.core.ui.utils.lineTo
import com.tangem.core.ui.utils.moveTo
import com.tangem.core.ui.utils.toPx
@ -180,79 +181,81 @@ private fun WalletContent(
)
} ?: PaddingValues(bottom = TangemTheme.dimens.spacing92 + bottomBarHeight)
LazyColumn(
modifier = Modifier.testTag(MainScreenTestTags.SCREEN_CONTAINER),
state = listState,
contentPadding = contentPadding,
horizontalAlignment = Alignment.CenterHorizontally,
) {
item(
// !!! Type of the key should be saveable via Bundle on Android !!!
key = state.wallets.map { it.walletCardState.id.stringValue },
contentType = state.wallets.map { it.walletCardState.id },
TangemSharedTransitionLayout {
LazyColumn(
modifier = Modifier.testTag(MainScreenTestTags.SCREEN_CONTAINER),
state = listState,
contentPadding = contentPadding,
horizontalAlignment = Alignment.CenterHorizontally,
) {
WalletsList(
modifier = Modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
lazyListState = walletsListState,
wallets = state.wallets.map(WalletState::walletCardState).toImmutableList(),
isBalanceHidden = state.isHidingMode,
)
}
when (selectedWallet) {
is WalletState.MultiCurrency -> {
actions(
actions = selectedWallet.buttons,
selectedWalletIndex = selectedWalletIndex,
modifier = movableItemModifier.padding(top = betweenItemsPadding),
)
}
is WalletState.SingleCurrency -> {
lazyActions(
actions = selectedWallet.buttons,
selectedWalletIndex = selectedWalletIndex,
modifier = movableItemModifier.padding(top = betweenItemsPadding),
)
}
}
notifications(configs = selectedWallet.warnings, modifier = itemModifier)
if (selectedWallet is WalletState.MultiCurrency) {
item(
key = "TangemPayMainScreenBlock",
contentType = selectedWallet.tangemPayState::class.java,
// !!! Type of the key should be saveable via Bundle on Android !!!
key = state.wallets.map { it.walletCardState.id.stringValue },
contentType = state.wallets.map { it.walletCardState.id },
) {
TangemPayMainScreenBlock(
state = selectedWallet.tangemPayState,
WalletsList(
modifier = Modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
lazyListState = walletsListState,
wallets = state.wallets.map(WalletState::walletCardState).toImmutableList(),
isBalanceHidden = state.isHidingMode,
modifier = itemModifier,
)
}
}
(selectedWallet as? WalletState.SingleCurrency)?.let { walletState ->
walletState.marketPriceBlockState?.let { marketPriceBlockState ->
marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier)
when (selectedWallet) {
is WalletState.MultiCurrency -> {
actions(
actions = selectedWallet.buttons,
selectedWalletIndex = selectedWalletIndex,
modifier = movableItemModifier.padding(top = betweenItemsPadding),
)
}
is WalletState.SingleCurrency -> {
lazyActions(
actions = selectedWallet.buttons,
selectedWalletIndex = selectedWalletIndex,
modifier = movableItemModifier.padding(top = betweenItemsPadding),
)
}
}
if (walletState is WalletState.SingleCurrency.Content) {
expressTransactionsItems(
expressTxs = walletState.expressTxsToDisplay,
modifier = itemModifier,
)
notifications(configs = selectedWallet.warnings, modifier = itemModifier)
if (selectedWallet is WalletState.MultiCurrency) {
item(
key = "TangemPayMainScreenBlock",
contentType = selectedWallet.tangemPayState::class.java,
) {
TangemPayMainScreenBlock(
state = selectedWallet.tangemPayState,
isBalanceHidden = state.isHidingMode,
modifier = itemModifier,
)
}
}
(selectedWallet as? WalletState.SingleCurrency)?.let { walletState ->
walletState.marketPriceBlockState?.let { marketPriceBlockState ->
marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier)
}
if (walletState is WalletState.SingleCurrency.Content) {
expressTransactionsItems(
expressTxs = walletState.expressTxsToDisplay,
modifier = itemModifier,
)
}
}
contentItems(
state = selectedWallet,
txHistoryItems = txHistoryItems,
isBalanceHidden = state.isHidingMode,
modifier = movableItemModifier,
)
nftCollections(state = selectedWallet, itemModifier = itemModifier)
organizeTokens(state = selectedWallet, itemModifier = itemModifier)
}
contentItems(
state = selectedWallet,
txHistoryItems = txHistoryItems,
isBalanceHidden = state.isHidingMode,
modifier = movableItemModifier,
)
nftCollections(state = selectedWallet, itemModifier = itemModifier)
organizeTokens(state = selectedWallet, itemModifier = itemModifier)
}
ShowBottomSheet(bottomSheetConfig = selectedWallet.bottomSheetConfig)

View file

@ -84,7 +84,7 @@ internal fun LazyListScope.portfolioTokensList(
}
itemsIndexed(
items = tokens,
key = { _, item -> item.id },
key = { _, item -> item.id.toString() + "-portfolio-${portfolio.id}" },
contentType = { _, item -> item::class.java },
itemContent = { tokenIndex, token ->
val indexWithHeader = tokenIndex.inc()