Updated on 2026-08-14

This commit is contained in:
Tangem 2024-01-15 13:45:06 +03:00
commit 025cd8aa9b
17 changed files with 262 additions and 155 deletions

View file

@ -20,6 +20,13 @@ class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, Token
}
}
fun convert(currency: CryptoCurrency): TokenIconState {
return when (currency) {
is CryptoCurrency.Coin -> getIconStateForCoin(currency, isUnreachable = false)
is CryptoCurrency.Token -> getIconStateForToken(currency, isErrorStatus = false)
}
}
private fun getIconStateForCoin(coin: CryptoCurrency.Coin, isUnreachable: Boolean): TokenIconState.CoinIcon {
return TokenIconState.CoinIcon(
url = coin.iconUrl,

View file

@ -13,7 +13,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency
import timber.log.Timber
import com.tangem.blockchain.common.Token as SdkToken
internal class ResponseCryptoCurrenciesFactory {
class ResponseCryptoCurrenciesFactory {
fun createCurrency(
currencyId: CryptoCurrency.ID,

View file

@ -4,7 +4,7 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.tokens.model.CryptoCurrency
internal class UserTokensResponseFactory {
class UserTokensResponseFactory {
fun createUserTokensResponse(
currencies: List<CryptoCurrency>,

View file

@ -5,13 +5,12 @@ import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectList
import com.tangem.datasource.local.preferences.utils.getObjectListSync
import com.tangem.datasource.local.preferences.utils.getObjectMap
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.converters.SavedSwapTransactionListConverter
import com.tangem.feature.swap.domain.SwapTransactionRepository
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
import com.tangem.feature.swap.domain.models.domain.SavedLastSwappedCryptoCurrency
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel
import com.tangem.feature.swap.domain.models.domain.*
import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@ -20,23 +19,25 @@ class DefaultSwapTransactionRepository(
private val appPreferencesStore: AppPreferencesStore,
) : SwapTransactionRepository {
private val converter = SavedSwapTransactionListConverter()
override suspend fun storeTransaction(
userWalletId: UserWalletId,
fromCryptoCurrencyId: CryptoCurrency.ID,
toCryptoCurrencyId: CryptoCurrency.ID,
fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency,
transaction: SavedSwapTransactionModel,
) {
transaction.status?.let { storeTransactionState(transaction.txId, it) }
appPreferencesStore.editData { mutablePreferences ->
val savedTransactions: List<SavedSwapTransactionListModel>? = mutablePreferences.getObjectList(
val savedTransactions: List<SavedSwapTransactionListModelInner>? = mutablePreferences.getObjectList(
key = PreferencesKeys.SWAP_TRANSACTIONS_KEY,
)
val tokenTransactions = savedTransactions
?.firstOrNull {
it.checkId(
checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrencyId,
toCurrencyId = toCryptoCurrencyId,
fromCurrencyId = fromCryptoCurrency.id,
toCurrencyId = toCryptoCurrency.id,
)
}
?.transactions
@ -49,15 +50,15 @@ class DefaultSwapTransactionRepository(
key = PreferencesKeys.SWAP_TRANSACTIONS_KEY,
value = savedTransactions?.updateList(
userWalletId = userWalletId,
fromCryptoCurrencyId = fromCryptoCurrencyId,
toCryptoCurrencyId = toCryptoCurrencyId,
fromCryptoCurrency = fromCryptoCurrency,
toCryptoCurrency = toCryptoCurrency,
transactions = tokenTransactions,
) ?: listOf(
SavedSwapTransactionListModel(
userWalletId = userWalletId.stringValue,
fromCryptoCurrencyId = fromCryptoCurrencyId.value,
toCryptoCurrencyId = toCryptoCurrencyId.value,
transactions = tokenTransactions,
converter.default(
userWalletId = userWalletId,
fromCryptoCurrency = fromCryptoCurrency,
toCryptoCurrency = toCryptoCurrency,
tokenTransactions = listOf(transaction),
),
),
)
@ -67,11 +68,12 @@ class DefaultSwapTransactionRepository(
override suspend fun getTransactions(
userWalletId: UserWalletId,
cryptoCurrencyId: CryptoCurrency.ID,
scanResponse: ScanResponse,
): Flow<List<SavedSwapTransactionListModel>?> {
val txStatuses = appPreferencesStore.getObjectMap<ExchangeStatusModel>(
key = PreferencesKeys.SWAP_TRANSACTIONS_STATUSES_KEY,
)
return appPreferencesStore.getObjectList<SavedSwapTransactionListModel>(
return appPreferencesStore.getObjectList<SavedSwapTransactionListModelInner>(
key = PreferencesKeys.SWAP_TRANSACTIONS_KEY,
).map { savedTransactions ->
val currencyTxs = savedTransactions
@ -83,11 +85,11 @@ class DefaultSwapTransactionRepository(
)
}
currencyTxs?.map { currencyTx ->
currencyTx.copy(
transactions = currencyTx.transactions.map { tx ->
tx.copy(status = txStatuses[tx.txId])
},
currencyTxs?.mapNotNull {
converter.convertBack(
value = it,
scanResponse = scanResponse,
txStatuses = txStatuses,
)
}
}
@ -95,21 +97,21 @@ class DefaultSwapTransactionRepository(
override suspend fun removeTransaction(
userWalletId: UserWalletId,
fromCryptoCurrencyId: CryptoCurrency.ID,
toCryptoCurrencyId: CryptoCurrency.ID,
fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency,
txId: String,
) {
clearTransactionsStatuses(txId = txId)
appPreferencesStore.editData { mutablePreferences ->
val savedList: List<SavedSwapTransactionListModel>? = mutablePreferences.getObjectList(
val savedList: List<SavedSwapTransactionListModelInner>? = mutablePreferences.getObjectList(
key = PreferencesKeys.SWAP_TRANSACTIONS_KEY,
)
val tokenTransactions = savedList
?.first {
?.firstOrNull {
it.checkId(
checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrencyId,
toCurrencyId = toCryptoCurrencyId,
fromCurrencyId = fromCryptoCurrency.id,
toCurrencyId = toCryptoCurrency.id,
)
}
?.transactions
@ -120,15 +122,15 @@ class DefaultSwapTransactionRepository(
savedList?.filterNot {
it.checkId(
checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrencyId,
toCurrencyId = toCryptoCurrencyId,
fromCurrencyId = fromCryptoCurrency.id,
toCurrencyId = toCryptoCurrency.id,
)
}
} else {
savedList.updateList(
userWalletId = userWalletId,
fromCryptoCurrencyId = fromCryptoCurrencyId,
toCryptoCurrencyId = toCryptoCurrencyId,
fromCryptoCurrency = fromCryptoCurrency,
toCryptoCurrency = toCryptoCurrency,
transactions = tokenTransactions,
)
}
@ -192,7 +194,7 @@ class DefaultSwapTransactionRepository(
}
}
private fun SavedSwapTransactionListModel.checkId(
private fun SavedSwapTransactionListModelInner.checkId(
checkUserWalletId: UserWalletId,
fromCurrencyId: CryptoCurrency.ID,
toCurrencyId: CryptoCurrency.ID,
@ -202,24 +204,24 @@ class DefaultSwapTransactionRepository(
fromCryptoCurrencyId == fromCurrencyId.value
}
private fun List<SavedSwapTransactionListModel>.updateList(
private fun List<SavedSwapTransactionListModelInner>.updateList(
userWalletId: UserWalletId,
fromCryptoCurrencyId: CryptoCurrency.ID,
toCryptoCurrencyId: CryptoCurrency.ID,
fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency,
transactions: List<SavedSwapTransactionModel>,
): List<SavedSwapTransactionListModel> {
): List<SavedSwapTransactionListModelInner> {
return addOrReplace(
item = SavedSwapTransactionListModel(
userWalletId = userWalletId.stringValue,
fromCryptoCurrencyId = fromCryptoCurrencyId.value,
toCryptoCurrencyId = toCryptoCurrencyId.value,
transactions = transactions,
item = converter.default(
userWalletId = userWalletId,
fromCryptoCurrency = fromCryptoCurrency,
toCryptoCurrency = toCryptoCurrency,
tokenTransactions = transactions,
),
predicate = {
it.checkId(
checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrencyId,
toCurrencyId = toCryptoCurrencyId,
fromCurrencyId = fromCryptoCurrency.id,
toCurrencyId = toCryptoCurrency.id,
)
},
)

View file

@ -0,0 +1,78 @@
package com.tangem.feature.swap.converters
import com.tangem.data.tokens.utils.ResponseCryptoCurrenciesFactory
import com.tangem.data.tokens.utils.UserTokensResponseFactory
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModelInner
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel
import com.tangem.utils.converter.Converter
class SavedSwapTransactionListConverter :
Converter<SavedSwapTransactionListModel, SavedSwapTransactionListModelInner> {
private val responseCryptoCurrenciesFactory = ResponseCryptoCurrenciesFactory()
private val userTokensResponseFactory = UserTokensResponseFactory()
override fun convert(value: SavedSwapTransactionListModel) = SavedSwapTransactionListModelInner(
userWalletId = value.userWalletId,
fromCryptoCurrencyId = value.fromCryptoCurrencyId,
toCryptoCurrencyId = value.toCryptoCurrencyId,
fromTokensResponse = userTokensResponseFactory.createResponseToken(
value.fromCryptoCurrency,
),
toTokensResponse = userTokensResponseFactory.createResponseToken(
value.toCryptoCurrency,
),
transactions = value.transactions,
)
fun convertBack(
value: SavedSwapTransactionListModelInner,
scanResponse: ScanResponse,
txStatuses: Map<String, ExchangeStatusModel>,
): SavedSwapTransactionListModel? {
val fromToken = value.fromTokensResponse
val toToken = value.toTokensResponse
return if (fromToken == null || toToken == null) {
null
} else {
val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = fromToken,
scanResponse = scanResponse,
) ?: return null
val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = toToken,
scanResponse = scanResponse,
) ?: return null
return SavedSwapTransactionListModel(
transactions = value.transactions.map { tx ->
tx.copy(status = txStatuses[tx.txId])
},
userWalletId = value.userWalletId,
fromCryptoCurrencyId = value.fromCryptoCurrencyId,
toCryptoCurrencyId = value.toCryptoCurrencyId,
fromCryptoCurrency = fromCryptoCurrency,
toCryptoCurrency = toCryptoCurrency,
)
}
}
fun default(
userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency,
tokenTransactions: List<SavedSwapTransactionModel>,
) = SavedSwapTransactionListModelInner(
userWalletId = userWalletId.stringValue,
fromCryptoCurrencyId = fromCryptoCurrency.id.value,
toCryptoCurrencyId = toCryptoCurrency.id.value,
fromTokensResponse = userTokensResponseFactory.createResponseToken(fromCryptoCurrency),
toTokensResponse = userTokensResponseFactory.createResponseToken(toCryptoCurrency),
transactions = tokenTransactions,
)
}

View file

@ -9,8 +9,8 @@ import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.legacy.WalletsStateHolder
import com.tangem.feature.swap.DefaultSwapTransactionRepository
import com.tangem.feature.swap.DefaultSwapRepository
import com.tangem.feature.swap.DefaultSwapTransactionRepository
import com.tangem.feature.swap.converters.ErrorsDataConverter
import com.tangem.feature.swap.domain.SwapTransactionRepository
import com.tangem.feature.swap.domain.api.SwapRepository

View file

@ -19,6 +19,7 @@ dependencies {
kapt(deps.hilt.kapt)
/** Domain */
implementation(projects.domain.models)
implementation(projects.domain.tokens)
implementation(projects.domain.tokens.models)
implementation(projects.domain.wallets)

View file

@ -15,6 +15,7 @@ dependencies {
/** Core modules */
implementation(projects.core.utils)
implementation(projects.core.datasource)
/** Other Libraries **/
implementation(deps.kotlin.serialization)

View file

@ -1,11 +1,28 @@
package com.tangem.feature.swap.domain.models.domain
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import java.math.BigDecimal
data class SavedSwapTransactionListModel(
val userWalletId: String,
val fromCryptoCurrencyId: String,
val toCryptoCurrencyId: String,
val fromCryptoCurrency: CryptoCurrency,
val toCryptoCurrency: CryptoCurrency,
val transactions: List<SavedSwapTransactionModel>,
)
/**
* IMPORTANT !!!
* This is internal model for storing swap tx. It should not be used outside.
*/
data class SavedSwapTransactionListModelInner(
val userWalletId: String,
val fromCryptoCurrencyId: String,
val toCryptoCurrencyId: String,
val fromTokensResponse: UserTokensResponse.Token? = null,
val toTokensResponse: UserTokensResponse.Token? = null,
val transactions: List<SavedSwapTransactionModel>,
)

View file

@ -616,8 +616,8 @@ internal class SwapInteractorImpl @Inject constructor(
) {
swapTransactionRepository.storeTransaction(
userWalletId = UserWalletId(userWalletManager.getWalletId()),
fromCryptoCurrencyId = currencyToSend.currency.id,
toCryptoCurrencyId = currencyToGet.currency.id,
fromCryptoCurrency = currencyToSend.currency,
toCryptoCurrency = currencyToGet.currency,
transaction = SavedSwapTransactionModel(
txId = swapDataModel.transaction.txId,
provider = swapProvider,

View file

@ -1,5 +1,6 @@
package com.tangem.feature.swap.domain
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
@ -11,20 +12,21 @@ interface SwapTransactionRepository {
suspend fun storeTransaction(
userWalletId: UserWalletId,
fromCryptoCurrencyId: CryptoCurrency.ID,
toCryptoCurrencyId: CryptoCurrency.ID,
fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency,
transaction: SavedSwapTransactionModel,
)
suspend fun getTransactions(
userWalletId: UserWalletId,
cryptoCurrencyId: CryptoCurrency.ID,
scanResponse: ScanResponse,
): Flow<List<SavedSwapTransactionListModel>?>
suspend fun removeTransaction(
userWalletId: UserWalletId,
fromCryptoCurrencyId: CryptoCurrency.ID,
toCryptoCurrencyId: CryptoCurrency.ID,
fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency,
txId: String,
)

View file

@ -19,14 +19,12 @@ internal data class SwapTransactionsState(
val hasFailed: Boolean,
val statuses: ImmutableList<ExchangeStatusState>,
val notification: ExchangeStatusNotifications? = null,
val toCryptoCurrencyId: CryptoCurrency.ID,
val toCryptoCurrency: CryptoCurrency,
val toCryptoAmount: String,
val toCryptoSymbol: String,
val toFiatAmount: String,
val toCurrencyIcon: TokenIconState,
val fromCryptoCurrencyId: CryptoCurrency.ID,
val fromCryptoCurrency: CryptoCurrency,
val fromCryptoAmount: String,
val fromCryptoSymbol: String,
val fromFiatAmount: String,
val fromCurrencyIcon: TokenIconState,
val showProviderLink: Boolean,

View file

@ -9,7 +9,7 @@ import com.tangem.core.ui.utils.toDateFormat
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.Quote
import com.tangem.domain.tokens.models.analytics.TokenExchangeAnalyticsEvent
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
@ -42,70 +42,70 @@ internal class TokenDetailsSwapTransactionsStateConverter(
fun convert(
savedTransactions: List<SavedSwapTransactionListModel>,
cryptoStatusList: List<CryptoCurrencyStatus>,
quotes: Set<Quote>,
): PersistentList<SwapTransactionsState> {
val result = mutableListOf<SwapTransactionsState>()
savedTransactions.forEach { swapCurrency ->
val firstStatus = cryptoStatusList.first { it.currency.id.value == swapCurrency.fromCryptoCurrencyId }
val secondStatus = cryptoStatusList.first { it.currency.id.value == swapCurrency.toCryptoCurrencyId }
savedTransactions
.forEach { swapCurrency ->
val toCryptoCurrency = swapCurrency.toCryptoCurrency
val fromCryptoCurrency = swapCurrency.fromCryptoCurrency
val (fromCurrency, toCurrency) = if (swapCurrency.fromCryptoCurrencyId == firstStatus.currency.id.value) {
firstStatus to secondStatus
} else {
secondStatus to firstStatus
swapCurrency.transactions.forEach { transaction ->
val toAmount = transaction.toCryptoAmount
val fromAmount = transaction.fromCryptoAmount
val toFiatAmount = quotes.firstOrNull {
it.rawCurrencyId == swapCurrency.fromCryptoCurrency.id.rawCurrencyId
}?.fiatRate?.multiply(toAmount)
val fromFiatAmount = quotes.firstOrNull {
it.rawCurrencyId == swapCurrency.fromCryptoCurrency.id.rawCurrencyId
}?.fiatRate?.multiply(fromAmount)
val timestamp = transaction.timestamp
val notifications =
getNotification(transaction.status?.status, transaction.status?.txExternalUrl)
val showProviderLink = getShowProviderLink(notifications, transaction.status)
result.add(
SwapTransactionsState(
txId = transaction.txId,
provider = transaction.provider,
txUrl = transaction.status?.txExternalUrl,
timestamp = TextReference.Str(
"${timestamp.toDateFormat()}, ${timestamp.toTimeFormat()}",
),
fiatSymbol = appCurrency.symbol,
statuses = getStatuses(transaction.status?.status),
hasFailed = transaction.status?.status == ExchangeStatus.Failed,
activeStatus = transaction.status?.status,
notification = getNotification(
transaction.status?.status,
transaction.status?.txExternalUrl,
),
toCryptoCurrency = toCryptoCurrency,
toCryptoAmount = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = toAmount,
cryptoCurrency = toCryptoCurrency,
),
toFiatAmount = getFiatAmount(toFiatAmount),
toCurrencyIcon = iconStateConverter.convert(toCryptoCurrency),
fromCryptoCurrency = fromCryptoCurrency,
fromCryptoAmount = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = fromAmount,
cryptoCurrency = fromCryptoCurrency,
),
fromFiatAmount = getFiatAmount(fromFiatAmount),
fromCurrencyIcon = iconStateConverter.convert(fromCryptoCurrency),
showProviderLink = showProviderLink,
onClick = { clickIntents.onSwapTransactionClick(transaction.txId) },
onGoToProviderClick = { url ->
analyticsEventsHandlerProvider().send(
TokenExchangeAnalyticsEvent.GoToProviderStatus(cryptoCurrency.symbol),
)
clickIntents.onGoToProviderClick(url = url)
},
),
)
}
}
swapCurrency.transactions.forEach { transaction ->
val toAmount = transaction.toCryptoAmount
val fromAmount = transaction.fromCryptoAmount
val toFiatAmount = toAmount.multiply(toCurrency.value.fiatRate)
val fromFiatAmount = fromAmount.multiply(fromCurrency.value.fiatRate)
val timestamp = transaction.timestamp
val notifications = getNotification(transaction.status?.status, transaction.status?.txExternalUrl)
val showProviderLink = getShowProviderLink(notifications, transaction.status)
result.add(
SwapTransactionsState(
txId = transaction.txId,
provider = transaction.provider,
txUrl = transaction.status?.txExternalUrl,
timestamp = TextReference.Str("${timestamp.toDateFormat()}, ${timestamp.toTimeFormat()}"),
fiatSymbol = appCurrency.symbol,
statuses = getStatuses(transaction.status?.status),
hasFailed = transaction.status?.status == ExchangeStatus.Failed,
activeStatus = transaction.status?.status,
notification = getNotification(
transaction.status?.status,
transaction.status?.txExternalUrl,
),
toCryptoCurrencyId = toCurrency.currency.id,
toCryptoAmount = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = toAmount,
cryptoCurrency = toCurrency.currency,
),
toCryptoSymbol = toCurrency.currency.symbol,
toFiatAmount = getFiatAmount(toFiatAmount),
toCurrencyIcon = iconStateConverter.convert(toCurrency),
fromCryptoCurrencyId = fromCurrency.currency.id,
fromCryptoAmount = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = fromAmount,
cryptoCurrency = fromCurrency.currency,
),
fromCryptoSymbol = fromCurrency.currency.symbol,
fromFiatAmount = getFiatAmount(fromFiatAmount),
fromCurrencyIcon = iconStateConverter.convert(fromCurrency),
showProviderLink = showProviderLink,
onClick = { clickIntents.onSwapTransactionClick(transaction.txId) },
onGoToProviderClick = { url ->
analyticsEventsHandlerProvider().send(
TokenExchangeAnalyticsEvent.GoToProviderStatus(cryptoCurrency.symbol),
)
clickIntents.onGoToProviderClick(url = url)
},
),
)
}
}
return result.toPersistentList()
}
@ -124,7 +124,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
)
}
private fun getFiatAmount(toFiatAmount: BigDecimal): String {
private fun getFiatAmount(toFiatAmount: BigDecimal?): String {
return BigDecimalFormatter.formatFiatAmount(
fiatAmount = toFiatAmount,
fiatCurrencyCode = appCurrency.code,

View file

@ -61,9 +61,9 @@ private fun ExchangeStatusBottomSheetContent(content: ExchangeStatusBottomSheetC
fromTokenIconState = config.fromCurrencyIcon,
toTokenIconState = config.toCurrencyIcon,
fromCryptoAmount = TextReference.Str(config.fromCryptoAmount),
fromCryptoSymbol = config.fromCryptoSymbol,
fromCryptoSymbol = config.fromCryptoCurrency.symbol,
toCryptoAmount = TextReference.Str(config.toCryptoAmount),
toCryptoSymbol = config.toCryptoSymbol,
toCryptoSymbol = config.toCryptoCurrency.symbol,
fromFiatAmount = TextReference.Str(config.fromFiatAmount),
toFiatAmount = TextReference.Str(config.toFiatAmount),
)

View file

@ -55,8 +55,8 @@ internal fun LazyListScope.swapTransactionsItems(
fromTokenIconState = item.fromCurrencyIcon,
toTokenIconState = item.toCurrencyIcon,
fromAmount = item.fromCryptoAmount,
fromSymbol = item.fromCryptoSymbol,
toSymbol = item.toCryptoSymbol,
fromSymbol = item.fromCryptoCurrency.symbol,
toSymbol = item.toCryptoCurrency.symbol,
onClick = item.onClick,
infoIconRes = iconRes,
infoIconTint = tint,

View file

@ -1,15 +1,14 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels
import arrow.core.getOrElse
import com.tangem.common.Provider
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.datasource.local.swaptx.ExchangeAnalyticsStatus
import com.tangem.datasource.local.swaptx.SwapTransactionStatusStore
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.Quote
import com.tangem.domain.tokens.models.analytics.TokenExchangeAnalyticsEvent
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.feature.swap.domain.SwapTransactionRepository
@ -27,17 +26,18 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
@Suppress("LongParameterList")
internal class ExchangeStatusFactory(
private val swapTransactionRepository: SwapTransactionRepository,
private val swapRepository: SwapRepository,
private val quotesRepository: QuotesRepository,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
private val swapTransactionStatusStore: SwapTransactionStatusStore,
private val dispatchers: CoroutineDispatcherProvider,
private val clickIntents: TokenDetailsClickIntents,
@ -57,14 +57,27 @@ internal class ExchangeStatusFactory(
)
}
suspend operator fun invoke() = combine(
flow = swapTransactionRepository.getTransactions(userWalletId, cryptoCurrency.id),
flow2 = getWalletCryptoCurrencies().conflate(),
) { savedTransactions, cryptoCurrenciesStatusList ->
getExchangeStatusState(
savedTransactions = savedTransactions,
cryptoCurrencyStatusList = cryptoCurrenciesStatusList,
suspend operator fun invoke(): Flow<PersistentList<SwapTransactionsState>> {
val selectedWallet = getSelectedWalletSyncUseCase().fold(
ifLeft = { return emptyFlow() },
ifRight = { it },
)
return swapTransactionRepository.getTransactions(
userWalletId = userWalletId,
cryptoCurrencyId = cryptoCurrency.id,
scanResponse = selectedWallet.scanResponse,
).conflate()
.map { savedTransactions ->
val quotes = savedTransactions
?.flatMap { setOf(it.fromCryptoCurrency.id, it.toCryptoCurrency.id) }
?.let { quotesRepository.getQuotesSync(it.toSet(), true) }
?: emptySet()
getExchangeStatusState(
savedTransactions = savedTransactions,
quotes = quotes,
)
}
}
suspend fun removeTransactionOnBottomSheetClosed(): TokenDetailsState {
@ -75,8 +88,8 @@ internal class ExchangeStatusFactory(
return if (selectedTx.activeStatus.isTerminal()) {
swapTransactionRepository.removeTransaction(
userWalletId = userWalletId,
fromCryptoCurrencyId = selectedTx.fromCryptoCurrencyId,
toCryptoCurrencyId = selectedTx.toCryptoCurrencyId,
fromCryptoCurrency = selectedTx.fromCryptoCurrency,
toCryptoCurrency = selectedTx.toCryptoCurrency,
txId = selectedTx.txId,
)
val filteredTxs = state.swapTxs
@ -88,19 +101,6 @@ internal class ExchangeStatusFactory(
}
}
private fun getWalletCryptoCurrencies() = flow {
val selectedWallet = getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = { it },
)
requireNotNull(selectedWallet) { "No selected wallet" }
val cryptoCurrenciesList = getMultiCryptoCurrencyStatusUseCase(selectedWallet.walletId)
.getOrElse { emptyList() }
emit(cryptoCurrenciesList)
}
suspend fun updateSwapTxStatuses(swapTxList: PersistentList<SwapTransactionsState>) = withContext(dispatchers.io) {
swapTxList.map { tx ->
async {
@ -144,15 +144,15 @@ internal class ExchangeStatusFactory(
private fun getExchangeStatusState(
savedTransactions: List<SavedSwapTransactionListModel>?,
cryptoCurrencyStatusList: List<CryptoCurrencyStatus>,
quotes: Set<Quote>,
): PersistentList<SwapTransactionsState> {
if (savedTransactions == null || cryptoCurrencyStatusList.isEmpty()) {
if (savedTransactions == null) {
return persistentListOf()
}
return swapTransactionsStateConverter.convert(
savedTransactions = savedTransactions,
cryptoStatusList = cryptoCurrencyStatusList,
quotes = quotes,
)
}

View file

@ -30,6 +30,7 @@ import com.tangem.domain.tokens.models.analytics.TokenExchangeAnalyticsEvent
import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.tokens.models.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.tokens.models.analytics.TokenSwapPromoAnalyticsEvent
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
@ -76,10 +77,10 @@ internal class TokenDetailsViewModel @Inject constructor(
private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase,
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
private val shouldShowSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase,
private val swapRepository: SwapRepository,
private val swapTransactionRepository: SwapTransactionRepository,
private val quotesRepository: QuotesRepository,
private val swapTransactionStatusStore: SwapTransactionStatusStore,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val reduxStateHolder: ReduxStateHolder,
@ -118,8 +119,8 @@ internal class TokenDetailsViewModel @Inject constructor(
ExchangeStatusFactory(
swapTransactionRepository = swapTransactionRepository,
swapRepository = swapRepository,
quotesRepository = quotesRepository,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
swapTransactionStatusStore = swapTransactionStatusStore,
dispatchers = dispatchers,
clickIntents = this,