Updated on 2026-08-14

This commit is contained in:
Tangem 2023-09-21 18:54:47 +05:00
parent 81cce1254d
commit 879c8d603b
19 changed files with 566 additions and 415 deletions

View file

@ -418,20 +418,22 @@ internal object WalletPreviewData {
listOf(
TxHistoryState.TxHistoryItemState.GroupTitle("Today"),
TxHistoryState.TxHistoryItemState.Transaction(
TransactionState.Sending(
TransactionState.Send(
txHash = UUID.randomUUID().toString(),
address = TextReference.Str("33BddS...ga2B"),
amount = "-0.500913 BTC",
timestamp = "8:41",
status = TransactionState.Content.Status.Unconfirmed,
),
),
TxHistoryState.TxHistoryItemState.GroupTitle("Yesterday"),
TxHistoryState.TxHistoryItemState.Transaction(
TransactionState.Sending(
TransactionState.Send(
txHash = UUID.randomUUID().toString(),
address = TextReference.Str("33BddS...ga2B"),
amount = "-0.500913 BTC",
timestamp = "8:41",
status = TransactionState.Content.Status.Confirmed,
),
),
),

View file

@ -7,17 +7,13 @@ import com.tangem.common.Provider
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isToday
import com.tangem.utils.extensions.isYesterday
import com.tangem.utils.toBriefAddressFormat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
@ -27,7 +23,6 @@ import kotlinx.coroutines.flow.update
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.joda.time.format.DateTimeFormatterBuilder
import java.math.BigDecimal
import java.util.Locale
/**
@ -45,6 +40,10 @@ internal class WalletTxHistoryItemFlowConverter(
private val clickIntents: WalletClickIntents,
) : Converter<Flow<PagingData<TxHistoryItem>>, TxHistoryState?> {
private val txHistoryItemConverter by lazy {
WalletTxHistoryTransactionStateConverter(symbol = blockchain.currency, decimals = blockchain.decimals())
}
/** Example, 2 Aug, 2023 */
private val dateFormatter by lazy {
DateTimeFormatterBuilder()
@ -95,68 +94,7 @@ internal class WalletTxHistoryItemFlowConverter(
}
private fun createTransactionState(item: TxHistoryItem): TransactionState {
return when (item.type) {
TxHistoryItem.TransactionType.Transfer -> {
when (val direction = item.direction) {
is TxHistoryItem.TransactionDirection.Incoming -> {
createIncomingTransferTransaction(item, direction, blockchain)
}
is TxHistoryItem.TransactionDirection.Outgoing -> {
createOutgoingTransferTransaction(item, direction, blockchain)
}
}
}
}
}
private fun createIncomingTransferTransaction(
item: TxHistoryItem,
direction: TxHistoryItem.TransactionDirection.Incoming,
blockchain: Blockchain,
): TransactionState {
return when (item.status) {
TxHistoryItem.TxStatus.Confirmed -> TransactionState.Receive(
txHash = item.txHash,
address = direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(blockchain = blockchain),
timestamp = item.getRawTimestamp(),
)
TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Receiving(
txHash = item.txHash,
address = direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(blockchain = blockchain),
timestamp = item.getRawTimestamp(),
)
}
}
private fun createOutgoingTransferTransaction(
item: TxHistoryItem,
direction: TxHistoryItem.TransactionDirection.Outgoing,
blockchain: Blockchain,
): TransactionState {
return when (item.status) {
TxHistoryItem.TxStatus.Confirmed -> TransactionState.Send(
txHash = item.txHash,
address = direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(blockchain = blockchain),
timestamp = item.getRawTimestamp(),
)
TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Sending(
txHash = item.txHash,
address = direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(blockchain = blockchain),
timestamp = item.getRawTimestamp(),
)
}
}
private fun BigDecimal.toCryptoCurrencyFormat(blockchain: Blockchain): String {
return BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = this,
cryptoCurrency = blockchain.currency,
decimals = blockchain.decimals(),
)
return txHistoryItemConverter.convert(value = item)
}
private fun PagingData<TxHistoryItemState>.insertGroupTitle(): PagingData<TxHistoryItemState> {
@ -202,14 +140,6 @@ internal class WalletTxHistoryItemFlowConverter(
}
}
/**
* Get timestamp without formatting.
* It's life hack that help us to add transaction's group title to flow.
*
* @see [convert]
*/
private fun TxHistoryItem.getRawTimestamp() = this.timestampInMillis.toString()
private fun TxHistoryItemState?.getTimestamp(): Long? {
return if (this is TxHistoryItemState.Transaction && this.state is TransactionState.Content) {
val txContent = this.state as TransactionState.Content
@ -242,9 +172,4 @@ internal class WalletTxHistoryItemFlowConverter(
DateTime(this.toLong(), DateTimeZone.getDefault()),
)
}
private fun TxHistoryItem.TransactionDirection.extractAddress(): TextReference = when (val addr = address) {
TxHistoryItem.Address.Multiple -> TextReference.Res(R.string.transaction_history_multiple_addresses)
is TxHistoryItem.Address.Single -> TextReference.Str(addr.rawAddress.toBriefAddressFormat())
}
}

View file

@ -0,0 +1,150 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
import java.math.BigDecimal
class WalletTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState {
return createTransactionStateItem(item = value)
}
// TODO: Finalize transaction types [REDACTED_JIRA]
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return when (val type = item.type) {
TxHistoryItem.TransactionType.Transfer -> mapTransfer(item)
TxHistoryItem.TransactionType.Approve -> mapApprove(item)
TxHistoryItem.TransactionType.Swap -> mapSwap(item)
TxHistoryItem.TransactionType.Deposit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
title = TextReference.Str("Deposit"),
subtitle = item.direction.extractAddress(),
isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming,
)
TxHistoryItem.TransactionType.Submit -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
title = TextReference.Str("Submit"),
subtitle = item.direction.extractAddress(),
isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming,
)
TxHistoryItem.TransactionType.Supply -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
title = TextReference.Str("Supply"),
subtitle = item.direction.extractAddress(),
isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming,
)
TxHistoryItem.TransactionType.Unoswap -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
title = TextReference.Str("Unoswap"),
subtitle = item.direction.extractAddress(),
isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming,
)
TxHistoryItem.TransactionType.Withdraw -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
title = TextReference.Str("Withdraw"),
subtitle = item.direction.extractAddress(),
isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming,
)
is TxHistoryItem.TransactionType.Custom -> TransactionState.Custom(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
title = TextReference.Str(type.id),
subtitle = item.direction.extractAddress(),
isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming,
)
}
}
private fun mapTransfer(item: TxHistoryItem): TransactionState {
return when (item.direction) {
is TxHistoryItem.TransactionDirection.Incoming -> TransactionState.Receive(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
)
is TxHistoryItem.TransactionDirection.Outgoing -> TransactionState.Send(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
)
}
}
private fun mapApprove(item: TxHistoryItem): TransactionState {
return TransactionState.Approve(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
)
}
private fun mapSwap(item: TxHistoryItem): TransactionState {
return TransactionState.Swap(
txHash = item.txHash,
address = item.direction.extractAddress(),
amount = item.amount.toCryptoCurrencyFormat(),
timestamp = item.getRawTimestamp(),
status = item.status.tiUiStatus(),
)
}
/**
* Get timestamp without formatting.
* It's life hack that help us to add transaction's group title to flow.
*
* @see [convert]
*/
private fun TxHistoryItem.getRawTimestamp() = this.timestampInMillis.toString()
private fun BigDecimal.toCryptoCurrencyFormat(): String {
return toFormattedCurrencyString(currency = symbol, decimals = decimals)
}
private fun TxHistoryItem.TransactionDirection.extractAddress(): TextReference = when (val addr = address) {
TxHistoryItem.Address.Multiple -> TextReference.Res(R.string.transaction_history_multiple_addresses)
is TxHistoryItem.Address.Single -> TextReference.Str(addr.rawAddress.toBriefAddressFormat())
}
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed
TxHistoryItem.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed
}
}

