Updated on 2026-08-14
This commit is contained in:
parent
81cce1254d
commit
879c8d603b
19 changed files with 566 additions and 415 deletions
|
|
@ -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<TransactionState>(
|
||||
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()),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<PagingData<TxHistoryItem>> {
|
||||
override fun getTxHistoryItems(currency: CryptoCurrency, pageSize: Int): Flow<PagingData<TxHistoryItem>> {
|
||||
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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<TxHistoryItem> {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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<TxHistoryItem>
|
||||
|
|
|
|||
|
|
@ -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<SdkTransactionHist
|
|||
timestampInMillis = value.timestamp,
|
||||
direction = value.direction.toDomain(),
|
||||
status = when (value.status) {
|
||||
TransactionStatus.Confirmed -> 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" },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<PagingData<TxHistoryItem>>
|
||||
fun getTxHistoryItems(currency: CryptoCurrency, pageSize: Int): Flow<PagingData<TxHistoryItem>>
|
||||
}
|
||||
|
|
@ -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<TxHistoryListError, Flow<PagingData<TxHistoryItem>>> {
|
||||
return either {
|
||||
repository
|
||||
.getTxHistoryItems(network = network, pageSize = pageSize)
|
||||
.getTxHistoryItems(currency = currency, pageSize = pageSize)
|
||||
.catch { raise(TxHistoryListError.DataError(it)) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Flow<PagingData<TxHistoryItem>>, 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<TxHistoryItemState>.insertGroupTitle(): PagingData<TxHistoryItemState> {
|
||||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue