diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt index 6509d4baf1..1bfb7c230a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt @@ -20,6 +20,13 @@ class CryptoCurrencyToIconStateConverter : Converter 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, diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt index ef55915ce2..fde4c4be2e 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt @@ -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, diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/UserTokensResponseFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/UserTokensResponseFactory.kt index 6f752af1a6..7e75db2896 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/UserTokensResponseFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/UserTokensResponseFactory.kt @@ -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, diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt index f617305f17..3499d36f4c 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt @@ -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? = mutablePreferences.getObjectList( + val savedTransactions: List? = 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?> { val txStatuses = appPreferencesStore.getObjectMap( key = PreferencesKeys.SWAP_TRANSACTIONS_STATUSES_KEY, ) - return appPreferencesStore.getObjectList( + return appPreferencesStore.getObjectList( 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? = mutablePreferences.getObjectList( + val savedList: List? = 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.updateList( + private fun List.updateList( userWalletId: UserWalletId, - fromCryptoCurrencyId: CryptoCurrency.ID, - toCryptoCurrencyId: CryptoCurrency.ID, + fromCryptoCurrency: CryptoCurrency, + toCryptoCurrency: CryptoCurrency, transactions: List, - ): List { + ): List { 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, ) }, ) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt new file mode 100644 index 0000000000..8e41921960 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt @@ -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 { + + 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, + ): 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, + ) = SavedSwapTransactionListModelInner( + userWalletId = userWalletId.stringValue, + fromCryptoCurrencyId = fromCryptoCurrency.id.value, + toCryptoCurrencyId = toCryptoCurrency.id.value, + fromTokensResponse = userTokensResponseFactory.createResponseToken(fromCryptoCurrency), + toTokensResponse = userTokensResponseFactory.createResponseToken(toCryptoCurrency), + transactions = tokenTransactions, + ) +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt index f48ab71c3a..95b8469b2a 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt @@ -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 diff --git a/features/swap/domain/build.gradle.kts b/features/swap/domain/build.gradle.kts index 5fa5dfec86..762f7f0252 100644 --- a/features/swap/domain/build.gradle.kts +++ b/features/swap/domain/build.gradle.kts @@ -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) diff --git a/features/swap/domain/models/build.gradle.kts b/features/swap/domain/models/build.gradle.kts index 96958add9b..2ec7133686 100644 --- a/features/swap/domain/models/build.gradle.kts +++ b/features/swap/domain/models/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { /** Core modules */ implementation(projects.core.utils) + implementation(projects.core.datasource) /** Other Libraries **/ implementation(deps.kotlin.serialization) diff --git a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedSwapTransactionListModel.kt b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedSwapTransactionListModel.kt index f2e6a4d139..3eb907948a 100644 --- a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedSwapTransactionListModel.kt +++ b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedSwapTransactionListModel.kt @@ -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, +) + +/** + * 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, ) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 38f55b3561..c32ea0aa31 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -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, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt index e00dadb2a9..f02a93f2ab 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt @@ -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?> suspend fun removeTransaction( userWalletId: UserWalletId, - fromCryptoCurrencyId: CryptoCurrency.ID, - toCryptoCurrencyId: CryptoCurrency.ID, + fromCryptoCurrency: CryptoCurrency, + toCryptoCurrency: CryptoCurrency, txId: String, ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt index c1e0f67210..9b9991a141 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt @@ -19,14 +19,12 @@ internal data class SwapTransactionsState( val hasFailed: Boolean, val statuses: ImmutableList, 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, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt index c5069303c7..a35684c08f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt @@ -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, - cryptoStatusList: List, + quotes: Set, ): PersistentList { val result = mutableListOf() - 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, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt index da9113487a..2583f8e384 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt @@ -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), ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt index 94c1d12187..53e398e71f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt @@ -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, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt index ffb90e01de..f566331795 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/ExchangeStatusFactory.kt @@ -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> { + 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) = withContext(dispatchers.io) { swapTxList.map { tx -> async { @@ -144,15 +144,15 @@ internal class ExchangeStatusFactory( private fun getExchangeStatusState( savedTransactions: List?, - cryptoCurrencyStatusList: List, + quotes: Set, ): PersistentList { - if (savedTransactions == null || cryptoCurrencyStatusList.isEmpty()) { + if (savedTransactions == null) { return persistentListOf() } return swapTransactionsStateConverter.convert( savedTransactions = savedTransactions, - cryptoStatusList = cryptoCurrencyStatusList, + quotes = quotes, ) } 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 b2d4ba321e..fd2d63a74c 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 @@ -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,