View file

@ -38,7 +38,6 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.models.Network
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.userwallets.UserWalletBuilder
@ -757,9 +756,9 @@ internal class WalletViewModel @Inject constructor(
updateNotifications(index)
}
private fun updateTxHistory(network: Network) {
private fun updateTxHistory(currency: CryptoCurrency) {
viewModelScope.launch(dispatchers.io) {
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(network)
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(currency.network)
uiState = stateFactory.getLoadingTxHistoryState(
itemsCountEither = txHistoryItemsCountEither,
@ -767,9 +766,7 @@ internal class WalletViewModel @Inject constructor(
txHistoryItemsCountEither.onRight {
uiState = stateFactory.getLoadedTxHistoryState(
txHistoryEither = txHistoryItemsUseCase(
network,
).map {
txHistoryEither = txHistoryItemsUseCase(currency = currency).map {
it.cachedIn(viewModelScope)
},
)
@ -786,7 +783,7 @@ internal class WalletViewModel @Inject constructor(
maybeCryptoCurrencyStatus.onRight { status ->
singleWalletCryptoCurrencyStatus = status
updateButtons(userWalletId = userWalletId, currencyStatus = status)
updateTxHistory(status.currency.network)
updateTxHistory(status.currency)
}
}
.flowOn(dispatchers.io)