diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt index b3622b4b1b..a98279f80f 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt @@ -23,6 +23,7 @@ import com.tangem.core.ui.R import com.tangem.core.ui.components.CircleShimmer import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.transactions.state.TransactionState +import com.tangem.core.ui.components.transactions.state.TransactionState.Content.* import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme @@ -116,11 +117,11 @@ private fun Icon(state: TransactionState, modifier: Modifier = Modifier) { modifier = modifier .size(TangemTheme.dimens.size40) .background( - color = when (state) { - is TransactionState.ProcessedTransactionContent -> { + color = when (state.status) { + is Status.Unconfirmed -> { TangemTheme.colors.icon.attention.copy(alpha = 0.1f) } - is TransactionState.CompletedTransactionContent -> { + is Status.Confirmed, Status.Failed -> { TangemTheme.colors.background.secondary } }, @@ -130,30 +131,20 @@ private fun Icon(state: TransactionState, modifier: Modifier = Modifier) { Icon( painter = painterResource( id = when (state) { - is TransactionState.Sending, - is TransactionState.Send, - -> R.drawable.ic_arrow_up_24 - - is TransactionState.Receiving, - is TransactionState.Receive, - -> R.drawable.ic_arrow_down_24 - - is TransactionState.Approving, - is TransactionState.Approved, - -> R.drawable.ic_doc_24 - - is TransactionState.Swapping, - is TransactionState.Swapped, - -> R.drawable.ic_exchange_vertical_24 + is TransactionState.Send -> R.drawable.ic_arrow_up_24 + is TransactionState.Receive -> R.drawable.ic_arrow_down_24 + is TransactionState.Approve -> R.drawable.ic_doc_24 + is TransactionState.Swap -> R.drawable.ic_exchange_vertical_24 + is TransactionState.Custom -> R.drawable.ic_exchange_vertical_24 }, ), contentDescription = null, modifier = Modifier .size(TangemTheme.dimens.size20) .align(Alignment.Center), - tint = when (state) { - is TransactionState.ProcessedTransactionContent -> TangemTheme.colors.icon.attention - is TransactionState.CompletedTransactionContent -> TangemTheme.colors.icon.informative + tint = when (state.status) { + Status.Confirmed, Status.Failed -> TangemTheme.colors.icon.informative + Status.Unconfirmed -> TangemTheme.colors.icon.attention }, ) } @@ -179,43 +170,29 @@ private fun Icon(state: TransactionState, modifier: Modifier = Modifier) { @Composable private fun Title(state: TransactionState, modifier: Modifier = Modifier) { when (state) { - is TransactionState.ProcessedTransactionContent -> { + is TransactionState.Content -> { Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6)) { Text( - text = stringResource( - id = when (state) { - is TransactionState.Sending -> R.string.common_transfer - is TransactionState.Receiving -> R.string.common_transfer - is TransactionState.Approving -> R.string.common_approval - is TransactionState.Swapping -> R.string.common_swap - }, - ), + text = when (state) { + is TransactionState.Approve -> stringResource(R.string.common_approval) + is TransactionState.Receive -> stringResource(R.string.common_transfer) + is TransactionState.Send -> stringResource(R.string.common_transfer) + is TransactionState.Swap -> stringResource(R.string.common_swap) + is TransactionState.Custom -> state.title.resolveReference() + }, color = TangemTheme.colors.text.primary1, style = TangemTheme.typography.subtitle2, ) - Image( - modifier = Modifier.align(Alignment.CenterVertically), - painter = painterResource(id = R.drawable.img_loader_15), - contentDescription = null, - ) + if (state.status is Status.Unconfirmed) { + Image( + modifier = Modifier.align(Alignment.CenterVertically), + painter = painterResource(id = R.drawable.img_loader_15), + contentDescription = null, + ) + } } } - is TransactionState.CompletedTransactionContent -> { - Text( - text = stringResource( - id = when (state) { - is TransactionState.Send -> R.string.common_transfer - is TransactionState.Receive -> R.string.common_transfer - is TransactionState.Approved -> R.string.common_approval - is TransactionState.Swapped -> R.string.common_swap - }, - ), - modifier = modifier, - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle2, - ) - } is TransactionState.Loading -> { RectangleShimmer( modifier = modifier.size(width = TangemTheme.dimens.size70, height = TangemTheme.dimens.size12), @@ -235,26 +212,28 @@ private fun Subtitle(state: TransactionState, modifier: Modifier = Modifier) { is TransactionState.Content -> { Text( text = when (state) { - is TransactionState.Sending, - is TransactionState.Send, - -> stringResource( + is TransactionState.Send -> stringResource( id = R.string.transaction_history_transaction_to_address, state.address.resolveReference(), ) - is TransactionState.Receiving, is TransactionState.Receive, - is TransactionState.Approving, - is TransactionState.Approved, + is TransactionState.Approve, -> stringResource( id = R.string.transaction_history_transaction_from_address, state.address.resolveReference(), ) - is TransactionState.Swapping, - is TransactionState.Swapped, - -> stringResource( + is TransactionState.Swap -> stringResource( id = R.string.transaction_history_contract_address, state.address.resolveReference(), ) + is TransactionState.Custom -> stringResource( + id = if (state.isIncoming) { + R.string.transaction_history_transaction_from_address + } else { + R.string.transaction_history_transaction_to_address + }, + state.subtitle.resolveReference(), + ) }, modifier = modifier, textAlign = TextAlign.Start, @@ -357,53 +336,53 @@ private fun Preview_TransactionItem_DarkTheme( private class TransactionItemStateProvider : CollectionPreviewParameterProvider( collection = listOf( - TransactionState.Sending( - txHash = UUID.randomUUID().toString(), - address = TextReference.Str("33BddS...ga2B"), - amount = "-0.500913 BTC", - timestamp = "8:41", - ), - TransactionState.Receiving( - txHash = UUID.randomUUID().toString(), - address = TextReference.Str("33BddS...ga2B"), - amount = "+0.500913 BTC", - timestamp = "8:41", - ), - TransactionState.Approving( - txHash = UUID.randomUUID().toString(), - address = TextReference.Str("33BddS...ga2B"), - amount = "+0.500913 BTC", - timestamp = "8:41", - ), - TransactionState.Swapping( - txHash = UUID.randomUUID().toString(), - address = TextReference.Str("33BddS...ga2B"), - amount = "+0.500913 BTC", - timestamp = "8:41", - ), TransactionState.Send( txHash = UUID.randomUUID().toString(), address = TextReference.Str("33BddS...ga2B"), amount = "-0.500913 BTC", timestamp = "8:41", + status = Status.Confirmed, ), TransactionState.Receive( txHash = UUID.randomUUID().toString(), address = TextReference.Str("33BddS...ga2B"), amount = "+0.500913 BTC", timestamp = "8:41", + status = Status.Unconfirmed, ), - TransactionState.Approved( + TransactionState.Approve( txHash = UUID.randomUUID().toString(), address = TextReference.Str("33BddS...ga2B"), amount = "+0.500913 BTC", timestamp = "8:41", + status = Status.Failed, ), - TransactionState.Swapped( + TransactionState.Swap( txHash = UUID.randomUUID().toString(), address = TextReference.Str("33BddS...ga2B"), amount = "+0.500913 BTC", timestamp = "8:41", + status = Status.Unconfirmed, + ), + TransactionState.Custom( + txHash = UUID.randomUUID().toString(), + address = TextReference.Str("33BddS...ga2B"), + amount = "+0.500913 BTC", + timestamp = "8:41", + status = Status.Confirmed, + title = TextReference.Str("Submit"), + subtitle = TextReference.Str("33BddS...ga2B"), + isIncoming = true, + ), + TransactionState.Custom( + txHash = UUID.randomUUID().toString(), + address = TextReference.Str("33BddS...ga2B"), + amount = "+0.500913 BTC", + timestamp = "8:41", + status = Status.Confirmed, + title = TextReference.Str("Submit"), + subtitle = TextReference.Str("33BddS...ga2B"), + isIncoming = false, ), TransactionState.Loading(txHash = UUID.randomUUID().toString()), ), diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/state/TransactionState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/state/TransactionState.kt index 8178e83e61..5335144a70 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/state/TransactionState.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/state/TransactionState.kt @@ -15,127 +15,41 @@ sealed interface TransactionState { /** * Content state * - * @property txHash transaction hash * @property address address * @property amount amount * @property timestamp timestamp + * @property status transaction status */ - sealed class Content( - override val txHash: String, - open val address: TextReference, - open val amount: String, - open val timestamp: String, - ) : TransactionState { + sealed class Content : TransactionState { + + abstract val address: TextReference + abstract val amount: String + abstract val timestamp: String + abstract val status: Status fun copySealed( txHash: String = this.txHash, address: TextReference = this.address, amount: String = this.amount, timestamp: String = this.timestamp, + status: Status = this.status, ): Content { return when (this) { - is Approved -> copy(txHash, address, amount, timestamp) - is Receive -> copy(txHash, address, amount, timestamp) - is Send -> copy(txHash, address, amount, timestamp) - is Swapped -> copy(txHash, address, amount, timestamp) - is Approving -> copy(txHash, address, amount, timestamp) - is Receiving -> copy(txHash, address, amount, timestamp) - is Sending -> copy(txHash, address, amount, timestamp) - is Swapping -> copy(txHash, address, amount, timestamp) + is Approve -> copy(txHash, address, amount, timestamp, status) + is Receive -> copy(txHash, address, amount, timestamp, status) + is Send -> copy(txHash, address, amount, timestamp, status) + is Swap -> copy(txHash, address, amount, timestamp, status) + is Custom -> copy(txHash, address, amount, timestamp, status) } } + + sealed class Status { + object Failed : Status() + object Confirmed : Status() + object Unconfirmed : Status() + } } - /** - * Content state for processed transaction - * - * @property txHash transaction hash - * @property address address - * @property amount amount - * @property timestamp timestamp - */ - sealed class ProcessedTransactionContent( - override val txHash: String, - override val address: TextReference, - override val amount: String, - override val timestamp: String, - ) : Content(txHash, address, amount, timestamp) - - /** - * Content state for completed transaction - * - * @property txHash transaction hash - * @property address address - * @property amount amount - * @property timestamp timestamp - */ - sealed class CompletedTransactionContent( - override val txHash: String, - override val address: TextReference, - override val amount: String, - override val timestamp: String, - ) : Content(txHash, address, amount, timestamp) - - /** - * Processed sending transaction state - * - * @property txHash transaction hash - * @property address address - * @property amount amount - * @property timestamp timestamp - */ - data class Sending( - override val txHash: String, - override val address: TextReference, - override val amount: String, - override val timestamp: String, - ) : ProcessedTransactionContent(txHash, address, amount, timestamp) - - /** - * Processed receiving transaction state - * - * @property txHash transaction hash - * @property address address - * @property amount amount - * @property timestamp timestamp - */ - data class Receiving( - override val txHash: String, - override val address: TextReference, - override val amount: String, - override val timestamp: String, - ) : ProcessedTransactionContent(txHash, address, amount, timestamp) - - /** - * Processed approving transaction state - * - * @property txHash transaction hash - * @property address address - * @property amount amount - * @property timestamp timestamp - */ - data class Approving( - override val txHash: String, - override val address: TextReference, - override val amount: String, - override val timestamp: String, - ) : ProcessedTransactionContent(txHash, address, amount, timestamp) - - /** - * Processed swapping transaction state - * - * @property txHash transaction hash - * @property address address - * @property amount amount - * @property timestamp timestamp - */ - data class Swapping( - override val txHash: String, - override val address: TextReference, - override val amount: String, - override val timestamp: String, - ) : ProcessedTransactionContent(txHash, address, amount, timestamp) - /** * Completed sending transaction state * @@ -149,7 +63,8 @@ sealed interface TransactionState { override val address: TextReference, override val amount: String, override val timestamp: String, - ) : CompletedTransactionContent(txHash, address, amount, timestamp) + override val status: Status, + ) : Content() /** * Completed receiving transaction state @@ -164,7 +79,8 @@ sealed interface TransactionState { override val address: TextReference, override val amount: String, override val timestamp: String, - ) : CompletedTransactionContent(txHash, address, amount, timestamp) + override val status: Status, + ) : Content() /** * Completed approving transaction state @@ -174,12 +90,13 @@ sealed interface TransactionState { * @property amount amount * @property timestamp timestamp */ - data class Approved( + data class Approve( override val txHash: String, override val address: TextReference, override val amount: String, override val timestamp: String, - ) : CompletedTransactionContent(txHash, address, amount, timestamp) + override val status: Status, + ) : Content() /** * Completed swapping transaction state @@ -189,12 +106,24 @@ sealed interface TransactionState { * @property amount amount * @property timestamp timestamp */ - data class Swapped( + data class Swap( override val txHash: String, override val address: TextReference, override val amount: String, override val timestamp: String, - ) : CompletedTransactionContent(txHash, address, amount, timestamp) + override val status: Status, + ) : Content() + + data class Custom( + override val txHash: String, + override val address: TextReference, + override val amount: String, + override val timestamp: String, + override val status: Status, + val title: TextReference, + val subtitle: TextReference, + val isIncoming: Boolean, + ) : Content() /** * Loading state diff --git a/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/DefaultTxHistoryRepository.kt b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/DefaultTxHistoryRepository.kt index 7aa4add858..a490199e35 100644 --- a/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/DefaultTxHistoryRepository.kt +++ b/data/txhistory/src/main/kotlin/com/tangem/data/txhistory/repository/DefaultTxHistoryRepository.kt @@ -5,6 +5,7 @@ import androidx.paging.PagingConfig import androidx.paging.PagingData import com.tangem.data.txhistory.repository.paging.TxHistoryPagingSource import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.Network import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryState @@ -33,7 +34,7 @@ class DefaultTxHistoryRepository( } } - override fun getTxHistoryItems(network: Network, pageSize: Int): Flow> { + override fun getTxHistoryItems(currency: CryptoCurrency, pageSize: Int): Flow> { val userWallet = getUserWallet() return Pager( config = PagingConfig( @@ -44,7 +45,7 @@ class DefaultTxHistoryRepository( loadPage = { page: Int, pageSize: Int -> walletManagersFacade.getTxHistoryItems( userWalletId = userWallet.walletId, - network = network, + currency = currency, page = page, pageSize = pageSize, ) diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt index 90455b7b92..64553c5f35 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt @@ -4,6 +4,7 @@ import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.blockchains.solana.RentProvider import com.tangem.blockchain.common.* import com.tangem.blockchain.common.address.Address +import com.tangem.blockchain.common.txhistory.TransactionHistoryRequest import com.tangem.blockchain.extensions.Result import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.datasource.config.ConfigManager @@ -89,16 +90,16 @@ class DefaultWalletManagersFacade( override suspend fun getTxHistoryItems( userWalletId: UserWalletId, - network: Network, + currency: CryptoCurrency, page: Int, pageSize: Int, ): PaginationWrapper { val userWallet = getUserWallet(userWalletId) - val blockchain = Blockchain.fromId(network.id.value) + val blockchain = Blockchain.fromId(currency.network.id.value) val walletManager = getOrCreateWalletManager( userWallet = userWallet, blockchain = blockchain, - derivationPath = network.derivationPath.value, + derivationPath = currency.network.derivationPath.value, ) requireNotNull(walletManager) { @@ -106,9 +107,14 @@ class DefaultWalletManagersFacade( } val itemsResult = walletManager.getTransactionsHistory( - address = walletManager.wallet.address, - page = page, - pageSize = pageSize, + request = TransactionHistoryRequest( + address = walletManager.wallet.address, + page = TransactionHistoryRequest.Page(number = page, size = pageSize), + filterType = when (currency) { + is CryptoCurrency.Coin -> TransactionHistoryRequest.FilterType.Coin + is CryptoCurrency.Token -> TransactionHistoryRequest.FilterType.Contract(currency.contractAddress) + }, + ), ) return when (itemsResult) { diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt index a958a783aa..23e5a9fd8c 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt @@ -57,13 +57,13 @@ interface WalletManagersFacade { * Returns transaction history items wrapped to pagination * * @param userWalletId The ID of the user's wallet. - * @param network The network. + * @param currency currency. * @param page Pagination page. * @param pageSize Pagination size. */ suspend fun getTxHistoryItems( userWalletId: UserWalletId, - network: Network, + currency: CryptoCurrency, page: Int, pageSize: Int, ): PaginationWrapper diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTransactionHistoryItemConverter.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTransactionHistoryItemConverter.kt index df57ff2349..d0f0ef7d65 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTransactionHistoryItemConverter.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTransactionHistoryItemConverter.kt @@ -1,6 +1,5 @@ package com.tangem.domain.walletmanager.utils -import com.tangem.blockchain.common.TransactionStatus import com.tangem.blockchain.common.txhistory.TransactionHistoryItem import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.utils.converter.Converter @@ -13,11 +12,20 @@ internal class SdkTransactionHistoryItemConverter : Converter TxHistoryItem.TxStatus.Confirmed - TransactionStatus.Unconfirmed -> TxHistoryItem.TxStatus.Unconfirmed + TransactionHistoryItem.TransactionStatus.Confirmed -> TxHistoryItem.TransactionStatus.Confirmed + TransactionHistoryItem.TransactionStatus.Failed -> TxHistoryItem.TransactionStatus.Failed + TransactionHistoryItem.TransactionStatus.Unconfirmed -> TxHistoryItem.TransactionStatus.Unconfirmed }, - type = when (value.type) { + type = when (val type = value.type) { TransactionHistoryItem.TransactionType.Transfer -> TxHistoryItem.TransactionType.Transfer + TransactionHistoryItem.TransactionType.Approve -> TxHistoryItem.TransactionType.Approve + is TransactionHistoryItem.TransactionType.Custom -> TxHistoryItem.TransactionType.Custom(type.id) + TransactionHistoryItem.TransactionType.Deposit -> TxHistoryItem.TransactionType.Deposit + TransactionHistoryItem.TransactionType.Submit -> TxHistoryItem.TransactionType.Submit + TransactionHistoryItem.TransactionType.Supply -> TxHistoryItem.TransactionType.Supply + TransactionHistoryItem.TransactionType.Swap -> TxHistoryItem.TransactionType.Swap + TransactionHistoryItem.TransactionType.Unoswap -> TxHistoryItem.TransactionType.Unoswap + TransactionHistoryItem.TransactionType.Withdraw -> TxHistoryItem.TransactionType.Withdraw }, amount = requireNotNull(value.amount.value) { "Transaction amount value must not be null" }, ) diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt index effa52cfdb..0855841539 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt @@ -130,8 +130,8 @@ internal class UpdateWalletManagerResultFactory { timestampInMillis = TimeUnit.SECONDS.toMillis(millis), direction = direction, status = when (data.status) { - TransactionStatus.Confirmed -> TxHistoryItem.TxStatus.Confirmed - TransactionStatus.Unconfirmed -> TxHistoryItem.TxStatus.Unconfirmed + TransactionStatus.Confirmed -> TxHistoryItem.TransactionStatus.Confirmed + TransactionStatus.Unconfirmed -> TxHistoryItem.TransactionStatus.Unconfirmed }, type = TxHistoryItem.TransactionType.Transfer, amount = amount, diff --git a/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/TxHistoryItem.kt b/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/TxHistoryItem.kt index c17f0dccb6..b956574ce5 100644 --- a/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/TxHistoryItem.kt +++ b/domain/txhistory/models/src/main/kotlin/com/tangem/domain/txhistory/models/TxHistoryItem.kt @@ -6,7 +6,7 @@ data class TxHistoryItem( val txHash: String, val timestampInMillis: Long, val direction: TransactionDirection, - val status: TxStatus, + val status: TransactionStatus, val type: TransactionType, val amount: BigDecimal, ) { @@ -20,9 +20,21 @@ data class TxHistoryItem( sealed interface TransactionType { object Transfer : TransactionType + object Submit : TransactionType + object Approve : TransactionType + object Supply : TransactionType + object Withdraw : TransactionType + object Deposit : TransactionType + object Swap : TransactionType + object Unoswap : TransactionType + data class Custom(val id: String) : TransactionType } - enum class TxStatus { Confirmed, Unconfirmed } + sealed class TransactionStatus { + object Failed : TransactionStatus() + object Unconfirmed : TransactionStatus() + object Confirmed : TransactionStatus() + } sealed class Address { data class Single(val rawAddress: String) : Address() diff --git a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepository.kt b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepository.kt index b912b2111e..7d180a783b 100644 --- a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepository.kt +++ b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/repository/TxHistoryRepository.kt @@ -1,6 +1,7 @@ package com.tangem.domain.txhistory.repository import androidx.paging.PagingData +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.Network import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryListError @@ -13,5 +14,5 @@ interface TxHistoryRepository { suspend fun getTxHistoryItemsCount(network: Network): Int @Throws(TxHistoryListError::class) - fun getTxHistoryItems(network: Network, pageSize: Int): Flow> + fun getTxHistoryItems(currency: CryptoCurrency, pageSize: Int): Flow> } \ No newline at end of file diff --git a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetTxHistoryItemsUseCase.kt b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetTxHistoryItemsUseCase.kt index 77ef74e98a..e72cbdca2b 100644 --- a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetTxHistoryItemsUseCase.kt +++ b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetTxHistoryItemsUseCase.kt @@ -3,7 +3,7 @@ package com.tangem.domain.txhistory.usecase import androidx.paging.PagingData import arrow.core.Either import arrow.core.raise.either -import com.tangem.domain.tokens.models.Network +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryListError import com.tangem.domain.txhistory.repository.TxHistoryRepository @@ -15,12 +15,12 @@ private const val DEFAULT_PAGE_SIZE = 20 class GetTxHistoryItemsUseCase(private val repository: TxHistoryRepository) { operator fun invoke( - network: Network, + currency: CryptoCurrency, pageSize: Int = DEFAULT_PAGE_SIZE, ): Either>> { return either { repository - .getTxHistoryItems(network = network, pageSize = pageSize) + .getTxHistoryItems(currency = currency, pageSize = pageSize) .catch { raise(TxHistoryListError.DataError(it)) } } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt index d1de3a2c01..74c1a93cb7 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt @@ -6,16 +6,12 @@ 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.domain.txhistory.models.TxHistoryItem import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents -import com.tangem.features.tokendetails.impl.R import com.tangem.utils.converter.Converter import com.tangem.utils.extensions.isToday import com.tangem.utils.extensions.isYesterday -import com.tangem.utils.toBriefAddressFormat -import com.tangem.utils.toFormattedCurrencyString import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -25,7 +21,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 internal class TokenDetailsTxHistoryItemFlowConverter( @@ -35,6 +30,10 @@ internal class TokenDetailsTxHistoryItemFlowConverter( private val clickIntents: TokenDetailsClickIntents, ) : Converter>, TxHistoryState> { + private val txHistoryItemConverter by lazy { + TokenDetailsTxHistoryTransactionStateConverter(symbol = symbol, decimals = decimals) + } + /** Example, 2 Aug, 2023 */ private val dateFormatter by lazy { DateTimeFormatterBuilder() @@ -84,62 +83,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter( } 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) - } - is TxHistoryItem.TransactionDirection.Outgoing -> { - createOutgoingTransferTransaction(item, direction) - } - } - } - } - } - - private fun createIncomingTransferTransaction( - item: TxHistoryItem, - direction: TxHistoryItem.TransactionDirection.Incoming, - ): TransactionState { - return when (item.status) { - TxHistoryItem.TxStatus.Confirmed -> TransactionState.Receive( - txHash = item.txHash, - address = direction.extractAddress(), - amount = item.amount.toCryptoCurrencyFormat(), - timestamp = item.getRawTimestamp(), - ) - TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Receiving( - txHash = item.txHash, - address = direction.extractAddress(), - amount = item.amount.toCryptoCurrencyFormat(), - timestamp = item.getRawTimestamp(), - ) - } - } - - private fun createOutgoingTransferTransaction( - item: TxHistoryItem, - direction: TxHistoryItem.TransactionDirection.Outgoing, - ): TransactionState { - return when (item.status) { - TxHistoryItem.TxStatus.Confirmed -> TransactionState.Send( - txHash = item.txHash, - address = direction.extractAddress(), - amount = item.amount.toCryptoCurrencyFormat(), - timestamp = item.getRawTimestamp(), - ) - TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Sending( - txHash = item.txHash, - address = direction.extractAddress(), - amount = item.amount.toCryptoCurrencyFormat(), - timestamp = item.getRawTimestamp(), - ) - } - } - - private fun BigDecimal.toCryptoCurrencyFormat(): String { - return toFormattedCurrencyString(currency = symbol, decimals = decimals) + return txHistoryItemConverter.convert(value = item) } private fun PagingData.insertGroupTitle(): PagingData { @@ -185,14 +129,6 @@ internal class TokenDetailsTxHistoryItemFlowConverter( } } - /** - * 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 @@ -225,9 +161,4 @@ internal class TokenDetailsTxHistoryItemFlowConverter( 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()) - } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryToTransactionStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryToTransactionStateConverter.kt index e0e714eea4..3740743315 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryToTransactionStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryToTransactionStateConverter.kt @@ -29,60 +29,116 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter( } override fun convert(value: TxHistoryItem): TransactionState { - return when (value.type) { - TxHistoryItem.TransactionType.Transfer -> { - when (val direction = value.direction) { - is TxHistoryItem.TransactionDirection.Incoming -> { - createIncomingTransferTransaction(value, direction) - } - is TxHistoryItem.TransactionDirection.Outgoing -> { - createOutgoingTransferTransaction(value, direction) - } - } - } - } + return createTransactionStateItem(item = value) } - private fun createIncomingTransferTransaction( - item: TxHistoryItem, - direction: TxHistoryItem.TransactionDirection.Incoming, - ): TransactionState { - return when (item.status) { - TxHistoryItem.TxStatus.Confirmed -> TransactionState.Receive( + // 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 = direction.extractAddress(), + address = item.direction.extractAddress(), amount = item.amount.toCryptoCurrencyFormat(), timestamp = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + status = item.status.tiUiStatus(), + title = TextReference.Str("Deposit"), + subtitle = item.direction.extractAddress(), + isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming, ) - TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Receiving( + TxHistoryItem.TransactionType.Submit -> TransactionState.Custom( txHash = item.txHash, - address = direction.extractAddress(), + address = item.direction.extractAddress(), amount = item.amount.toCryptoCurrencyFormat(), timestamp = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + 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 = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + 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 = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + 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 = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + 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 = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + status = item.status.tiUiStatus(), + title = TextReference.Str(type.id), + subtitle = item.direction.extractAddress(), + isIncoming = item.direction is TxHistoryItem.TransactionDirection.Incoming, ) } } - private fun createOutgoingTransferTransaction( - item: TxHistoryItem, - direction: TxHistoryItem.TransactionDirection.Outgoing, - ): TransactionState { - return when (item.status) { - TxHistoryItem.TxStatus.Confirmed -> TransactionState.Send( + private fun mapTransfer(item: TxHistoryItem): TransactionState { + return when (item.direction) { + is TxHistoryItem.TransactionDirection.Incoming -> TransactionState.Receive( txHash = item.txHash, - address = direction.extractAddress(), + address = item.direction.extractAddress(), amount = item.amount.toCryptoCurrencyFormat(), timestamp = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + status = item.status.tiUiStatus(), ) - TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Sending( + is TxHistoryItem.TransactionDirection.Outgoing -> TransactionState.Send( txHash = item.txHash, - address = direction.extractAddress(), + address = item.direction.extractAddress(), amount = item.amount.toCryptoCurrencyFormat(), timestamp = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + 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 = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + 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 = timeFormatter.print(DateTime(item.timestampInMillis, DateTimeZone.getDefault())), + status = item.status.tiUiStatus(), + ) + } + private fun BigDecimal.toCryptoCurrencyFormat(): String { return toFormattedCurrencyString(currency = symbol, decimals = decimals) } @@ -91,4 +147,10 @@ internal class TokenDetailsTxHistoryToTransactionStateConverter( 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 + } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt new file mode 100644 index 0000000000..d5e78350e5 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryTransactionStateConverter.kt @@ -0,0 +1,150 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.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.features.tokendetails.impl.R +import com.tangem.utils.converter.Converter +import com.tangem.utils.toBriefAddressFormat +import com.tangem.utils.toFormattedCurrencyString +import java.math.BigDecimal + +internal class TokenDetailsTxHistoryTransactionStateConverter( + private val symbol: String, + private val decimals: Int, +) : Converter { + + 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 + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index 36cfad8630..3824db3ec1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -170,9 +170,7 @@ internal class TokenDetailsViewModel @Inject constructor( txHistoryItemsCountEither.onRight { uiState = stateFactory.getLoadedTxHistoryState( - txHistoryEither = txHistoryItemsUseCase( - network = cryptoCurrency.network, - ).map { + txHistoryEither = txHistoryItemsUseCase(currency = cryptoCurrency).map { it.cachedIn(viewModelScope) }, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 4b51515ef3..53c4e086ce 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -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, ), ), ), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryItemFlowConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryItemFlowConverter.kt index d1d713271b..1443a0c980 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryItemFlowConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryItemFlowConverter.kt @@ -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>, 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.insertGroupTitle(): PagingData { @@ -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()) - } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryTransactionStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryTransactionStateConverter.kt new file mode 100644 index 0000000000..ca23784729 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/txhistory/WalletTxHistoryTransactionStateConverter.kt @@ -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 { + + 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 + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 0a92d35a37..3cd1221d97 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -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) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 4c97997ed7..2ba79f375f 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -81,7 +81,7 @@ okHttp-prettyLogging = "3.1.0" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-350" +tangemBlockchainSdk = "develop-351" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-297" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds