Updated on 2026-08-14
This commit is contained in:
commit
bb5275e21e
7 changed files with 61 additions and 153 deletions
|
|
@ -9,9 +9,9 @@ import java.math.BigDecimal
|
|||
|
||||
interface SwapInteractor {
|
||||
|
||||
suspend fun getTokensDataState(currency: Currency): TokensDataStateExpress
|
||||
suspend fun getTokensDataState(currency: CryptoCurrency): TokensDataStateExpress
|
||||
|
||||
fun initDerivationPathAndNetwork(derivationPath: String?, network: Network?)
|
||||
fun initDerivationPathAndNetwork(derivationPath: String?, network: Network)
|
||||
|
||||
/**
|
||||
* Init tokens to swap, load tokens list available to swap for given network
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.feature.swap.domain
|
||||
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
|
|
@ -52,7 +52,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
private var derivationPath: String? = null
|
||||
private var network: Network? = null
|
||||
|
||||
override suspend fun getTokensDataState(currency: Currency): TokensDataStateExpress {
|
||||
override suspend fun getTokensDataState(currency: CryptoCurrency): TokensDataStateExpress {
|
||||
val selectedWallet = getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = { null },
|
||||
ifRight = { it },
|
||||
|
|
@ -65,36 +65,32 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
.getOrElse { emptyList() }
|
||||
|
||||
val walletCurrencyStatusesExceptInitial = walletCurrencyStatuses.filter {
|
||||
it.currency.network.backendId != currency.networkId ||
|
||||
it.currency.network.backendId != currency.network.backendId ||
|
||||
it.currency.getContractAddress() != currency.getContractAddress()
|
||||
}
|
||||
|
||||
val pairsLeast = getPairs(
|
||||
initialCurrency = LeastTokenInfo(
|
||||
contractAddress = (currency as? Currency.NonNativeToken)?.contractAddress ?: "0",
|
||||
network = currency.networkId,
|
||||
contractAddress = (currency as? CryptoCurrency.Token)?.contractAddress ?: "0",
|
||||
network = currency.network.backendId,
|
||||
),
|
||||
currenciesList = walletCurrencyStatusesExceptInitial.map { it.currency },
|
||||
)
|
||||
|
||||
val initialCryptoCurrency = mapLegacyCurrencyToCryptoCurrency(currency, walletCurrencyStatuses)
|
||||
?: error("Initial crypto currency must not be null")
|
||||
|
||||
return TokensDataStateExpress(
|
||||
initialCryptoCurrency = initialCryptoCurrency,
|
||||
fromGroup = getToCurrenciesGroup(
|
||||
currency = initialCryptoCurrency,
|
||||
currency = currency,
|
||||
leastPairs = pairsLeast,
|
||||
cryptoCurrenciesList = walletCurrencyStatusesExceptInitial,
|
||||
tokenInfoForFilter = { it.from },
|
||||
tokenInfoForAvailable = { it.to }
|
||||
tokenInfoForAvailable = { it.to },
|
||||
),
|
||||
toGroup = getToCurrenciesGroup(
|
||||
currency = initialCryptoCurrency,
|
||||
currency = currency,
|
||||
leastPairs = pairsLeast,
|
||||
cryptoCurrenciesList = walletCurrencyStatusesExceptInitial,
|
||||
tokenInfoForFilter = { it.to },
|
||||
tokenInfoForAvailable = { it.from }
|
||||
tokenInfoForAvailable = { it.from },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -107,8 +103,8 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
tokenInfoForAvailable: (SwapPairLeast) -> LeastTokenInfo,
|
||||
): CurrenciesGroup {
|
||||
val filteredPairs = leastPairs.filter {
|
||||
tokenInfoForFilter(it).contractAddress == currency.getContractAddress()
|
||||
&& tokenInfoForFilter(it).network == currency.network.backendId
|
||||
tokenInfoForFilter(it).contractAddress == currency.getContractAddress() &&
|
||||
tokenInfoForFilter(it).network == currency.network.backendId
|
||||
}
|
||||
|
||||
val availableCryptoCurrencies = filteredPairs.mapNotNull { pair ->
|
||||
|
|
@ -125,17 +121,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun mapLegacyCurrencyToCryptoCurrency(
|
||||
currency: Currency,
|
||||
currencies: List<CryptoCurrencyStatus>,
|
||||
): CryptoCurrency? {
|
||||
return currencies.map { it.currency }
|
||||
.find {
|
||||
it.network.backendId == currency.networkId &&
|
||||
it.getContractAddress() == currency.getContractAddress()
|
||||
}
|
||||
}
|
||||
|
||||
private fun findCryptoCurrencyStatusByLeastInfo(
|
||||
leastTokenInfo: LeastTokenInfo,
|
||||
cryptoCurrencyStatusesList: List<CryptoCurrencyStatus>,
|
||||
|
|
@ -165,7 +150,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
|
||||
@Deprecated("used in old swap mechanism")
|
||||
override fun initDerivationPathAndNetwork(derivationPath: String?, network: Network?) {
|
||||
override fun initDerivationPathAndNetwork(derivationPath: String?, network: Network) {
|
||||
this.derivationPath = derivationPath
|
||||
this.network = network
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
import com.tangem.feature.swap.domain.models.domain.CryptoCurrencySwapInfo
|
||||
|
||||
data class TokensDataStateExpress(
|
||||
val initialCryptoCurrency: CryptoCurrency,
|
||||
val fromGroup: CurrenciesGroup,
|
||||
val toGroup: CurrenciesGroup,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -82,7 +82,5 @@ class SwapFragment : ComposeFragment() {
|
|||
|
||||
companion object {
|
||||
const val CURRENCY_BUNDLE_KEY = "swap_currency"
|
||||
const val DERIVATION_PATH = "DERIVATION_STYLE"
|
||||
const val NETWORK = "NETWORK"
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,7 @@ import com.tangem.core.ui.extensions.wrappedList
|
|||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.feature.swap.converters.TokensDataConverter
|
||||
import com.tangem.feature.swap.domain.models.DataError
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.domain.NetworkInfo
|
||||
import com.tangem.feature.swap.domain.models.domain.isNonNative
|
||||
import com.tangem.feature.swap.domain.models.formatToUIRepresentation
|
||||
import com.tangem.feature.swap.domain.models.ui.*
|
||||
import com.tangem.feature.swap.models.*
|
||||
|
|
@ -34,19 +32,19 @@ internal class StateBuilder(val actions: UiActions, val isBalanceHiddenProvider:
|
|||
isBalanceHiddenProvider = isBalanceHiddenProvider,
|
||||
)
|
||||
|
||||
fun createInitialLoadingState(initialCurrency: Currency, networkInfo: NetworkInfo): SwapStateHolder {
|
||||
fun createInitialLoadingState(initialCurrency: CryptoCurrency, networkInfo: NetworkInfo): SwapStateHolder {
|
||||
return SwapStateHolder(
|
||||
networkId = initialCurrency.networkId,
|
||||
networkId = initialCurrency.network.backendId,
|
||||
blockchainId = networkInfo.blockchainId,
|
||||
sendCardData = SwapCardData(
|
||||
type = TransactionCardType.SendCard(actions.onAmountChanged, actions.onAmountSelected),
|
||||
amountEquivalent = null,
|
||||
amountTextFieldValue = null,
|
||||
tokenIconUrl = initialCurrency.logoUrl,
|
||||
tokenIconUrl = initialCurrency.iconUrl,
|
||||
tokenCurrency = initialCurrency.symbol,
|
||||
coinId = initialCurrency.id,
|
||||
coinId = null,
|
||||
canSelectAnotherToken = false,
|
||||
isNotNativeToken = initialCurrency.isNonNative(),
|
||||
isNotNativeToken = initialCurrency is CryptoCurrency.Token,
|
||||
balance = "",
|
||||
isBalanceHidden = true,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -9,11 +9,9 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.core.ui.utils.InputNumberFormatter
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.feature.swap.analytics.SwapEvents
|
||||
import com.tangem.feature.swap.domain.BlockchainInteractor
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.domain.PermissionOptions
|
||||
import com.tangem.feature.swap.domain.models.formatToUIRepresentation
|
||||
import com.tangem.feature.swap.domain.models.ui.*
|
||||
|
|
@ -52,17 +50,11 @@ internal class SwapViewModel @Inject constructor(
|
|||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(), DefaultLifecycleObserver {
|
||||
|
||||
// try to get rid of this and use only CryptoCurrency
|
||||
private val currency = Json.decodeFromString<Currency>(
|
||||
private val initialCryptoCurrency = Json.decodeFromString<CryptoCurrency>(
|
||||
savedStateHandle[SwapFragment.CURRENCY_BUNDLE_KEY]
|
||||
?: error("no expected parameter Currency found"),
|
||||
)
|
||||
|
||||
private var cryptoCurrency: CryptoCurrency by Delegates.notNull()
|
||||
|
||||
private val derivationPath = savedStateHandle.get<String>(SwapFragment.DERIVATION_PATH)
|
||||
private val network = savedStateHandle.get<Network>(SwapFragment.NETWORK)
|
||||
|
||||
private var isBalanceHidden = true
|
||||
|
||||
private val stateBuilder = StateBuilder(
|
||||
|
|
@ -75,12 +67,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
private val amountDebouncer = Debouncer()
|
||||
private val singleTaskScheduler = SingleTaskScheduler<SwapState>()
|
||||
|
||||
private var dataState by mutableStateOf(SwapProcessDataState(networkId = currency.networkId))
|
||||
private var dataState by mutableStateOf(SwapProcessDataState(networkId = initialCryptoCurrency.network.backendId))
|
||||
|
||||
var uiState: SwapStateHolder by mutableStateOf(
|
||||
stateBuilder.createInitialLoadingState(
|
||||
initialCurrency = currency,
|
||||
networkInfo = blockchainInteractor.getBlockchainInfo(currency.networkId),
|
||||
initialCurrency = initialCryptoCurrency,
|
||||
networkInfo = blockchainInteractor.getBlockchainInfo(initialCryptoCurrency.network.backendId),
|
||||
),
|
||||
)
|
||||
private set
|
||||
|
|
@ -93,8 +85,11 @@ internal class SwapViewModel @Inject constructor(
|
|||
get() = swapRouter.currentScreen
|
||||
|
||||
init {
|
||||
swapInteractor.initDerivationPathAndNetwork(derivationPath, network)
|
||||
initTokens(currency)
|
||||
swapInteractor.initDerivationPathAndNetwork(
|
||||
derivationPath = initialCryptoCurrency.network.derivationPath.value,
|
||||
network = initialCryptoCurrency.network,
|
||||
)
|
||||
initTokens(initialCryptoCurrency)
|
||||
}
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
|
|
@ -115,7 +110,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onScreenOpened() {
|
||||
analyticsEventHandler.send(SwapEvents.SwapScreenOpened(currency.symbol))
|
||||
analyticsEventHandler.send(SwapEvents.SwapScreenOpened(initialCryptoCurrency.symbol))
|
||||
}
|
||||
|
||||
fun setRouter(router: SwapRouter) {
|
||||
|
|
@ -133,21 +128,20 @@ internal class SwapViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun initTokens(currency: Currency) {
|
||||
private fun initTokens(currency: CryptoCurrency) {
|
||||
// new flow
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
runCatching(dispatchers.io) {
|
||||
swapInteractor.getTokensDataState(currency)
|
||||
swapInteractor.getTokensDataState(initialCryptoCurrency)
|
||||
}.onSuccess { state ->
|
||||
dataState = dataState.copy(
|
||||
fromCryptoCurrency = state.initialCryptoCurrency,
|
||||
fromCryptoCurrency = initialCryptoCurrency,
|
||||
toCryptoCurrency = state.toGroup.available.first().currencyStatus.currency
|
||||
)
|
||||
|
||||
cryptoCurrency = state.initialCryptoCurrency
|
||||
// updateTokensState(dataState = state.foundTokensState)
|
||||
startLoadingQuotes(
|
||||
fromToken = state.initialCryptoCurrency,
|
||||
fromToken = initialCryptoCurrency,
|
||||
toToken = state.toGroup.available.first().currencyStatus.currency,
|
||||
amount = lastAmount.value,
|
||||
)
|
||||
|
|
@ -157,39 +151,39 @@ internal class SwapViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
// old flow
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
runCatching(dispatchers.io) {
|
||||
swapInteractor.initTokensToSwap(currency)
|
||||
}
|
||||
.onSuccess { state ->
|
||||
// dataState = dataState.copy(
|
||||
// fromCurrency = state.preselectTokens.fromToken,
|
||||
// toCurrency = state.preselectTokens.toToken,
|
||||
// )
|
||||
// updateTokensState(dataState = state.foundTokensState)
|
||||
// startLoadingQuotes(
|
||||
// fromToken = state.preselectTokens.fromToken,
|
||||
// toToken = state.preselectTokens.toToken,
|
||||
// amount = lastAmount.value,
|
||||
// )
|
||||
}
|
||||
.onFailure {
|
||||
Timber.tag(loggingTag).e(it)
|
||||
}
|
||||
}
|
||||
// viewModelScope.launch(dispatchers.main) {
|
||||
// runCatching(dispatchers.io) {
|
||||
// swapInteractor.initTokensToSwap(currency)
|
||||
// }
|
||||
// .onSuccess { state ->
|
||||
// // dataState = dataState.copy(
|
||||
// // fromCurrency = state.preselectTokens.fromToken,
|
||||
// // toCurrency = state.preselectTokens.toToken,
|
||||
// // )
|
||||
// // updateTokensState(dataState = state.foundTokensState)
|
||||
// // startLoadingQuotes(
|
||||
// // fromToken = state.preselectTokens.fromToken,
|
||||
// // toToken = state.preselectTokens.toToken,
|
||||
// // amount = lastAmount.value,
|
||||
// // )
|
||||
// }
|
||||
// .onFailure {
|
||||
// Timber.tag(loggingTag).e(it)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private fun updateTokensState(dataState: FoundTokensStateExpress) {
|
||||
uiState = stateBuilder.addTokensToState(
|
||||
uiState = uiState,
|
||||
dataState = dataState,
|
||||
networkInfo = blockchainInteractor.getBlockchainInfo(currency.networkId),
|
||||
networkInfo = blockchainInteractor.getBlockchainInfo(initialCryptoCurrency.network.backendId),
|
||||
)
|
||||
}
|
||||
|
||||
private fun startLoadingQuotes(fromToken: CryptoCurrency, toToken: CryptoCurrency, amount: String) {
|
||||
singleTaskScheduler.cancelTask()
|
||||
uiState = stateBuilder.createQuotesLoadingState(uiState, fromToken, toToken, cryptoCurrency.id.value)
|
||||
uiState = stateBuilder.createQuotesLoadingState(uiState, fromToken, toToken, initialCryptoCurrency.id.value)
|
||||
singleTaskScheduler.scheduleTask(
|
||||
viewModelScope,
|
||||
loadQuotesTask(
|
||||
|
|
@ -395,9 +389,9 @@ internal class SwapViewModel @Inject constructor(
|
|||
val toToken: CryptoCurrency
|
||||
if (isOrderReversed) {
|
||||
fromToken = foundToken
|
||||
toToken = cryptoCurrency
|
||||
toToken = initialCryptoCurrency
|
||||
} else {
|
||||
fromToken = cryptoCurrency
|
||||
fromToken = initialCryptoCurrency
|
||||
toToken = foundToken
|
||||
}
|
||||
dataState = dataState.copy(
|
||||
|
|
@ -445,7 +439,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
|
||||
private fun onMaxAmountClicked() {
|
||||
dataState.fromCryptoCurrency?.let {
|
||||
val balance = swapInteractor.getTokenBalance(cryptoCurrency.network.id.value, it)
|
||||
val balance = swapInteractor.getTokenBalance(initialCryptoCurrency.network.id.value, it)
|
||||
onAmountChanged(balance.formatToUIRepresentation())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue