Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-24 16:07:06 +02:00
parent 698f1e6047
commit d84f383cf8
29 changed files with 567 additions and 547 deletions

View file

@ -144,13 +144,13 @@ private fun AddAndManageRow(
) {
Text(
text = stringResourceSafe(id = title),
style = TangemTheme.typography2.bodyMedium16,
color = TangemTheme.colors2.text.neutral.primary,
style = TangemTheme.typography3.body.medium,
color = TangemTheme.colors3.text.primary,
)
Text(
text = stringResourceSafe(id = subtitle),
style = TangemTheme.typography2.captionMedium12,
color = TangemTheme.colors2.text.neutral.secondary,
style = TangemTheme.typography3.caption.medium,
color = TangemTheme.colors3.text.secondary,
)
}
SpacerW(8.dp)

View file

@ -1,13 +1,17 @@
package com.tangem.feature.wallet.child.organizetokens.model.converter.items
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.tangem.common.getTotalCryptoAmount
import com.tangem.common.getTotalFiatAmount
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.row.internal.TangemRowTailUM
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.styledStringReference
import com.tangem.core.ui.format.bigdecimal.cryptoStyled
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.formatStyled
@ -36,7 +40,21 @@ internal class OrganizeTokenItemConverter(
id = getTokenItemId(currency.id),
headIconUM = TangemIconUM.Currency(iconStateConverter.convert(currencyStatus)),
titleUM = TangemTokenRowUM.TitleUM.Content(
text = stringReference(currency.name),
text = combinedReference(
stringReference(currency.name),
stringReference(" "),
styledStringReference(
value = currency.symbol,
spanStyleReference = {
SpanStyle(
color = TangemTheme.colors3.text.secondary,
fontWeight = FontWeight.Medium,
fontSize = 12.sp,
letterSpacing = 0.18.sp,
)
},
),
),
),
subtitleUM = TangemTokenRowUM.SubtitleUM.Empty,
topEndContentUM = TangemTokenRowUM.EndContentUM.Content(

View file

@ -62,11 +62,11 @@ private fun Menu(
private fun SortByBalanceMenuSection(organizeMenuUM: OrganizeTokensUM.OrganizeMenuUM, onDropdownDismiss: () -> Unit) {
Text(
text = stringResourceSafe(R.string.organize_tokens_sort_by_balance),
style = TangemTheme.typography2.headingSemibold17,
style = TangemTheme.typography3.body.medium,
color = if (organizeMenuUM.isSortedByBalance) {
TangemTheme.colors2.text.status.disabled
TangemTheme.colors3.text.tertiary
} else {
TangemTheme.colors2.text.neutral.primary
TangemTheme.colors3.text.primary
},
maxLines = 1,
modifier = Modifier
@ -79,12 +79,12 @@ private fun SortByBalanceMenuSection(organizeMenuUM: OrganizeTokensUM.OrganizeMe
},
enabled = !organizeMenuUM.isSortedByBalance,
)
.padding(vertical = TangemTheme.dimens2.x2_5, horizontal = TangemTheme.dimens2.x4),
.padding(vertical = 10.dp, horizontal = 16.dp),
)
HorizontalDivider(
thickness = 0.5.dp,
color = TangemTheme.colors2.border.neutral.quaternary,
color = TangemTheme.colors3.border.tertiary,
)
}
@ -102,36 +102,36 @@ private fun GroupTokensMenuSection(organizeMenuUM: OrganizeTokensUM.OrganizeMenu
onDropdownDismiss()
},
)
.padding(vertical = TangemTheme.dimens2.x2_5, horizontal = TangemTheme.dimens2.x4),
.padding(vertical = 10.dp, horizontal = 16.dp),
) {
Text(
text = stringResourceSafe(R.string.organize_tokens_group),
style = TangemTheme.typography2.headingSemibold17,
color = TangemTheme.colors2.text.neutral.primary,
style = TangemTheme.typography3.body.medium,
color = TangemTheme.colors3.text.primary,
maxLines = 1,
)
Box(
modifier = Modifier.size(TangemTheme.dimens2.x6),
modifier = Modifier.size(24.dp),
contentAlignment = Alignment.Center,
) {
if (organizeMenuUM.isGrouped) {
Box(
modifier = Modifier
.padding(TangemTheme.dimens2.x0_5)
.size(TangemTheme.dimens2.x5)
.padding(2.dp)
.size(20.dp)
.background(
color = TangemTheme.colors2.graphic.neutral.primary,
color = TangemTheme.colors3.icon.primary,
shape = CircleShape,
),
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_check_default_24),
contentDescription = null,
tint = TangemTheme.colors2.graphic.neutral.primaryInverted,
tint = TangemTheme.colors3.icon.inverse,
modifier = Modifier
.align(Alignment.Center)
.padding(TangemTheme.dimens2.x0_5)
.size(TangemTheme.dimens2.x4),
.padding(2.dp)
.size(16.dp),
)
}
}

View file

@ -34,8 +34,8 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.haze.hazeEffectTangem
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.ds.button.TangemButton
import com.tangem.core.ui.ds.image.TangemIcon
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.row.TangemRowContainer
import com.tangem.core.ui.ds.row.TangemRowLayoutId
import com.tangem.core.ui.ds.row.header.TangemHeaderRow
@ -43,10 +43,9 @@ import com.tangem.core.ui.ds.row.internal.TangemRowTail
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.ds.row.token.internal.TokenRowEndContent
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds.topbar.TangemTopBarActionContent
import com.tangem.core.ui.ds.topbar.TangemTopBarActionUM
import com.tangem.core.ui.ds.topbar.TangemTopBarType
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
import com.tangem.core.ui.extensions.copy
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
@ -82,21 +81,21 @@ internal fun OrganizeTokensContent(
onDismissRequest = onDismiss,
content = TangemBottomSheetConfigContent.Empty,
),
containerColor = TangemTheme.colors2.surface.level2,
containerColor = TangemTheme.colors3.bg.primary,
title = {
TangemTopBar(
TangemTopNavigation(
contentPadding = TangemTopNavigation.DefaultContentPadding.copy(top = 16.dp),
windowInsets = WindowInsets(0.dp),
blurBackground = false,
contentAlign = TangemTopNavigation.ContentAlign.Center,
title = resourceReference(R.string.organize_tokens_title),
type = TangemTopBarType.BottomSheet,
endContent = {
TangemTopBarActionContent(
actionUM = TangemTopBarActionUM(
iconRes = R.drawable.ic_exchange_mini_24,
isActionable = true,
onClick = { isShowDropdownMenu = true },
ghostModeProgress = 0f,
),
endButton = {
TangemButton(
modifier = Modifier.testTag(OrganizeTokensScreenTestTags.MENU_BUTTON),
type = TangemTopBarType.BottomSheet,
variant = TangemButton.Variant.Material,
size = TangemButton.Size.X11,
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_exchange_mini_24),
onClick = { isShowDropdownMenu = true },
)
OrganizeDropDownMenu(
organizeMenuUM = organizeTokensUM.organizeMenuUM,
@ -137,7 +136,7 @@ private fun TokenList(
var draggingItem by remember { mutableStateOf<OrganizeRowItemUM?>(null) }
Box(
modifier = modifier.background(TangemTheme.colors2.surface.level2),
modifier = modifier.background(TangemTheme.colors3.bg.primary),
) {
val footerInset = LocalTangemBottomSheetContentBottomInset.current
@ -238,7 +237,7 @@ private fun LazyItemScope.DraggableItem(
enabled = isValidDropTarget,
) { _ ->
val modifierWithBackground = itemModifier
.background(color = TangemTheme.colors.background.primary)
.background(color = TangemTheme.colors3.bg.secondary)
.semantics { lazyListItemPosition = index }
when (item) {
@ -281,16 +280,23 @@ private fun BoxScope.BottomButtons(organizeTokensUM: OrganizeTokensUM) {
.padding(bottom = bottomBarHeight + TangemTheme.dimens2.x4),
) {
TangemButton(
buttonUM = organizeTokensUM.cancelButton,
modifier = Modifier
.weight(1f)
.testTag(OrganizeTokensScreenTestTags.CANCEL_BUTTON),
onClick = organizeTokensUM.cancelButton.onClick,
text = organizeTokensUM.cancelButton.text,
variant = TangemButton.Variant.Secondary,
size = TangemButton.Size.X12,
isEnabled = organizeTokensUM.cancelButton.isEnabled,
)
TangemButton(
buttonUM = organizeTokensUM.applyButton,
modifier = Modifier
.weight(1f)
.testTag(OrganizeTokensScreenTestTags.APPLY_BUTTON),
onClick = organizeTokensUM.applyButton.onClick,
text = organizeTokensUM.applyButton.text,
size = TangemButton.Size.X12,
isEnabled = organizeTokensUM.applyButton.isEnabled,
)
}
}
@ -355,8 +361,8 @@ private fun OrganizeTokenRow(
TokenRowEndContent(
endContentUM = tokenRowUM.topEndContentUM,
isBalanceHidden = isBalanceHidden,
textStyle = TangemTheme.typography2.captionSemibold12,
textColor = TangemTheme.colors2.text.neutral.secondary,
textStyle = TangemTheme.typography3.caption.medium,
textColor = TangemTheme.colors3.text.secondary,
placeholderWidth = TangemTheme.dimens2.x11,
modifier = Modifier
.layoutId(layoutId = TangemRowLayoutId.START_BOTTOM)

View file

@ -1,5 +1,6 @@
package com.tangem.feature.wallet.child.organizetokens.ui.preview
import androidx.compose.ui.text.SpanStyle
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.ds.button.TangemButtonType
import com.tangem.core.ui.ds.button.TangemButtonUM
@ -8,9 +9,12 @@ import com.tangem.core.ui.ds.row.header.TangemHeaderRowUM
import com.tangem.core.ui.ds.row.internal.TangemRowTailUM
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.styledStringReference
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.child.organizetokens.entity.OrganizeRowItemUM
import com.tangem.feature.wallet.child.organizetokens.entity.OrganizeTokensUM
import com.tangem.feature.wallet.child.organizetokens.entity.RoundingModeUM
@ -75,7 +79,16 @@ internal object OrganizeTokensPreview {
tokenRowUM = draggableToken.copy(
id = "${group.id}_token_$tokenNumber",
titleUM = TangemTokenRowUM.TitleUM.Content(
text = stringReference(value = "Token $tokenNumber from $networkNumber network"),
text = combinedReference(
stringReference(value = "Token $tokenNumber"),
stringReference(value = " "),
styledStringReference(
value = "TKN$tokenNumber",
spanStyleReference = {
SpanStyle(color = TangemTheme.colors2.text.neutral.secondary)
},
),
),
),
),
groupId = group.id,

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.test.BaseBottomSheetTestTags
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpOffset
@ -31,6 +30,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.test.BaseBottomSheetTestTags
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenActionButtonUM
import kotlinx.collections.immutable.ImmutableList
@ -60,9 +60,9 @@ internal fun TokenActionContent(
tokenRowUM = tokenRowUM,
isBalanceHidden = isBalanceHidden,
modifier = Modifier
.padding(horizontal = TangemTheme.dimens2.x3)
.padding(horizontal = 12.dp)
.clip(RoundedCornerShape(18.dp))
.background(TangemTheme.colors2.surface.level3),
.background(TangemTheme.colors3.bg.secondary),
)
TangemContextMenu(
expanded = true,
@ -93,17 +93,17 @@ private fun TokenActionContextMenuContent(actions: ImmutableList<TokenActionButt
Column(
modifier = Modifier
.widthIn(min = 206.dp)
.padding(TangemTheme.dimens2.x1_5),
.padding(6.dp),
) {
actions.fastForEach { item ->
Column {
Row(
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2_5),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.testTag(BaseBottomSheetTestTags.ACTION_BUTTON)
.fillMaxWidth()
.clip(RoundedCornerShape(TangemTheme.dimens2.x2_5))
.clip(RoundedCornerShape(10.dp))
.clickable(
enabled = item.isEnabled,
onClick = {
@ -112,39 +112,39 @@ private fun TokenActionContextMenuContent(actions: ImmutableList<TokenActionButt
},
)
.padding(
horizontal = TangemTheme.dimens2.x2_5,
vertical = TangemTheme.dimens2.x2_5,
horizontal = 10.dp,
vertical = 10.dp,
),
) {
Icon(
imageVector = ImageVector.vectorResource(item.iconResId),
contentDescription = null,
tint = if (item.isWarning) {
TangemTheme.colors2.graphic.status.warning
TangemTheme.colors3.icon.accent.red
} else {
TangemTheme.colors2.graphic.neutral.primary
TangemTheme.colors3.icon.primary
},
modifier = Modifier
.size(TangemTheme.dimens2.x5)
.size(20.dp)
.testTag(BaseBottomSheetTestTags.ACTION_ICON),
)
Text(
text = item.text.resolveReference(),
style = TangemTheme.typography2.headingRegular17,
style = TangemTheme.typography3.body.medium,
color = if (item.isWarning) {
TangemTheme.colors2.text.status.warning
TangemTheme.colors3.text.accent.red
} else {
TangemTheme.colors2.text.neutral.primary
TangemTheme.colors3.text.primary
},
)
}
if (item.hasDivider) {
Spacer(
modifier = Modifier
.padding(vertical = TangemTheme.dimens2.x1)
.padding(vertical = 4.dp)
.fillMaxWidth()
.height(1.dp)
.background(TangemTheme.colors2.border.neutral.primary),
.background(TangemTheme.colors3.border.primary),
)
}
}

View file

@ -29,7 +29,7 @@ internal object WalletBalancePreview {
styledStringReference(
".56",
{
TangemTheme.typography2.headingRegular28.toSpanStyle()
TangemTheme.typography3.heading.medium.toSpanStyle()
},
),
stringReference(" $"),
@ -55,7 +55,7 @@ internal object WalletBalancePreview {
styledStringReference(
".56",
{
TangemTheme.typography2.headingRegular28.toSpanStyle()
TangemTheme.typography3.heading.medium.toSpanStyle()
},
),
stringReference(" $"),

View file

@ -8,7 +8,6 @@ import com.tangem.core.ui.ds.button.TangemButtonUM
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
/**
@ -27,16 +26,7 @@ internal sealed class WalletActionButtons(
val buttonUM: TangemButtonUM
get() = TangemButtonUM(
text = text,
tangemIconUM = TangemIconUM.Icon(
iconRes = iconRes,
tintReference = {
if (isEnabled) {
TangemTheme.colors2.graphic.neutral.primary
} else {
TangemTheme.colors2.graphic.neutral.quaternary
}
},
),
tangemIconUM = TangemIconUM.Icon(iconRes = iconRes),
type = TangemButtonType.Secondary,
shape = TangemButtonShape.Rounded,
onClick = onClick,

View file

@ -103,14 +103,14 @@ internal class SetTokenListErrorTransformer(
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
spanStyleReference = { SpanStyle(color = TangemTheme.colors3.text.secondary) },
)
},
balance = BigDecimal.ZERO.formatStyled {
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
spanStyleReference = { TangemTheme.typography2.headingRegular28.toSpanStyle() },
spanStyleReference = { TangemTheme.typography3.heading.medium.toSpanStyle() },
)
},
isZeroBalance = true,

View file

@ -52,7 +52,7 @@ internal class MultiWalletBalanceUMTransformer(
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
spanStyleReference = { SpanStyle(color = TangemTheme.colors3.text.secondary) },
)
},
balance = fiatBalance.amount.formatStyled {
@ -60,7 +60,7 @@ internal class MultiWalletBalanceUMTransformer(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
spanStyleReference = {
TangemTheme.typography2.headingRegular28.toSpanStyle()
TangemTheme.typography3.heading.medium.toSpanStyle()
},
)
},

View file

@ -36,6 +36,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.semantics.clearAndSetSemantics
@ -46,7 +47,6 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.ExperimentalDecomposeApi
import com.tangem.core.ui.components.atoms.handComposableComponentHeight
import com.tangem.core.ui.components.background.northernlights.NorthernLightsBackground
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheetDraggableHeader
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
@ -181,9 +181,6 @@ private fun WalletContent2(
onBottomSheetStateChange: (BottomSheetState) -> Unit,
bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit,
) {
val density = LocalDensity.current
val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(this).toDp() }
var walletBalance by remember { mutableStateOf<TextReference?>(TextReference.EMPTY) }
var pullToRefreshConfig by remember {
mutableStateOf(
@ -207,10 +204,15 @@ private fun WalletContent2(
)
},
) { paddingValues, bottomSheetState ->
val marketHintApproxHeight = 140.dp
val density = LocalDensity.current
var marketsHintHeight by remember { mutableStateOf(0.dp) }
val collapsedBodyOverhang = with(density) { behavior.state.partialHeightLimit.toDp() }
val contentPadding = PaddingValues(
bottom = paddingValues.calculateBottomPadding() + marketHintApproxHeight,
bottom = paddingValues.calculateBottomPadding() +
marketsHintHeight +
collapsedBodyOverhang +
TangemTheme.dimens2.x2,
)
val selectedWalletIndex by rememberUpdatedState(state.selectedWalletIndex)
@ -235,22 +237,17 @@ private fun WalletContent2(
.fillMaxSize()
.hazeSourceTangem(zIndex = -2f),
) {
val backgroundColor = if (LocalIsInDarkTheme.current) {
TangemTheme.colors2.surface.level1
} else {
TangemTheme.colors2.surface.level2
}
Box(
modifier = Modifier
.matchParentSize()
.background(backgroundColor),
.background(TangemTheme.colors3.bg.primary),
)
val isSheetExpanded by remember {
derivedStateOf { bottomSheetState.targetValue == TangemSheetValue.Expanded }
}
if (!isSheetExpanded) {
NorthernLightsBackground(
containerColor = backgroundColor,
containerColor = TangemTheme.colors3.bg.primary,
modifier = Modifier
.graphicsLayer { alpha = 1 - behavior.state.collapsedFraction * 2 }
.matchParentSize(),
@ -262,10 +259,10 @@ private fun WalletContent2(
pullToRefreshState = pullToRefreshState,
pullToRefreshConfig = pullToRefreshConfig,
behavior = behavior,
topOffset = subtitleBottom + TangemTheme.dimens2.x2,
topOffset = subtitleBottom + 8.dp,
)
val overlay = TangemTheme.colors2.overlay.overlayPrimary
val overlay = TangemTheme.colors3.material.tint.solid
// Root-coordinates bounds of the "Add & Manage" button per pager page, reported by the
// button itself, so the markets hint and tooltip can avoid covering it
@ -376,14 +373,14 @@ private fun WalletContent2(
},
)
}
val peekHeight =
bottomSheetHeaderHeightProvider() + handComposableComponentHeight + bottomBarHeight
MarketsHint(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth(fraction = .6f)
.padding(bottom = peekHeight),
.padding(bottom = paddingValues.calculateBottomPadding())
.onSizeChanged { size ->
marketsHintHeight = with(density) { size.height.toDp() }
},
isVisible = isShowMarketsHint,
obstacleBounds = remember(currentWalletIndex) {
{ organizeButtonBounds[currentWalletIndex] }
@ -400,7 +397,7 @@ private fun WalletContent2(
.fillMaxWidth(),
isVisible = state.showMarketsOnboarding,
availableHeight = maxHeight,
sheetTopInset = TangemTheme.dimens2.x3,
sheetTopInset = 12.dp,
bottomSheetState = bottomSheetState,
onCloseClick = state.onDismissMarketsTooltip,
obstacleBounds = remember(walletsPagerState, organizeButtonBounds) {
@ -425,15 +422,15 @@ private inline fun BaseScaffoldWithMarkets(
) {
val density = LocalDensity.current
val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(density = this).toDp() }
val peekHeight = bottomSheetHeaderHeightProvider() + TangemTheme.dimens2.x3 + bottomBarHeight
val peekHeight = bottomSheetHeaderHeightProvider() + 12.dp + bottomBarHeight
val coroutineScope = rememberCoroutineScope()
val bottomSheetState = rememberTangemStandardBottomSheetState()
val scaffoldState = rememberTangemBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
val expandedBackground = TangemTheme.colors2.surface.level2
val collapsedBackground = TangemTheme.colors2.surface.level3
val expandedBackground = TangemTheme.colors3.bg.primary
val collapsedBackground = TangemTheme.colors3.bg.secondary
val background by animateColorAsState(
targetValue = if (bottomSheetState.targetValue == TangemSheetValue.Expanded) {
expandedBackground
@ -527,8 +524,8 @@ private fun BottomSheet(
val maxHeight = LocalWindowSize.current.height
val shape = RoundedCornerShape(
topStart = TangemTheme.dimens2.x8,
topEnd = TangemTheme.dimens2.x8,
topStart = 32.dp,
topEnd = 32.dp,
)
CustomBottomSheet(
state = bottomSheetState,

View file

@ -61,14 +61,14 @@ internal fun MarketsHint(isVisible: Boolean, modifier: Modifier = Modifier, obst
) {
Text(
text = stringResourceSafe(R.string.markets_hint),
style = TangemTheme.typography2.bodyRegular15,
color = TangemTheme.colors2.text.neutral.tertiary,
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.secondary,
textAlign = TextAlign.Center,
)
Icon(
modifier = Modifier.size(size = 24.dp),
painter = painterResource(id = R.drawable.ic_chevron_24),
tint = TangemTheme.colors2.graphic.neutral.tertiary,
tint = TangemTheme.colors3.icon.secondary,
contentDescription = null,
)
}

View file

@ -32,9 +32,13 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.*
import com.tangem.core.ui.components.sheetscaffold.TangemSheetState
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_cross_20
import com.tangem.core.ui.test.MarketTooltipTestTags
import com.tangem.core.ui.utils.toPx
import com.tangem.feature.wallet.impl.R
@ -118,14 +122,14 @@ internal fun MarketsTooltip(
@Composable
internal fun MarketsTooltipContent(onCloseClick: () -> Unit, modifier: Modifier = Modifier) {
val backgroundColor = TangemTheme.colors.background.action
val backgroundColor = TangemTheme.colors3.bg.tertiary
val tipDpSize = DpSize(width = 20.dp, height = 8.dp)
val tooltipShape = remember(tipDpSize) { TooltipShape(cornerRadius = 16.dp, tipSize = tipDpSize) }
Row(
modifier = modifier
.shadow(
elevation = TangemTheme.dimens.elevation12,
elevation = 12.dp,
shape = tooltipShape,
clip = false,
ambientColor = Color.Black.copy(alpha = 0.7f),
@ -149,27 +153,21 @@ internal fun MarketsTooltipContent(onCloseClick: () -> Unit, modifier: Modifier
) {
Text(
text = stringResourceSafe(id = R.string.markets_tooltip_v2_title),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.primary,
)
Text(
text = stringResourceSafe(id = R.string.markets_tooltip_message),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
style = TangemTheme.typography3.caption.medium,
color = TangemTheme.colors3.text.secondary,
)
}
Icon(
modifier = Modifier
.size(size = 16.dp)
.clickable(
interactionSource = null,
indication = null,
onClick = onCloseClick,
)
.testTag(MarketTooltipTestTags.CLOSE_BUTTON),
painter = painterResource(id = R.drawable.ic_close_24),
tint = TangemTheme.colors.icon.informative,
contentDescription = null,
TangemButton(
variant = TangemButton.Variant.Ghost,
size = TangemButton.Size.X7,
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_cross_20),
onClick = onCloseClick,
modifier = Modifier.testTag(MarketTooltipTestTags.CLOSE_BUTTON),
)
}
}

View file

@ -9,7 +9,7 @@ import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.boundsInRoot
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.ds.button.TangemButton
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.res.LocalHapticManager
@ -26,7 +26,7 @@ internal const val ORGANIZE_TOKENS_BUTTON_ITEM_KEY = "OrganizeTokensButton"
internal fun LazyListScope.nftCollections2(state: WalletUM, itemModifier: Modifier) {
(state as? WalletUM.Content)?.let { content ->
item(key = "NFTCollections", contentType = "NFTCollections") {
WalletNFTItem(
WalletNFTItem2(
modifier = itemModifier,
state = content.nftState,
)
@ -62,15 +62,18 @@ internal fun LazyListScope.organizeTokens2(
}
TangemButton(
buttonUM = organizeButton.copy(
onClick = {
hapticManager.perform(TangemHapticEffect.View.ContextClick)
organizeButton.onClick()
},
),
modifier = itemModifier
.onGloballyPositioned { currentOnButtonBoundsChange(it.boundsInRoot()) }
.testTag(testTag),
size = TangemButton.Size.X9,
onClick = {
hapticManager.perform(TangemHapticEffect.View.ContextClick)
organizeButton.onClick()
},
variant = TangemButton.Variant.Secondary,
iconStart = organizeButton.tangemIconUM,
text = organizeButton.text,
isEnabled = organizeButton.isEnabled,
)
}
}

View file

@ -41,7 +41,7 @@ import kotlinx.collections.immutable.persistentListOf
internal fun WalletNFTItem2(state: WalletNFTItemUM, modifier: Modifier = Modifier) {
val nftModifier = modifier
.clip(RoundedCornerShape(18.dp))
.background(TangemTheme.colors2.surface.level3)
.background(TangemTheme.colors3.bg.secondary)
when (state) {
is WalletNFTItemUM.Hidden -> Unit
is WalletNFTItemUM.Empty -> WalletNFTItemEmpty(
@ -70,13 +70,13 @@ private fun WalletNFTItemEmpty(onClick: () -> Unit, modifier: Modifier = Modifie
painter = painterResource(R.drawable.img_nft_empty_collection),
contentDescription = null,
modifier = Modifier
.size(TangemTheme.dimens2.x10)
.size(40.dp)
.layoutId(TangemRowLayoutId.HEAD),
)
Text(
text = stringResourceSafe(R.string.nft_wallet_title),
style = TangemTheme.typography2.bodySemibold16,
color = TangemTheme.colors2.text.neutral.primary,
style = TangemTheme.typography3.body.medium,
color = TangemTheme.colors3.text.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
@ -85,8 +85,8 @@ private fun WalletNFTItemEmpty(onClick: () -> Unit, modifier: Modifier = Modifie
)
Text(
text = stringResourceSafe(R.string.nft_wallet_receive_nft),
style = TangemTheme.typography2.captionSemibold12,
color = TangemTheme.colors2.text.neutral.secondary,
style = TangemTheme.typography3.caption.medium,
color = TangemTheme.colors3.text.secondary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
@ -96,7 +96,7 @@ private fun WalletNFTItemEmpty(onClick: () -> Unit, modifier: Modifier = Modifie
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24),
contentDescription = null,
tint = TangemTheme.colors2.graphic.neutral.tertiaryConstant,
tint = TangemTheme.colors3.icon.secondary,
modifier = Modifier.layoutId(TangemRowLayoutId.TAIL),
)
}
@ -116,9 +116,9 @@ private fun WalletNFTItemContent(state: WalletNFTItemUM.Content, onClick: () ->
}
Text(
text = stringResourceSafe(R.string.nft_wallet_title),
style = TangemTheme.typography2.bodySemibold16.applyBladeBrush(
style = TangemTheme.typography3.body.medium.applyBladeBrush(
isEnabled = state.isFlickering,
textColor = TangemTheme.colors2.text.neutral.primary,
textColor = TangemTheme.colors3.text.primary,
),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@ -132,9 +132,9 @@ private fun WalletNFTItemContent(state: WalletNFTItemUM.Content, onClick: () ->
state.allAssetsCount,
state.collectionsCount,
),
style = TangemTheme.typography2.captionSemibold12.applyBladeBrush(
style = TangemTheme.typography3.caption.medium.applyBladeBrush(
isEnabled = state.isFlickering,
textColor = TangemTheme.colors2.text.neutral.secondary,
textColor = TangemTheme.colors3.text.secondary,
),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@ -145,7 +145,7 @@ private fun WalletNFTItemContent(state: WalletNFTItemUM.Content, onClick: () ->
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24),
contentDescription = null,
tint = TangemTheme.colors2.graphic.neutral.tertiaryConstant,
tint = TangemTheme.colors3.icon.secondary,
modifier = Modifier.layoutId(TangemRowLayoutId.TAIL),
)
}
@ -173,8 +173,8 @@ private fun WalletNFTItemFailed(modifier: Modifier = Modifier) {
}
Text(
text = stringResourceSafe(R.string.nft_wallet_title),
style = TangemTheme.typography2.bodySemibold16,
color = TangemTheme.colors2.text.neutral.primary,
style = TangemTheme.typography3.body.medium,
color = TangemTheme.colors3.text.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
@ -183,8 +183,8 @@ private fun WalletNFTItemFailed(modifier: Modifier = Modifier) {
)
Text(
text = stringResourceSafe(R.string.nft_wallet_unable_to_load),
style = TangemTheme.typography2.captionSemibold12,
color = TangemTheme.colors2.text.neutral.secondary,
style = TangemTheme.typography3.caption.medium,
color = TangemTheme.colors3.text.secondary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
@ -207,7 +207,7 @@ private fun WalletNFTItemLoading(modifier: Modifier = Modifier) {
.layoutId(TangemRowLayoutId.HEAD),
)
TextShimmer(
style = TangemTheme.typography2.bodySemibold16,
style = TangemTheme.typography3.body.medium,
radius = TangemTheme.dimens2.x25,
modifier = Modifier
@ -216,7 +216,7 @@ private fun WalletNFTItemLoading(modifier: Modifier = Modifier) {
.width(TangemTheme.dimens.size110),
)
TextShimmer(
style = TangemTheme.typography2.captionSemibold12,
style = TangemTheme.typography3.caption.medium,
radius = TangemTheme.dimens2.x25,
modifier = Modifier
.layoutId(TangemRowLayoutId.START_BOTTOM)
@ -251,7 +251,7 @@ private fun BoxScope.CollectionsPreviews(previews: ImmutableList<CollectionPrevi
},
error = {
Box(
modifier = previewModifier.background(TangemTheme.colors2.surface.level2),
modifier = previewModifier.background(TangemTheme.colors3.bg.primary),
)
},
contentDescription = null,
@ -259,10 +259,9 @@ private fun BoxScope.CollectionsPreviews(previews: ImmutableList<CollectionPrevi
}
is CollectionPreview.More -> {
Icon(
modifier = previewModifier
.background(TangemTheme.colors2.surface.level2),
modifier = previewModifier.background(TangemTheme.colors3.bg.primary),
imageVector = ImageVector.vectorResource(R.drawable.ic_nft_preview_more_16),
tint = TangemTheme.colors2.text.neutral.secondary,
tint = TangemTheme.colors3.text.secondary,
contentDescription = null,
)
}
@ -289,7 +288,7 @@ private fun BoxScope.previews2Modifiers(): List<Modifier> = listOf(
.zIndex(1f)
.padding(TangemTheme.dimens2.x0_5)
.clip(RoundedCornerShape(topStart = 10.dp))
.background(TangemTheme.colors2.surface.level3)
.background(TangemTheme.colors3.bg.secondary)
.padding(start = TangemTheme.dimens2.x0_5, top = TangemTheme.dimens2.x0_5)
.size(TangemTheme.dimens2.x6)
.clip(RoundedCornerShape(TangemTheme.dimens2.x2))
@ -307,7 +306,7 @@ private fun BoxScope.previews3Modifiers(): List<Modifier> = listOf(
.zIndex(1f)
.padding(top = 10.dp, end = 1.dp)
.clip(RoundedCornerShape(8.dp))
.background(TangemTheme.colors2.surface.level3)
.background(TangemTheme.colors3.bg.secondary)
.padding(TangemTheme.dimens2.x0_5)
.size(18.dp)
.clip(RoundedCornerShape(6.dp))
@ -347,7 +346,7 @@ private fun Preview_WalletNFTItem(@PreviewParameter(WalletNFTItemProvider2::clas
WalletNFTItem2(
state = state,
modifier = Modifier
.background(TangemTheme.colors2.surface.level1),
.background(TangemTheme.colors3.bg.primary),
)
}
}

View file

@ -102,7 +102,7 @@ internal fun WalletBalance(
walletBalanceUM = walletBalanceUM,
isBalanceHidden = isBalanceHidden,
)
SpacerH(TangemTheme.dimens2.x3)
SpacerH(12.dp)
Box(
modifier = Modifier.onGloballyPositioned { coordinates ->
val rawBottomPx = coordinates.boundsInRoot().bottom
@ -113,9 +113,9 @@ internal fun WalletBalance(
SubtitleRow(walletBalanceUM = walletBalanceUM)
}
}
SpacerH(TangemTheme.dimens2.x2)
SpacerH(8.dp)
ActionButtons(buttons = hapticButtons, modifier = Modifier.fillMaxWidth())
SpacerH(TangemTheme.dimens2.x6)
SpacerH(24.dp)
}
}
@ -140,20 +140,20 @@ private fun SubtitleRow(walletBalanceUM: WalletBalanceUM, modifier: Modifier = M
is WalletAdditionalInfo.Content.SyncProgress -> {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1_5),
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
Text(
text = resourceReference(
id = R.string.initial_wallet_sync_restore_progress,
formatArgs = wrappedList(content.progressPercent),
).resolveReference(),
style = TangemTheme.typography2.bodyRegular14,
color = TangemTheme.colors2.text.neutral.tertiary,
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.secondary,
modifier = Modifier.testTag(MainScreenTestTags.SYNC_PROGRESS_TEXT),
)
CircularProgressIndicator(
modifier = Modifier.size(19.dp),
color = TangemTheme.colors2.graphic.neutral.primary,
color = TangemTheme.colors3.icon.secondary,
strokeWidth = 2.dp,
)
}
@ -161,12 +161,12 @@ private fun SubtitleRow(walletBalanceUM: WalletBalanceUM, modifier: Modifier = M
else -> {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
text = walletBalanceUM.name,
style = TangemTheme.typography2.bodyRegular14,
color = TangemTheme.colors2.text.neutral.tertiary,
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.secondary,
modifier = Modifier.testTag(MainScreenTestTags.CARD_TITLE),
)
TangemDeviceIcon(
@ -194,36 +194,36 @@ private fun Balance(walletBalanceUM: WalletBalanceUM, isBalanceHidden: Boolean,
when (balanceUM) {
is WalletBalanceUM.Content -> Text(
text = balanceUM.balance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
style = TangemTheme.typography2.titleRegular44.applyBladeBrush(
style = TangemTheme.typography3.display.medium.applyBladeBrush(
isEnabled = balanceUM.isBalanceFlickering,
textColor = TangemTheme.colors2.text.neutral.primary,
textColor = TangemTheme.colors3.text.primary,
),
color = TangemTheme.colors2.text.neutral.primary,
color = TangemTheme.colors3.text.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
autoSize = TextAutoSize.StepBased(
minFontSize = TangemTheme.typography2.bodySemibold15.fontSize,
maxFontSize = TangemTheme.typography2.titleRegular44.fontSize,
minFontSize = TangemTheme.typography3.body.medium.fontSize,
maxFontSize = TangemTheme.typography3.display.medium.fontSize,
),
)
is WalletBalanceUM.Error -> Text(
text = StringsSigns.DASH_SIGN,
style = TangemTheme.typography2.titleRegular44,
color = TangemTheme.colors2.text.neutral.primary,
style = TangemTheme.typography3.display.medium,
color = TangemTheme.colors3.text.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
autoSize = TextAutoSize.StepBased(
minFontSize = TangemTheme.typography2.bodySemibold15.fontSize,
maxFontSize = TangemTheme.typography2.titleRegular44.fontSize,
minFontSize = TangemTheme.typography3.body.medium.fontSize,
maxFontSize = TangemTheme.typography3.display.medium.fontSize,
),
)
is WalletBalanceUM.Loading -> TextShimmer(
text = "123456",
style = TangemTheme.typography2.titleRegular44,
radius = TangemTheme.dimens2.x25,
style = TangemTheme.typography3.display.medium,
radius = 100.dp,
)
is WalletBalanceUM.Empty -> TextPlaceholder(
textStyle = TangemTheme.typography2.titleRegular44,
textStyle = TangemTheme.typography3.display.medium,
width = 200.dp,
)
}
@ -244,7 +244,7 @@ private fun WalletBalance_Preview(
behavior = rememberTangemExitUntilCollapsedScrollBehavior(),
buttons = params.actionsList,
isBalanceHidden = false,
modifier = Modifier.background(TangemTheme.colors2.surface.level1),
modifier = Modifier.background(TangemTheme.colors3.bg.secondary),
)
}
}

View file

@ -46,10 +46,10 @@ internal fun WalletListContent(
promoBannersBlockComponent: PromoBannersBlockComponent? = null,
walletId: String? = null,
) {
val containerColor = TangemTheme.colors2.surface.level1
val containerColor = TangemTheme.colors3.bg.primary
val movableItemModifier = Modifier.padding(horizontal = TangemTheme.dimens2.x3)
val itemModifier = movableItemModifier.padding(top = TangemTheme.dimens2.x3)
val movableItemModifier = Modifier.padding(horizontal = 12.dp)
val itemModifier = movableItemModifier.padding(top = 12.dp)
LazyColumn(
modifier = modifier.testTag(MainScreenTestTags.SCREEN_CONTAINER),
@ -73,7 +73,7 @@ internal fun WalletListContent(
item(key = "PromoBannersBlock") {
component.ContentWithPadding(
horizontalItemPadding = 12.dp,
modifier = Modifier.padding(top = TangemTheme.dimens2.x3),
modifier = Modifier.padding(top = 12.dp),
walletId = walletId,
)
}

View file

@ -1,41 +1,41 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.common
import android.content.res.Configuration
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.*
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.haze.hazeEffectTangem
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds.topbar.TangemTopBarActionContent
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.topbar.TangemTopBarActionUM
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.topnavigation.TangemNavigationText
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.orMaskWithStars
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.res.*
import com.tangem.core.ui.res.LocalHapticManager
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.test.MainScreenTestTags
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTopBarConfig
import dev.chrisbanes.haze.HazeProgressive
import dev.chrisbanes.haze.HazeTint
import kotlinx.collections.immutable.persistentListOf
private const val VISIBILITY_THRESHOLD = 0.5f
private val BRAND_ICON_SLOT_SIZE = 44.dp
/**
* Wallet screen collapsing top bar
@ -53,76 +53,54 @@ internal fun WalletTopBar(
behavior: TangemCollapsingAppBarBehavior,
) {
val hapticManager = LocalHapticManager.current
Surface(
color = Color.Unspecified,
contentColor = Color.Unspecified,
modifier = Modifier.hazeEffectTangemTopBar(behavior),
) {
val isWrappedBalanceShown by remember {
derivedStateOf { behavior.state.collapsedFraction > VISIBILITY_THRESHOLD }
}
val isWrappedBalanceShown by remember {
derivedStateOf { behavior.state.collapsedFraction > VISIBILITY_THRESHOLD }
}
val wrappedBalance = remember(walletBalance, isWrappedBalanceShown, isBalanceHidden) {
walletBalance?.orMaskWithStars(isBalanceHidden).takeIf { isWrappedBalanceShown }
}
val wrappedBalance = remember(walletBalance, isWrappedBalanceShown, isBalanceHidden) {
walletBalance?.orMaskWithStars(isBalanceHidden).takeIf { isWrappedBalanceShown }
}
TangemTopBar(
title = wrappedBalance,
startContent = {
TangemTopBarActionContent(
TangemTopBarActionUM(
iconRes = R.drawable.ic_tangem_24,
isActionable = false,
),
TangemTopNavigation(
modifier = Modifier.testTag(MainScreenTestTags.TOP_BAR),
contentAlign = TangemTopNavigation.ContentAlign.Center,
startButton = {
// Non-clickable brand mark, sized to align with the trailing action buttons.
Box(modifier = Modifier.size(BRAND_ICON_SLOT_SIZE), contentAlignment = Alignment.Center) {
Icon(
painter = painterResource(id = R.drawable.ic_tangem_24),
contentDescription = null,
tint = TangemTheme.colors3.icon.primary,
)
},
endContent = {
Row(
modifier = Modifier
.clip(CircleShape)
.background(
lerp(
start = Color.Transparent,
stop = TangemTheme.colors2.button.backgroundSecondary,
fraction = behavior.state.collapsedFraction,
),
),
) {
topBarConfig.endActions.forEach { action ->
TangemTopBarActionContent(
action.copy(
onClick = action.onClick?.let { onClick ->
{
hapticManager.perform(TangemHapticEffect.View.ContextClick)
onClick()
}
},
),
modifier = Modifier.testTag(MainScreenTestTags.MORE_BUTTON),
)
}
}
},
endButtonsGroup = if (topBarConfig.endActions.isNotEmpty()) {
{
topBarConfig.endActions.forEach { action ->
TangemButton(
variant = TangemButton.Variant.Ghost,
size = TangemButton.Size.X11,
iconStart = TangemIconUM.Icon(iconRes = action.iconRes),
isEnabled = action.isActionable && action.onClick != null,
onClick = {
hapticManager.perform(TangemHapticEffect.View.ContextClick)
action.onClick?.invoke()
},
modifier = Modifier.testTag(MainScreenTestTags.MORE_BUTTON),
)
}
},
modifier = Modifier
.statusBarsPadding()
.testTag(MainScreenTestTags.TOP_BAR),
)
}
}
@Composable
private fun Modifier.hazeEffectTangemTopBar(behavior: TangemCollapsingAppBarBehavior): Modifier {
val rootBackground by LocalRootBackgroundColor.current
val intensity by animateFloatAsState(targetValue = behavior.state.collapsedFraction * 2f)
return hazeEffectTangem {
fallbackTint = HazeTint(rootBackground.copy(alpha = intensity / 2))
progressive = HazeProgressive.verticalGradient(
startIntensity = intensity,
endIntensity = 0f,
preferPerformance = true,
)
}
}
} else {
null
},
contentColumn = {
AnimatedVisibility(visible = wrappedBalance != null) {
wrappedBalance?.let { balance ->
TangemNavigationText(text = balance, role = TangemNavigationText.Role.Title)
}
}
},
)
}
// region Preview

View file

@ -40,9 +40,6 @@ import com.tangem.core.ui.components.tokenlist.NON_CONTENT_TOKENS_LIST_KEY
import com.tangem.core.ui.components.tokenlist.TokenListItem
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.ds.button.SecondaryTangemButton
import com.tangem.core.ui.ds.button.TangemButtonShape
import com.tangem.core.ui.ds.button.TangemButtonSize
import com.tangem.core.ui.ds.image.TangemIcon
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.row.header.TangemHeaderRow
@ -51,6 +48,7 @@ import com.tangem.core.ui.ds.row.internal.TangemRowTailUM
import com.tangem.core.ui.ds.row.token.TangemTokenRow
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.MainScreenTestTags
@ -159,13 +157,13 @@ private fun LazyListScope.tokenItem(
val itemModifier = modifier
.testTag(MainScreenTestTags.TOKEN_LIST_ITEM)
.semantics { lazyListItemPosition = index }
.padding(top = if (index == 0) TangemTheme.dimens2.x3 else 0.dp)
.padding(top = if (index == 0) 12.dp else 0.dp)
.roundedShapeItemDecoration(
radius = 18.dp,
currentIndex = index,
addDefaultPadding = false,
lastIndex = lastIndex,
backgroundColor = TangemTheme.colors2.surface.level3,
backgroundColor = TangemTheme.colors3.bg.secondary,
)
var position by remember { mutableStateOf(Offset.Zero) }
@ -261,11 +259,11 @@ private fun LazyListScope.portfolioItem(
modifier = modifier
.animateItem(fadeInSpec = null, placementSpec = null, fadeOutSpec = null)
.roundedShapeItemDecoration(
radius = if (listItem.isExpanded) TangemTheme.dimens2.x6 else TangemTheme.dimens2.x5,
radius = if (listItem.isExpanded) 24.dp else 20.dp,
currentIndex = tokenIndex + 1,
addDefaultPadding = false,
lastIndex = lastIndex,
backgroundColor = TangemTheme.colors2.surface.level3,
backgroundColor = TangemTheme.colors3.bg.secondary,
),
visible = listItem.isExpanded,
) {
@ -327,15 +325,15 @@ private fun LazyListScope.accountItem(
)
val portfolioModifier = modifier
.padding(top = if (index != 0) TangemTheme.dimens2.x2 else TangemTheme.dimens2.x3)
.padding(top = if (index != 0) 8.dp else 12.dp)
.testTag(MainScreenTestTags.ACCOUNT_LIST_ITEM)
.semantics { lazyListItemPosition = index }
.roundedShapeItemDecoration(
currentIndex = 0,
radius = if (listItem.isExpanded) TangemTheme.dimens2.x6 else TangemTheme.dimens2.x5,
radius = if (listItem.isExpanded) 24.dp else 20.dp,
addDefaultPadding = false,
lastIndex = effectiveLastIndex,
backgroundColor = TangemTheme.colors2.surface.level3,
backgroundColor = TangemTheme.colors3.bg.secondary,
)
if (listItem.isCollapsable) {
PortfolioRowItem(
@ -422,7 +420,7 @@ internal fun PortfolioRowItem(
}
val iconBoxSize = when (headIcon) {
is TangemIconUM.Empty -> TangemTheme.dimens2.x9
is TangemIconUM.Empty -> 36.dp
else -> size.toBoxSize()
}
TangemIcon(
@ -444,8 +442,8 @@ internal fun PortfolioRowItem(
animationSpec = tween(durationMillis = 350),
)
val startStyle = TangemTheme.typography2.captionSemibold12
val stopStyle = TangemTheme.typography2.bodySemibold16
val startStyle = TangemTheme.typography3.caption.medium
val stopStyle = TangemTheme.typography3.body.medium
val textStyle by remember(animationFraction.value) {
derivedStateOf { lerp(startStyle, stopStyle, animationFraction.value) }
@ -509,7 +507,7 @@ private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
NonContentItemContent(
modifier = modifier
.animateItem(fadeInSpec = null, fadeOutSpec = null)
.padding(top = TangemTheme.dimens.spacing96),
.padding(top = 96.dp),
)
}
}
@ -521,7 +519,7 @@ private fun LazyListScope.nonContentItem2(onEmptyClick: () -> Unit, modifier: Mo
) {
NonContentItemContentV2(
onClick = onEmptyClick,
textColor = TangemTheme.colors2.text.neutral.tertiary,
textColor = TangemTheme.colors3.text.secondary,
modifier = modifier
.animateItem(fadeInSpec = null, fadeOutSpec = null)
.padding(top = 46.dp),
@ -540,17 +538,17 @@ private fun LazyListScope.nonContentAccountItem(listItem: TokensListItemUM2.Port
modifier = modifier
.animateItem(fadeInSpec = null, placementSpec = null, fadeOutSpec = null)
.roundedShapeItemDecoration(
radius = if (listItem.isExpanded) TangemTheme.dimens2.x6 else TangemTheme.dimens2.x5,
radius = if (listItem.isExpanded) 24.dp else 20.dp,
addDefaultPadding = false,
currentIndex = 1,
lastIndex = 1,
backgroundColor = TangemTheme.colors2.surface.level3,
backgroundColor = TangemTheme.colors3.bg.secondary,
),
visible = listItem.isExpanded,
) {
NonContentItemContentV2(
modifier = Modifier.padding(vertical = 36.dp),
textColor = TangemTheme.colors2.text.neutral.secondary,
textColor = TangemTheme.colors3.text.secondary,
onClick = listItem.onEmptyClick,
)
}
@ -566,23 +564,23 @@ internal fun NonContentItemContentV2(textColor: Color, modifier: Modifier = Modi
Icon(
painter = painterResource(id = R.drawable.ic_empty_64),
contentDescription = null,
modifier = Modifier.size(size = TangemTheme.dimens2.x16),
tint = TangemTheme.colors2.graphic.neutral.quaternary,
modifier = Modifier.size(64.dp),
tint = TangemTheme.colors3.icon.tertiary,
)
SpacerH(TangemTheme.dimens2.x5)
SpacerH(20.dp)
Text(
text = stringResourceSafe(id = R.string.main_empty_tokens_list_message),
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing48),
modifier = Modifier.padding(horizontal = 48.dp),
color = textColor,
textAlign = TextAlign.Center,
style = TangemTheme.typography2.bodyRegular14,
style = TangemTheme.typography3.subheading.medium,
)
SpacerH(TangemTheme.dimens2.x4)
SecondaryTangemButton(
SpacerH(16.dp)
TangemButton(
text = resourceReference(id = R.string.common_add_tokens),
variant = TangemButton.Variant.Secondary,
size = TangemButton.Size.X9,
onClick = onClick,
size = TangemButtonSize.X8,
shape = TangemButtonShape.Rounded,
modifier = Modifier.testTag(MainScreenTestTags.EMPTY_TOKENS_ADD_BUTTON),
)
}