Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-29 16:28:48 +03:00
parent 557e8eceb6
commit 5fda020fc3
58 changed files with 587 additions and 557 deletions

View file

@ -17,6 +17,8 @@ import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.test.MarketsTestTags
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -116,6 +118,7 @@ private fun Content(
LazyColumn(
state = lazyListState,
contentPadding = PaddingValues(bottom = bottomBarHeight, top = contentPadding.calculateTopPadding()),
modifier = Modifier.testTag(MarketsTestTags.TOKEN_DETAILS_CONTENT),
) {
item("header") {
Header(state = state)

View file

@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@ -48,6 +49,7 @@ import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds.topbar.TangemTopBarType
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.test.TokenElementsTestTags
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemThemePreviewRedesign
@ -314,13 +316,15 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif
tangemIconUM = exchangeItemUM.icon,
modifier = Modifier
.layoutId(layoutId = TangemRowLayoutId.HEAD)
.size(TangemTheme.dimens2.x10),
.size(TangemTheme.dimens2.x10)
.testTag(TokenElementsTestTags.TOKEN_ICON),
)
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens2.x2)
.layoutId(TangemRowLayoutId.START_TOP),
.layoutId(TangemRowLayoutId.START_TOP)
.testTag(TokenElementsTestTags.TOKEN_TITLE),
text = exchangeItemUM.title.resolveReference(),
style = TangemTheme.typography2.bodySemibold16,
color = TangemTheme.colors2.text.neutral.primary,
@ -329,7 +333,8 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens2.x2)
.layoutId(TangemRowLayoutId.START_BOTTOM),
.layoutId(TangemRowLayoutId.START_BOTTOM)
.testTag(TokenElementsTestTags.TOKEN_PRICE),
text = exchangeItemUM.subTitle.resolveReference(),
style = TangemTheme.typography2.captionSemibold12,
color = TangemTheme.colors2.text.neutral.secondary,
@ -338,7 +343,8 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif
Text(
modifier = Modifier
.padding(start = TangemTheme.dimens2.x2)
.layoutId(TangemRowLayoutId.END_TOP),
.layoutId(TangemRowLayoutId.END_TOP)
.testTag(TokenElementsTestTags.TOKEN_FIAT_AMOUNT_TEXT),
text = exchangeItemUM.volumeInUsd.resolveReference(),
style = TangemTheme.typography2.bodySemibold16,
color = TangemTheme.colors2.text.neutral.primary,
@ -351,7 +357,8 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif
shape = CircleShape,
)
.padding(vertical = 2.dp, horizontal = 6.dp)
.layoutId(TangemRowLayoutId.END_BOTTOM),
.layoutId(TangemRowLayoutId.END_BOTTOM)
.testTag(TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT),
text = exchangeItemUM.auditLabel.text.resolveReference(),
style = TangemTheme.typography2.captionSemibold11,
color = getColorByTrustValue(exchangeItemUM.auditLabel.type),

View file

@ -10,10 +10,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -65,7 +64,8 @@ private fun ListedOnBlockV1(state: ListedOnUM, modifier: Modifier = Modifier) {
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
.clickable(enabled = state is ListedOnUM.Content) {
(state as? ListedOnUM.Content)?.onClick?.invoke()
},
}
.testTag(MarketsTestTags.LISTED_ON_BLOCK),
) {
Description(
state = state,
@ -89,9 +89,11 @@ private fun ListedOnBlockV1(state: ListedOnUM, modifier: Modifier = Modifier) {
@Composable
private fun ListedOnBlockV2(state: ListedOnUM, modifier: Modifier = Modifier) {
TokenMarketInformationBlock(
modifier = modifier.clickable(enabled = state is ListedOnUM.Content) {
(state as? ListedOnUM.Content)?.onClick?.invoke()
},
modifier = modifier
.clickable(enabled = state is ListedOnUM.Content) {
(state as? ListedOnUM.Content)?.onClick?.invoke()
}
.testTag(MarketsTestTags.LISTED_ON_BLOCK),
title = {
Row(verticalAlignment = Alignment.CenterVertically) {
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1)) {
@ -103,6 +105,7 @@ private fun ListedOnBlockV2(state: ListedOnUM, modifier: Modifier = Modifier) {
overflow = TextOverflow.Ellipsis,
)
Text(
modifier = Modifier.testTag(MarketsTestTags.LISTED_ON_EXCHANGES_COUNT),
text = state.description.resolveReference(),
style = TangemTheme.typography2.headingSemibold20,
color = TangemTheme.colors2.text.neutral.primary,
@ -178,7 +181,7 @@ internal fun ListedOnBlockPlaceholderV2(modifier: Modifier = Modifier) {
private fun Description(state: ListedOnUM, modifier: Modifier = Modifier) {
Text(
text = state.description.resolveReference(),
modifier = modifier.semantics { testTag = MarketsTestTags.LISTED_ON_EXCHANGES_COUNT },
modifier = modifier.testTag(MarketsTestTags.LISTED_ON_EXCHANGES_COUNT),
color = TangemTheme.colors.text.tertiary,
overflow = TextOverflow.Ellipsis,
maxLines = 1,

View file

@ -13,12 +13,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.account.AccountIconUM
import com.tangem.common.ui.earn.EarnBlock
import com.tangem.common.ui.earn.EarnBlockUM
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
import com.tangem.common.ui.notifications.notifications
@ -35,6 +37,7 @@ import com.tangem.core.ui.ds.button.TangemButtonUM
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.themedColor
import com.tangem.core.ui.res.LocalHazeState
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.domain.models.account.CryptoPortfolioIcon
@ -140,7 +143,7 @@ private fun BoxScope.TokenDetailsMarketBlockOverlay(
)
}
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
@Composable
private fun TokenDetailsBody(
tokenDetailsUM: TokenDetailsUM,
@ -165,6 +168,7 @@ private fun TokenDetailsBody(
LazyColumn(
modifier = modifier
.testTag(TokenDetailsScreenTestTags.SCREEN_CONTAINER)
.hazeSourceTangem(state = LocalHazeState.current)
.topFade(
height = topContentPadding,
@ -190,9 +194,18 @@ private fun TokenDetailsBody(
)
tokenDetailsUM.earnBlockState?.let { earnBlock ->
item(key = "staking_block") {
val stakingTag = when {
earnBlock is EarnBlockUM.Content &&
earnBlock.type == EarnBlockUM.Type.Staking &&
earnBlock.trailingUM is EarnBlockUM.TrailingUM.Button ->
TokenDetailsScreenTestTags.STAKING_AVAILABLE_BLOCK
else -> TokenDetailsScreenTestTags.STAKING_BLOCK
}
EarnBlock(
state = earnBlock,
modifier = itemModifier.padding(vertical = TangemTheme.dimens2.x3),
modifier = itemModifier
.padding(vertical = TangemTheme.dimens2.x3)
.testTag(stakingTag),
)
}
}

View file

@ -16,9 +16,18 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.*
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
import com.tangem.core.ui.test.TokenDetailsTopBarTestTags
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -58,7 +67,9 @@ internal fun TokenDetailsTopBar(topAppBarUM: TokenDetailsTopAppBarUM, modifier:
.clip(CircleShape)
.hazeEffectTangem { blurRadius = ACTION_BLUR_RADIUS }
TangemTopBar(
modifier = modifier.statusBarsPadding(),
modifier = modifier
.statusBarsPadding()
.testTag(TokenDetailsTopBarTestTags.BACK_BUTTON),
startContent = {
TangemTopBarActionContent(
modifier = actionModifier,
@ -73,7 +84,7 @@ internal fun TokenDetailsTopBar(topAppBarUM: TokenDetailsTopAppBarUM, modifier:
var isDropdownMenuShown by rememberSaveable { mutableStateOf(false) }
Box {
TangemTopBarActionContent(
modifier = actionModifier,
modifier = actionModifier.testTag(TokenDetailsTopBarTestTags.MORE_BUTTON),
actionUM = TangemTopBarActionUM(
iconRes = CoreUiR.drawable.ic_more_default_24,
onClick = { isDropdownMenuShown = true },
@ -105,7 +116,9 @@ internal fun TokenDetailsTopBar(topAppBarUM: TokenDetailsTopAppBarUM, modifier:
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x0_5),
) {
TokenDetailsTitle(titleState = topAppBarUM.titleState)
Box(modifier = Modifier.testTag(TokenDetailsScreenTestTags.TOKEN_TITLE)) {
TokenDetailsTitle(titleState = topAppBarUM.titleState)
}
Text(
text = topAppBarUM.subtitle.resolveAnnotatedReference(),
color = TangemTheme.colors2.text.neutral.tertiary,

View file

@ -96,6 +96,7 @@ internal fun OrganizeTokensContent(
onClick = { isShowDropdownMenu = true },
ghostModeProgress = 0f,
),
modifier = Modifier.testTag(OrganizeTokensScreenTestTags.MENU_BUTTON),
type = TangemTopBarType.BottomSheet,
)
OrganizeDropDownMenu(
@ -161,8 +162,7 @@ private fun TokenList(
modifier = Modifier
.align(Alignment.TopCenter)
.reorderable(reorderableListState)
.testTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST)
.hazeSourceTangem(zIndex = 1f),
.testTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST),
state = reorderableListState.listState,
contentPadding = listContentPadding,
) {
@ -221,7 +221,7 @@ private fun LazyItemScope.DraggableItem(
when (item) {
is OrganizeRowItemUM.Network -> TangemHeaderRow(
modifier = modifierWithBackground,
modifier = modifierWithBackground.testTag(OrganizeTokensScreenTestTags.GROUP_TITLE_ITEM),
reorderableState = reorderableState,
headerRowUM = item.headerRowUM,
)
@ -231,7 +231,7 @@ private fun LazyItemScope.DraggableItem(
isBalanceHidden = isBalanceHidden,
)
is OrganizeRowItemUM.Token -> OrganizeTokenRow(
modifier = modifierWithBackground,
modifier = modifierWithBackground.testTag(OrganizeTokensScreenTestTags.TOKEN_LIST_ITEM),
tokenRowUM = item.tokenRowUM,
reorderableState = reorderableState,
isBalanceHidden = isBalanceHidden,
@ -262,11 +262,15 @@ private fun BoxScope.BottomButtons(organizeTokensUM: OrganizeTokensUM) {
) {
TangemButton(
buttonUM = organizeTokensUM.cancelButton,
modifier = Modifier.weight(1f),
modifier = Modifier
.weight(1f)
.testTag(OrganizeTokensScreenTestTags.CANCEL_BUTTON),
)
TangemButton(
buttonUM = organizeTokensUM.applyButton,
modifier = Modifier.weight(1f),
modifier = Modifier
.weight(1f)
.testTag(OrganizeTokensScreenTestTags.APPLY_BUTTON),
)
}
}

View file

@ -14,6 +14,8 @@ import androidx.compose.ui.Modifier
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
@ -101,6 +103,7 @@ private fun TokenActionContextMenuContent(actions: ImmutableList<TokenActionButt
Row(
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
modifier = Modifier
.testTag(BaseBottomSheetTestTags.ACTION_BUTTON)
.clickable(
enabled = item.isEnabled,
onClick = {
@ -123,7 +126,9 @@ private fun TokenActionContextMenuContent(actions: ImmutableList<TokenActionButt
} else {
TangemTheme.colors2.graphic.neutral.primary
},
modifier = Modifier.size(TangemTheme.dimens2.x5),
modifier = Modifier
.size(TangemTheme.dimens2.x5)
.testTag(BaseBottomSheetTestTags.ACTION_ICON),
)
Text(
text = item.text.resolveReference(),

View file

@ -2,7 +2,11 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.ds.button.TangemButton
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.test.MainScreenTestTags
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
import com.tangem.features.tangempay.entity.TangemPayMainUM
@ -25,9 +29,14 @@ internal fun LazyListScope.organizeTokens2(state: WalletUM, itemModifier: Modifi
key = "OrganizeTokensButton",
contentType = "OrganizeTokensButton",
) {
val testTag = if (organizeButton.text == resourceReference(R.string.main_add_and_manage_tokens)) {
MainScreenTestTags.ADD_AND_MANAGE_BUTTON
} else {
MainScreenTestTags.ORGANIZE_TOKENS_BUTTON
}
TangemButton(
buttonUM = organizeButton,
modifier = itemModifier,
modifier = itemModifier.testTag(testTag),
)
}
}

View file

@ -68,6 +68,7 @@ internal fun WalletBalance(
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.testTag(MainScreenTestTags.WALLET_LIST_ITEM)
.alpha(alpha)
.scale(scale)
.snapToExitUntilCollapsed(behavior)
@ -150,8 +151,12 @@ private fun SubtitleRow(walletBalanceUM: WalletBalanceUM, modifier: Modifier = M
text = walletBalanceUM.name,
style = TangemTheme.typography2.bodyRegular14,
color = TangemTheme.colors2.text.neutral.tertiary,
modifier = Modifier.testTag(MainScreenTestTags.CARD_TITLE),
)
TangemDeviceIcon(
state = walletBalanceUM.deviceIcon,
modifier = Modifier.testTag(MainScreenTestTags.CARD_IMAGE),
)
TangemDeviceIcon(state = walletBalanceUM.deviceIcon)
}
}
}

View file

@ -9,12 +9,14 @@ import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.paging.compose.LazyPagingItems
import com.tangem.common.ui.notifications.notifications
import com.tangem.common.ui.notifications.notificationsCarousel
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.components.transactions.txHistoryItems
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.MainScreenTestTags
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.tokensListItems
@ -40,7 +42,7 @@ internal fun WalletListContent(
val itemModifier = movableItemModifier.padding(top = TangemTheme.dimens2.x3)
LazyColumn(
modifier = modifier,
modifier = modifier.testTag(MainScreenTestTags.SCREEN_CONTAINER),
state = listState,
contentPadding = contentPadding,
horizontalAlignment = Alignment.CenterHorizontally,

View file

@ -93,7 +93,10 @@ internal fun WalletTopBar(
),
) {
topBarConfig.endActions.forEach { action ->
TangemTopBarActionContent(action)
TangemTopBarActionContent(
action,
modifier = Modifier.testTag(MainScreenTestTags.MORE_BUTTON),
)
}
}
},