Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-13 18:00:34 +03:00
parent ed8419b45b
commit b97ddcb3f2
17 changed files with 379 additions and 147 deletions

View file

@ -1,10 +1,15 @@
package com.tangem.feature.tokendetails.presentation.tokendetails
import androidx.compose.ui.graphics.Color
import androidx.paging.PagingData
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.marketprice.PriceChangeState
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton
@ -76,8 +81,8 @@ internal object TokenDetailsPreviewData {
val balanceLoading = TokenDetailsBalanceBlockState.Loading(actionButtons = actionButtons)
val balanceContent = TokenDetailsBalanceBlockState.Content(
actionButtons = actionButtons,
fiatBalance = "123,00$",
cryptoBalance = "866,96 USDT",
fiatBalance = "91,50$",
cryptoBalance = "966,96 XLM",
)
val balanceError = TokenDetailsBalanceBlockState.Error(actionButtons = actionButtons)
@ -88,7 +93,131 @@ internal object TokenDetailsPreviewData {
onRefresh = {},
)
val tokenDetailsState = TokenDetailsState(
private val txHistoryItems = listOf(
TxHistoryState.TxHistoryItemState.Title(onExploreClick = {}),
TxHistoryState.TxHistoryItemState.GroupTitle(
title = "Today",
itemKey = "Today",
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "1",
amount = "-0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.OUTGOING,
onClick = {},
iconRes = R.drawable.ic_arrow_up_24,
title = stringReference(value = "Sending"),
subtitle = stringReference(value = "to: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "2",
amount = "+0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
onClick = {},
iconRes = R.drawable.ic_arrow_down_24,
title = stringReference(value = "Receiving"),
subtitle = stringReference(value = "from: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "3",
amount = "+0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
onClick = {},
iconRes = R.drawable.ic_doc_24,
title = stringReference(value = "Approving"),
subtitle = stringReference(value = "from: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "4",
amount = "+0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
onClick = {},
iconRes = R.drawable.ic_exchange_vertical_24,
title = stringReference(value = "Swapping"),
subtitle = stringReference(value = "contract: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.GroupTitle(
title = "Yesterday",
itemKey = "Yesterday",
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "5",
amount = "-0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.OUTGOING,
onClick = {},
iconRes = R.drawable.ic_arrow_up_24,
title = stringReference(value = "Sending"),
subtitle = stringReference(value = "to: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "6",
amount = "+0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
onClick = {},
iconRes = R.drawable.ic_arrow_down_24,
title = stringReference(value = "Receiving"),
subtitle = stringReference(value = "from: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "7",
amount = "+0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
onClick = {},
iconRes = R.drawable.ic_doc_24,
title = stringReference(value = "Approving"),
subtitle = stringReference(value = "from: 33BddS...ga2B"),
timestamp = 0,
),
),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Content(
txHash = "8",
amount = "+0.500913 XLM",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
onClick = {},
iconRes = R.drawable.ic_exchange_vertical_24,
title = stringReference(value = "Swapping"),
subtitle = stringReference(value = "contract: 33BddS...ga2B"),
timestamp = 0,
),
),
)
val tokenDetailsState_1 = TokenDetailsState(
topAppBarConfig = tokenDetailsTopAppBarConfig,
tokenInfoBlockState = tokenInfoBlockState,
tokenBalanceBlockState = balanceLoading,
@ -108,4 +237,41 @@ internal object TokenDetailsPreviewData {
isMarketPriceAvailable = false,
event = consumedEvent(),
)
val tokenDetailsState_2 = TokenDetailsState(
topAppBarConfig = tokenDetailsTopAppBarConfig,
tokenInfoBlockState = tokenInfoBlockState.copy(
name = "Stellar",
),
tokenBalanceBlockState = balanceContent,
marketPriceBlockState = MarketPriceBlockState.Content(
currencySymbol = "XLM",
price = "0.11$",
priceChangeConfig = PriceChangeState.Content(
valueInPercent = "5,16%",
type = PriceChangeType.UP,
),
),
notifications = persistentListOf(),
txHistoryState = TxHistoryState.NotSupported(
onExploreClick = {},
pendingTransactions = persistentListOf(),
),
dialogConfig = null,
pendingTxs = persistentListOf(),
swapTxs = persistentListOf(),
pullToRefreshConfig = pullToRefreshConfig,
bottomSheetConfig = null,
isBalanceHidden = false,
isMarketPriceAvailable = true,
event = consumedEvent(),
)
val tokenDetailsState_3 = tokenDetailsState_2.copy(
txHistoryState = TxHistoryState.Content(
contentItems = MutableStateFlow(
value = PagingData.from(txHistoryItems),
),
),
)
}

View file

@ -3,6 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@ -20,6 +21,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.paging.compose.collectAsLazyPagingItems
import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheet
import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig
@ -82,14 +85,12 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
.pullRefresh(pullRefreshState),
) {
LazyColumn(
modifier = Modifier
.fillMaxSize(),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(bottom = TangemTheme.dimens.spacing16),
) {
item {
TokenInfoBlock(
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing4)
.padding(horizontal = horizontalPadding),
modifier = Modifier.padding(horizontal = horizontalPadding),
state = state.tokenInfoBlockState,
)
}
@ -181,18 +182,32 @@ internal fun TokenDetailsEventEffect(snackbarHostState: SnackbarHostState, event
)
}
@Preview
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun Preview_TokenDetailsScreen_LightTheme() {
TangemTheme(isDark = false) {
TokenDetailsScreen(state = TokenDetailsPreviewData.tokenDetailsState)
private fun TokenDetailsScreenPreview_Light(
@PreviewParameter(TokenDetailsScreenParameterProvider::class) state: TokenDetailsState,
) {
TangemTheme {
TokenDetailsScreen(state)
}
}
@Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun Preview_TokenDetailsScreen_DarkTheme() {
private fun TokenDetailsScreenPreview_Dark(
@PreviewParameter(TokenDetailsScreenParameterProvider::class) state: TokenDetailsState,
) {
TangemTheme(isDark = true) {
TokenDetailsScreen(state = TokenDetailsPreviewData.tokenDetailsState)
TokenDetailsScreen(state)
}
}
}
private class TokenDetailsScreenParameterProvider : CollectionPreviewParameterProvider<TokenDetailsState>(
collection = listOf(
TokenDetailsPreviewData.tokenDetailsState_1,
TokenDetailsPreviewData.tokenDetailsState_2,
TokenDetailsPreviewData.tokenDetailsState_3,
),
)
// endregion Preview

View file

@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
@ -32,18 +33,21 @@ internal fun TokenDetailsBalanceBlock(
color = TangemTheme.colors.background.primary,
) {
Column {
Text(
Box(
modifier = Modifier
.padding(
top = TangemTheme.dimens.spacing12,
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
text = stringResource(id = R.string.common_balance_title),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
maxLines = 1,
)
.padding(top = TangemTheme.dimens.spacing12)
.padding(horizontal = TangemTheme.dimens.spacing12)
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.spacing24),
contentAlignment = Alignment.CenterStart,
) {
Text(
text = stringResource(id = R.string.common_balance_title),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
maxLines = 1,
)
}
FiatBalance(
state = state,
isBalanceHidden = isBalanceHidden,
@ -124,7 +128,7 @@ private fun CryptoBalance(
}
}
@Preview
@Preview(widthDp = 328, heightDp = 152)
@Composable
private fun Preview_TokenDetailsBalanceBlock_LightTheme(
@PreviewParameter(TokenDetailsBalanceBlockStateProvider::class) state: TokenDetailsBalanceBlockState,
@ -134,7 +138,7 @@ private fun Preview_TokenDetailsBalanceBlock_LightTheme(
}
}
@Preview
@Preview(widthDp = 328, heightDp = 152)
@Composable
private fun Preview_TokenDetailsBalanceBlock_DarkTheme(
@PreviewParameter(TokenDetailsBalanceBlockStateProvider::class) state: TokenDetailsBalanceBlockState,

View file

@ -14,7 +14,6 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ColorMatrix
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
@ -29,9 +28,15 @@ private const val NORMAL_ALPHA = 1f
@Composable
internal fun TokenInfoBlock(state: TokenInfoBlockState, modifier: Modifier = Modifier) {
Row(modifier = modifier.fillMaxWidth()) {
Row(
modifier = modifier
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size60),
) {
Column(
modifier = Modifier.weight(1F),
modifier = Modifier
.align(Alignment.CenterVertically)
.weight(1F),
) {
Text(
text = state.name,
@ -88,7 +93,7 @@ private fun NetworkInfoText(currency: TokenInfoBlockState.Currency) {
)
Text(
text = state.boldText,
style = TangemTheme.typography.caption2.copy(fontWeight = FontWeight.Medium),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.primary1,
)
}

View file

@ -126,7 +126,7 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
Layout(content = content, modifier = modifier) { measurables, constraints ->
val layoutWidth = constraints.maxWidth
val horizontalPadding = with(density) { dimens.size14.roundToPx() }
val horizontalPadding = with(density) { dimens.size12.roundToPx() }
val verticalPadding = with(density) { dimens.size16.roundToPx() }
val layoutWidthWithoutPaddings = layoutWidth - 2 * horizontalPadding
@ -137,7 +137,7 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
/*
* Title width take the whole REMAINING space.
* If FiatAmount took the whole free space, then Title will has min width.
* If FiatAmount took the whole free space, then Title will have min width.
*/
val title: Placeable
@ -149,7 +149,7 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
/*
* PriceChange width take the whole REMAINING space.
* If CryptoAmount took the whole free space, then PriceChange will has min width.
* If CryptoAmount took the whole free space, then PriceChange will have min width.
*/
val priceChange: Placeable?

View file

@ -103,7 +103,7 @@ private fun TokenList(
)
val listContentPadding = PaddingValues(
top = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing4,
bottom = TangemTheme.dimens.spacing92,
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
@ -245,7 +245,7 @@ private fun TopBar(
Row(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size56),
.padding(bottom = TangemTheme.dimens.spacing8),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {