Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-28 15:43:18 +03:00
parent 6a15cfd2e4
commit 294c7139ee
31 changed files with 169 additions and 96 deletions

View file

@ -2,5 +2,5 @@ package com.tangem.common
object Strings {
const val STARS = "***"
const val STARS = "\u2217\u2217\u2217"
}

View file

@ -5,6 +5,9 @@ plugins {
}
dependencies {
/** Project - Common */
implementation(projects.common)
/** Project - Domain */
implementation(projects.domain.tokens.models)
implementation(projects.domain.appTheme.models)

View file

@ -19,6 +19,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import com.tangem.common.Strings
import com.tangem.core.ui.R
import com.tangem.core.ui.components.CircleShimmer
import com.tangem.core.ui.components.RectangleShimmer
@ -33,8 +34,9 @@ import java.util.UUID
/**
* Transaction component
*
* @param state state
* @param modifier modifier
* @param state state
* @param isBalanceHidden is balance hidden
* @param modifier modifier
*
* @see <a href = "https://www.figma.com/file/RU7AIgwHtGdMfy83T5UOoR/iOS?type=design&node-id=446-438&t=71jPDxMMk4e0
* a025-4">Figma Component</a>
@ -42,7 +44,7 @@ import java.util.UUID
[REDACTED_AUTHOR]
*/
@Composable
fun Transaction(state: TransactionState, modifier: Modifier = Modifier) {
fun Transaction(state: TransactionState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
Surface(
modifier = modifier
.background(TangemTheme.colors.background.primary)
@ -89,6 +91,7 @@ fun Transaction(state: TransactionState, modifier: Modifier = Modifier) {
Amount(
state = state,
isBalanceHidden = isBalanceHidden,
modifier = Modifier.constrainAs(amountItem) {
start.linkTo(titleItem.end)
top.linkTo(titleItem.top)
@ -265,11 +268,11 @@ private fun Subtitle(state: TransactionState, modifier: Modifier = Modifier) {
}
@Composable
private fun Amount(state: TransactionState, modifier: Modifier = Modifier) {
private fun Amount(state: TransactionState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
when (state) {
is TransactionState.Content -> {
Text(
text = state.amount,
text = if (isBalanceHidden) Strings.STARS else state.amount,
modifier = modifier,
textAlign = TextAlign.End,
color = when (state.direction) {
@ -333,7 +336,7 @@ private fun Preview_TransactionItem_LightTheme(
@PreviewParameter(TransactionItemStateProvider::class) state: TransactionState,
) {
TangemTheme(isDark = false) {
Transaction(state)
Transaction(state = state, isBalanceHidden = false)
}
}
@ -343,7 +346,7 @@ private fun Preview_TransactionItem_DarkTheme(
@PreviewParameter(TransactionItemStateProvider::class) state: TransactionState,
) {
TangemTheme(isDark = true) {
Transaction(state)
Transaction(state = state, isBalanceHidden = false)
}
}

View file

@ -24,12 +24,14 @@ import com.tangem.core.ui.res.TangemTheme
fun LazyListScope.txHistoryItems(
state: TxHistoryState,
txHistoryItems: LazyPagingItems<TxHistoryState.TxHistoryItemState>?,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
when (state) {
is TxHistoryState.Content -> {
contentItems(
txHistoryItems = requireNotNull(txHistoryItems),
isBalanceHidden = isBalanceHidden,
modifier = modifier,
)
}
@ -54,6 +56,7 @@ fun LazyListScope.txHistoryItems(
@OptIn(ExperimentalFoundationApi::class)
private fun LazyListScope.contentItems(
txHistoryItems: LazyPagingItems<TxHistoryState.TxHistoryItemState>,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
items(
@ -70,6 +73,7 @@ private fun LazyListScope.contentItems(
txHistoryItems[index]?.let { item ->
TxHistoryListItem(
state = item,
isBalanceHidden = isBalanceHidden,
modifier = modifier
.animateItemPlacement()
.roundedShapeItemDecoration(

View file

@ -5,7 +5,11 @@ import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.transactions.state.TxHistoryState
@Composable
internal fun TxHistoryListItem(state: TxHistoryState.TxHistoryItemState, modifier: Modifier = Modifier) {
internal fun TxHistoryListItem(
state: TxHistoryState.TxHistoryItemState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
when (state) {
is TxHistoryState.TxHistoryItemState.GroupTitle -> {
TxHistoryGroupTitle(config = state, modifier = modifier)
@ -14,7 +18,11 @@ internal fun TxHistoryListItem(state: TxHistoryState.TxHistoryItemState, modifie
TxHistoryTitle(config = state, modifier = modifier)
}
is TxHistoryState.TxHistoryItemState.Transaction -> {
Transaction(state = state.state, modifier = modifier)
Transaction(
state = state.state,
isBalanceHidden = isBalanceHidden,
modifier = modifier,
)
}
}
}

View file

@ -67,7 +67,6 @@ internal object TokenDetailsPreviewData {
actionButtons = actionButtons,
fiatBalance = "123,00$",
cryptoBalance = "866,96 USDT",
isBalanceHidden = false,
)
val balanceError = TokenDetailsBalanceBlockState.Error(actionButtons = actionButtons)
@ -93,5 +92,6 @@ internal object TokenDetailsPreviewData {
pendingTxs = persistentListOf(),
pullToRefreshConfig = pullToRefreshConfig,
bottomSheetConfig = null,
isBalanceHidden = false,
)
}

View file

@ -15,7 +15,6 @@ internal sealed class TokenDetailsBalanceBlockState {
override val actionButtons: ImmutableList<TokenDetailsActionButton>,
val fiatBalance: String,
val cryptoBalance: String,
val isBalanceHidden: Boolean,
) : TokenDetailsBalanceBlockState()
data class Error(

View file

@ -21,4 +21,5 @@ internal data class TokenDetailsState(
val dialogConfig: TokenDetailsDialogConfig?,
val pullToRefreshConfig: TokenDetailsPullToRefreshConfig,
val bottomSheetConfig: TangemBottomSheetConfig?,
val isBalanceHidden: Boolean,
)

View file

@ -21,7 +21,6 @@ import java.math.BigDecimal
internal class TokenDetailsLoadedBalanceConverter(
private val currentStateProvider: Provider<TokenDetailsState>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val isBalanceHiddenProvider: Provider<Boolean>,
private val symbol: String,
private val decimals: Int,
) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, TokenDetailsState> {
@ -65,7 +64,6 @@ internal class TokenDetailsLoadedBalanceConverter(
actionButtons = currentState.actionButtons,
fiatBalance = formatFiatAmount(status.value, appCurrencyProvider()),
cryptoBalance = formatCryptoAmount(status),
isBalanceHidden = isBalanceHiddenProvider(),
)
}
is CryptoCurrencyStatus.Loading -> {

View file

@ -49,6 +49,7 @@ internal class TokenDetailsSkeletonStateConverter(
dialogConfig = null,
pullToRefreshConfig = createPullToRefresh(),
bottomSheetConfig = null,
isBalanceHidden = true,
)
}

View file

@ -17,7 +17,6 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter
@ -29,7 +28,6 @@ import kotlinx.coroutines.flow.Flow
internal class TokenDetailsStateFactory(
private val currentStateProvider: Provider<TokenDetailsState>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val isBalanceHiddenProvider: Provider<Boolean>,
private val clickIntents: TokenDetailsClickIntents,
currencySymbolProvider: Provider<String>,
currencyDecimalsProvider: Provider<Int>,
@ -47,7 +45,6 @@ internal class TokenDetailsStateFactory(
TokenDetailsLoadedBalanceConverter(
currentStateProvider = currentStateProvider,
appCurrencyProvider = appCurrencyProvider,
isBalanceHiddenProvider = isBalanceHiddenProvider,
symbol = currencySymbolProvider(),
decimals = currencyDecimalsProvider(),
)
@ -100,7 +97,9 @@ internal class TokenDetailsStateFactory(
fun getLoadedTxHistoryState(
txHistoryEither: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>,
): TokenDetailsState {
return loadedTxHistoryConverter.convert(txHistoryEither)
return currentStateProvider().copy(
txHistoryState = loadedTxHistoryConverter.convert(txHistoryEither),
)
}
fun getStateWithClosedDialog(): TokenDetailsState {
@ -203,14 +202,8 @@ internal class TokenDetailsStateFactory(
fun getStateWithUpdatedHidden(isBalanceHidden: Boolean): TokenDetailsState {
val currentState = currentStateProvider()
val possibleTokenBalanceBlockState = currentState.tokenBalanceBlockState as?
TokenDetailsBalanceBlockState.Content
possibleTokenBalanceBlockState?.let {
return currentState.copy(
tokenBalanceBlockState = possibleTokenBalanceBlockState.copy(isBalanceHidden = isBalanceHidden),
)
} ?: return currentState
return currentState.copy(isBalanceHidden = isBalanceHidden)
}
fun getStateWithNotifications(warnings: Set<CryptoCurrencyWarning>): TokenDetailsState {

View file

@ -16,7 +16,7 @@ internal class TokenDetailsLoadedTxHistoryConverter(
private val clickIntents: TokenDetailsClickIntents,
symbol: String,
decimals: Int,
) : Converter<Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>, TokenDetailsState> {
) : Converter<Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>, TxHistoryState> {
private val txHistoryItemFlowConverter by lazy {
TokenDetailsTxHistoryItemFlowConverter(
@ -27,23 +27,19 @@ internal class TokenDetailsLoadedTxHistoryConverter(
)
}
override fun convert(value: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>): TokenDetailsState {
override fun convert(value: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>): TxHistoryState {
return value.fold(ifLeft = ::convertError, ifRight = ::convert)
}
private fun convertError(error: TxHistoryListError): TokenDetailsState {
return currentStateProvider().copy(
txHistoryState = when (error) {
is TxHistoryListError.DataError -> {
TxHistoryState.Error(onReloadClick = clickIntents::onReloadClick)
}
},
)
private fun convertError(error: TxHistoryListError): TxHistoryState {
return when (error) {
is TxHistoryListError.DataError -> {
TxHistoryState.Error(onReloadClick = clickIntents::onReloadClick)
}
}
}
private fun convert(items: Flow<PagingData<TxHistoryItem>>): TokenDetailsState {
return currentStateProvider().copy(
txHistoryState = txHistoryItemFlowConverter.convert(value = items),
)
private fun convert(items: Flow<PagingData<TxHistoryItem>>): TxHistoryState {
return txHistoryItemFlowConverter.convert(value = items)
}
}

View file

@ -30,7 +30,10 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
) : Converter<Flow<PagingData<TxHistoryItem>>, TxHistoryState> {
private val txHistoryItemConverter by lazy {
TokenDetailsTxHistoryTransactionStateConverter(symbol = symbol, decimals = decimals)
TokenDetailsTxHistoryTransactionStateConverter(
symbol = symbol,
decimals = decimals,
)
}
override fun convert(value: Flow<PagingData<TxHistoryItem>>): TxHistoryState {

View file

@ -29,7 +29,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
TxHistoryItem.TransactionType.Deposit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -39,7 +39,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -49,7 +49,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -59,7 +59,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -69,7 +69,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -79,7 +79,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -93,7 +93,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
return TransactionState.Transfer(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -104,7 +104,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
return TransactionState.Approve(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -114,7 +114,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
return TransactionState.Swap(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -141,7 +141,7 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter(
is TxHistoryItem.TransactionDirection.Outgoing -> TransactionState.Content.Direction.OUTGOING
}
private fun TxHistoryItem.extractFormattedCryptoBalance(): String {
private fun TxHistoryItem.getAmount(): String {
val prefix = when (direction) {
is TxHistoryItem.TransactionDirection.Incoming -> "+"
is TxHistoryItem.TransactionDirection.Outgoing -> "-"

View file

@ -26,7 +26,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Deposit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -36,7 +36,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -46,7 +46,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -56,7 +56,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -66,7 +66,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -76,7 +76,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -90,7 +90,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
return TransactionState.Transfer(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -101,7 +101,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
return TransactionState.Approve(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -111,7 +111,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
return TransactionState.Swap(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -142,7 +142,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
is TxHistoryItem.TransactionDirection.Outgoing -> TransactionState.Content.Direction.OUTGOING
}
private fun TxHistoryItem.extractFormattedCryptoBalance(): String {
private fun TxHistoryItem.getAmount(): String {
val prefix = when (direction) {
is TxHistoryItem.TransactionDirection.Incoming -> "+"
is TxHistoryItem.TransactionDirection.Outgoing -> "-"

View file

@ -79,7 +79,13 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
state = state.tokenInfoBlockState,
)
}
item { TokenDetailsBalanceBlock(modifier = itemModifier, state = state.tokenBalanceBlockState) }
item {
TokenDetailsBalanceBlock(
modifier = itemModifier,
isBalanceHidden = state.isBalanceHidden,
state = state.tokenBalanceBlockState,
)
}
items(
items = state.notifications.filter { it.isVisible },
key = { it.config::class.java },
@ -95,11 +101,16 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
item {
PendingTxsBlock(
pendingTxs = state.pendingTxs,
isBalanceHidden = state.isBalanceHidden,
modifier = itemModifier,
)
}
}
txHistoryItems(state = state.txHistoryState, txHistoryItems = txHistoryItems)
txHistoryItems(
state = state.txHistoryState,
isBalanceHidden = state.isBalanceHidden,
txHistoryItems = txHistoryItems,
)
}
PullRefreshIndicator(
@ -127,7 +138,11 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
}
@Composable
private fun PendingTxsBlock(pendingTxs: PersistentList<TransactionState>, modifier: Modifier = Modifier) {
private fun PendingTxsBlock(
pendingTxs: PersistentList<TransactionState>,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
@ -135,7 +150,7 @@ private fun PendingTxsBlock(pendingTxs: PersistentList<TransactionState>, modifi
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8),
horizontalAlignment = Alignment.Start,
) {
pendingTxs.fastForEach { Transaction(state = it) }
pendingTxs.fastForEach { Transaction(state = it, isBalanceHidden = isBalanceHidden) }
}
}

View file

@ -9,6 +9,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.common.Strings.STARS
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.buttons.HorizontalActionChips
import com.tangem.core.ui.res.TangemTheme
@ -20,7 +21,11 @@ import com.tangem.features.tokendetails.impl.R
import kotlinx.collections.immutable.toImmutableList
@Composable
internal fun TokenDetailsBalanceBlock(state: TokenDetailsBalanceBlockState, modifier: Modifier = Modifier) {
internal fun TokenDetailsBalanceBlock(
state: TokenDetailsBalanceBlockState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier.fillMaxWidth(),
shape = TangemTheme.shapes.roundedCornersXMedium,
@ -41,12 +46,14 @@ internal fun TokenDetailsBalanceBlock(state: TokenDetailsBalanceBlockState, modi
)
FiatBalance(
state = state,
isBalanceHidden = isBalanceHidden,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing4)
.padding(horizontal = TangemTheme.dimens.spacing12),
)
CryptoBalance(
state = state,
isBalanceHidden = isBalanceHidden,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing4)
.padding(horizontal = TangemTheme.dimens.spacing12),
@ -62,7 +69,11 @@ internal fun TokenDetailsBalanceBlock(state: TokenDetailsBalanceBlockState, modi
}
@Composable
private fun FiatBalance(state: TokenDetailsBalanceBlockState, modifier: Modifier = Modifier) {
private fun FiatBalance(
state: TokenDetailsBalanceBlockState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
when (state) {
is TokenDetailsBalanceBlockState.Loading -> RectangleShimmer(
modifier = modifier.size(
@ -72,7 +83,7 @@ private fun FiatBalance(state: TokenDetailsBalanceBlockState, modifier: Modifier
)
is TokenDetailsBalanceBlockState.Content -> Text(
modifier = modifier,
text = if (state.isBalanceHidden) DOTS else state.fiatBalance,
text = if (isBalanceHidden) STARS else state.fiatBalance,
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
@ -86,7 +97,11 @@ private fun FiatBalance(state: TokenDetailsBalanceBlockState, modifier: Modifier
}
@Composable
private fun CryptoBalance(state: TokenDetailsBalanceBlockState, modifier: Modifier = Modifier) {
private fun CryptoBalance(
state: TokenDetailsBalanceBlockState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
when (state) {
is TokenDetailsBalanceBlockState.Loading -> RectangleShimmer(
modifier = modifier.size(
@ -96,7 +111,7 @@ private fun CryptoBalance(state: TokenDetailsBalanceBlockState, modifier: Modifi
)
is TokenDetailsBalanceBlockState.Content -> Text(
modifier = modifier,
text = if (state.isBalanceHidden) DOTS else state.cryptoBalance,
text = if (isBalanceHidden) STARS else state.cryptoBalance,
style = TangemTheme.typography.caption,
color = TangemTheme.colors.text.tertiary,
)
@ -115,7 +130,7 @@ private fun Preview_TokenDetailsBalanceBlock_LightTheme(
@PreviewParameter(TokenDetailsBalanceBlockStateProvider::class) state: TokenDetailsBalanceBlockState,
) {
TangemTheme(isDark = false) {
TokenDetailsBalanceBlock(state)
TokenDetailsBalanceBlock(state = state, isBalanceHidden = false)
}
}
@ -125,7 +140,7 @@ private fun Preview_TokenDetailsBalanceBlock_DarkTheme(
@PreviewParameter(TokenDetailsBalanceBlockStateProvider::class) state: TokenDetailsBalanceBlockState,
) {
TangemTheme(isDark = true) {
TokenDetailsBalanceBlock(state)
TokenDetailsBalanceBlock(state = state, isBalanceHidden = false)
}
}
@ -135,6 +150,4 @@ private class TokenDetailsBalanceBlockStateProvider : CollectionPreviewParameter
TokenDetailsPreviewData.balanceContent,
TokenDetailsPreviewData.balanceError,
),
)
const val DOTS = "***"
)

View file

@ -78,12 +78,10 @@ internal class TokenDetailsViewModel @Inject constructor(
private var cryptoCurrency by Delegates.notNull<CryptoCurrency>()
private val selectedAppCurrencyFlow: StateFlow<AppCurrency> = createSelectedAppCurrencyFlow()
private var isBalanceHidden = true
private val stateFactory = TokenDetailsStateFactory(
currentStateProvider = Provider { uiState },
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
isBalanceHiddenProvider = Provider { isBalanceHidden },
clickIntents = this,
currencySymbolProvider = Provider { cryptoCurrency.symbol },
currencyDecimalsProvider = Provider { cryptoCurrency.decimals },
@ -125,8 +123,9 @@ internal class TokenDetailsViewModel @Inject constructor(
isBalanceHiddenUseCase()
.flowWithLifecycle(owner.lifecycle)
.onEach { hidden ->
isBalanceHidden = hidden
uiState = stateFactory.getStateWithUpdatedHidden(isBalanceHidden = hidden)
uiState = stateFactory.getStateWithUpdatedHidden(
isBalanceHidden = hidden,
)
}
.launchIn(viewModelScope)
@ -186,11 +185,9 @@ internal class TokenDetailsViewModel @Inject constructor(
}
txHistoryItemsCountEither.onRight {
uiState = stateFactory.getLoadedTxHistoryState(
txHistoryEither = txHistoryItemsUseCase(currency = cryptoCurrency).map {
it.cachedIn(viewModelScope)
},
)
val either = txHistoryItemsUseCase(currency = cryptoCurrency)
.map { it.cachedIn(viewModelScope) }
uiState = stateFactory.getLoadedTxHistoryState(txHistoryEither = either)
}
}
}

View file

@ -397,6 +397,7 @@ internal object WalletPreviewData {
tokenActionsBottomSheet = actionsBottomSheet,
onManageTokensClick = {},
event = consumedEvent(),
isBalanceHidden = false,
)
}
@ -451,6 +452,7 @@ internal object WalletPreviewData {
),
),
event = consumedEvent(),
isBalanceHidden = false,
)
}
}

View file

@ -26,6 +26,7 @@ internal sealed class WalletMultiCurrencyState : WalletState.ContentState() {
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val tokensListState: WalletTokensListState,
override val event: StateEvent<WalletEvent> = consumedEvent(),
override val isBalanceHidden: Boolean,
val tokenActionsBottomSheet: ActionsBottomSheetConfig?,
val onManageTokensClick: () -> Unit,
) : WalletMultiCurrencyState()
@ -41,6 +42,7 @@ internal sealed class WalletMultiCurrencyState : WalletState.ContentState() {
override val isBottomSheetShow: Boolean = false,
override val onBottomSheetDismiss: () -> Unit = {},
override val event: StateEvent<WalletEvent> = consumedEvent(),
override val isBalanceHidden: Boolean,
) : WalletMultiCurrencyState(), WalletLockedState {
override val notifications = persistentListOf(

View file

@ -38,6 +38,7 @@ internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
override val buttons: PersistentList<WalletManageButton>,
override val txHistoryState: TxHistoryState,
override val event: StateEvent<WalletEvent> = consumedEvent(),
override val isBalanceHidden: Boolean,
val marketPriceBlockState: MarketPriceBlockState,
) : WalletSingleCurrencyState()
@ -53,6 +54,7 @@ internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
override val isBottomSheetShow: Boolean = false,
override val onBottomSheetDismiss: () -> Unit = {},
override val event: StateEvent<WalletEvent> = consumedEvent(),
override val isBalanceHidden: Boolean,
val onExploreClick: () -> Unit,
) : WalletSingleCurrencyState(), WalletLockedState {

View file

@ -39,6 +39,9 @@ internal sealed class WalletState {
/** State event */
abstract val event: StateEvent<WalletEvent>
/** Whether balance should be hidden */
abstract val isBalanceHidden: Boolean
/**
* Util function that allow to make a copy
*
@ -50,6 +53,7 @@ internal sealed class WalletState {
walletsListConfig: WalletsListConfig = this.walletsListConfig,
pullToRefreshConfig: WalletPullToRefreshConfig = this.pullToRefreshConfig,
event: StateEvent<WalletEvent> = this.event,
isBalanceHidden: Boolean = this.isBalanceHidden,
): ContentState {
return when (this) {
is WalletMultiCurrencyState.Content -> {
@ -57,6 +61,7 @@ internal sealed class WalletState {
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
event = event,
isBalanceHidden = isBalanceHidden,
)
}
is WalletMultiCurrencyState.Locked -> {
@ -64,6 +69,7 @@ internal sealed class WalletState {
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
event = event,
isBalanceHidden = isBalanceHidden,
)
}
is WalletSingleCurrencyState.Content -> {
@ -71,6 +77,7 @@ internal sealed class WalletState {
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
event = event,
isBalanceHidden = isBalanceHidden,
)
}
is WalletSingleCurrencyState.Locked -> {
@ -78,6 +85,7 @@ internal sealed class WalletState {
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
event = event,
isBalanceHidden = isBalanceHidden,
)
}
}

View file

@ -37,6 +37,7 @@ internal class WalletLockedConverter(
onUnlockWalletsNotificationClick = clickIntents::onUnlockWalletNotificationClick,
onUnlockClick = clickIntents::onUnlockWalletClick,
onScanClick = clickIntents::onScanToUnlockWalletClick,
isBalanceHidden = isBalanceHidden,
)
}
@ -51,6 +52,7 @@ internal class WalletLockedConverter(
onUnlockClick = clickIntents::onUnlockWalletClick,
onScanClick = clickIntents::onScanToUnlockWalletClick,
onExploreClick = clickIntents::onExploreClick,
isBalanceHidden = isBalanceHidden,
)
}

View file

@ -55,6 +55,7 @@ internal class WalletSkeletonStateConverter(
bottomSheetConfig = null,
tokenActionsBottomSheet = null,
onManageTokensClick = clickIntents::onManageTokensClick,
isBalanceHidden = true,
)
}
@ -73,6 +74,7 @@ internal class WalletSkeletonStateConverter(
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),
),
),
isBalanceHidden = true,
)
}

View file

@ -88,6 +88,7 @@ internal class WalletStateFactory(
private val loadedTxHistoryConverter by lazy {
WalletLoadedTxHistoryConverter(
currentStateProvider = currentStateProvider,
isBalanceHiddenProvider = isBalanceHiddenProvider,
currentCardTypeResolverProvider = currentCardTypeResolverProvider,
clickIntents = clickIntents,
)

View file

@ -54,6 +54,7 @@ internal class WalletsUnlockStateConverter(
bottomSheetConfig = null,
tokenActionsBottomSheet = null,
onManageTokensClick = clickIntents::onManageTokensClick,
isBalanceHidden = isBalanceHidden,
)
}
@ -74,6 +75,7 @@ internal class WalletsUnlockStateConverter(
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),
),
),
isBalanceHidden = isBalanceHidden,
)
}

View file

@ -27,6 +27,7 @@ internal class WalletLoadedTxHistoryConverter(
private val currentStateProvider: Provider<WalletState>,
private val currentCardTypeResolverProvider: Provider<CardTypesResolver>,
private val clickIntents: WalletClickIntents,
private val isBalanceHiddenProvider: Provider<Boolean>,
) : Converter<Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>, WalletState> {
private val walletTxHistoryItemFlowConverter by lazy {
@ -34,6 +35,7 @@ internal class WalletLoadedTxHistoryConverter(
currentStateProvider = currentStateProvider,
blockchain = currentCardTypeResolverProvider().getBlockchain(),
clickIntents = clickIntents,
isBalanceHiddenProvider = isBalanceHiddenProvider,
)
}

View file

@ -35,12 +35,17 @@ import org.joda.time.DateTimeZone
*/
internal class WalletTxHistoryItemFlowConverter(
private val currentStateProvider: Provider<WalletState>,
private val isBalanceHiddenProvider: Provider<Boolean>,
private val blockchain: Blockchain,
private val clickIntents: WalletClickIntents,
) : Converter<Flow<PagingData<TxHistoryItem>>, TxHistoryState?> {
private val txHistoryItemConverter by lazy {
WalletTxHistoryTransactionStateConverter(symbol = blockchain.currency, decimals = blockchain.decimals())
WalletTxHistoryTransactionStateConverter(
symbol = blockchain.currency,
decimals = blockchain.decimals(),
isBalanceHiddenProvider = isBalanceHiddenProvider,
)
}
override fun convert(value: Flow<PagingData<TxHistoryItem>>): TxHistoryState? {

View file

@ -1,5 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import com.tangem.common.Provider
import com.tangem.common.Strings
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.txhistory.models.TxHistoryItem
@ -11,6 +13,7 @@ import com.tangem.utils.toFormattedCurrencyString
class WalletTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
private val isBalanceHiddenProvider: Provider<Boolean>,
) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState {
@ -26,7 +29,7 @@ class WalletTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Deposit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -36,7 +39,7 @@ class WalletTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -46,7 +49,7 @@ class WalletTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -56,7 +59,7 @@ class WalletTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -66,7 +69,7 @@ class WalletTxHistoryTransactionStateConverter(
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -76,7 +79,7 @@ class WalletTxHistoryTransactionStateConverter(
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -90,7 +93,7 @@ class WalletTxHistoryTransactionStateConverter(
return TransactionState.Transfer(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -101,7 +104,7 @@ class WalletTxHistoryTransactionStateConverter(
return TransactionState.Approve(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -111,7 +114,7 @@ class WalletTxHistoryTransactionStateConverter(
return TransactionState.Swap(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.extractFormattedCryptoBalance(),
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
direction = item.direction.toUiDirection(),
@ -142,7 +145,9 @@ class WalletTxHistoryTransactionStateConverter(
is TxHistoryItem.TransactionDirection.Outgoing -> TransactionState.Content.Direction.OUTGOING
}
private fun TxHistoryItem.extractFormattedCryptoBalance(): String {
private fun TxHistoryItem.getAmount(): String {
if (isBalanceHiddenProvider()) return Strings.STARS
val prefix = when (direction) {
is TxHistoryItem.TransactionDirection.Incoming -> "+"
is TxHistoryItem.TransactionDirection.Outgoing -> "-"

View file

@ -142,7 +142,12 @@ private fun WalletContent(
marketPriceBlock(state = state.marketPriceBlockState, modifier = itemModifier)
}
contentItems(state = state, txHistoryItems = txHistoryItems, modifier = movableItemModifier)
contentItems(
state = state,
txHistoryItems = txHistoryItems,
isBalanceHidden = state.isBalanceHidden,
modifier = movableItemModifier,
)
if (state is WalletMultiCurrencyState) {
val contentTokenListState = state.tokensListState as? WalletTokensListState.ContentState

View file

@ -22,10 +22,11 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
internal fun LazyListScope.contentItems(
state: WalletState.ContentState,
txHistoryItems: LazyPagingItems<TxHistoryState.TxHistoryItemState>?,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
when (state) {
is WalletMultiCurrencyState -> tokensListItems(state.tokensListState, modifier)
is WalletSingleCurrencyState -> txHistoryItems(state.txHistoryState, txHistoryItems, modifier)
is WalletSingleCurrencyState -> txHistoryItems(state.txHistoryState, txHistoryItems, isBalanceHidden, modifier)
}
}