Updated on 2026-08-14
This commit is contained in:
parent
fdc485fbca
commit
a7a4d5733f
1 changed files with 69 additions and 32 deletions
|
|
@ -38,6 +38,7 @@ import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
|||
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCryptoCurrencyStatus
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
|
|
@ -61,6 +62,7 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.promo.ShouldShowStoriesUseCase
|
||||
import com.tangem.domain.promo.models.StoryContentIds
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
|
|
@ -68,8 +70,6 @@ import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
|||
import com.tangem.domain.tangempay.GetTangemPayCurrencyStatusUseCase
|
||||
import com.tangem.domain.tangempay.GetTangemPayCustomerIdUseCase
|
||||
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
||||
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.promo.ShouldShowStoriesUseCase
|
||||
import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
|
|
@ -229,7 +229,7 @@ internal class SwapModel @Inject constructor(
|
|||
val feeSelectorRepository = FeeSelectorRepository()
|
||||
|
||||
// shows currency order (direct - swap initial to selected, reversed = selected to initial)
|
||||
private var isOrderReversed by mutableStateOf(false)
|
||||
private val isOrderReversed = MutableStateFlow(value = params.isInitialReverseOrder)
|
||||
private val lastAmount = mutableStateOf(INITIAL_AMOUNT)
|
||||
private val lastReducedBalanceBy = mutableStateOf(BigDecimal.ZERO)
|
||||
private val swapRouter: SwapRouter = SwapRouter(router = router)
|
||||
|
|
@ -538,20 +538,22 @@ internal class SwapModel @Inject constructor(
|
|||
selectedAccountCurrency?.status to selectedAccountCurrency?.account
|
||||
}
|
||||
|
||||
applyInitialTokenChoice(
|
||||
val isApplied = applyInitialTokenChoice(
|
||||
state = state,
|
||||
selectedCurrency = selectedCurrency,
|
||||
selectedAccount = selectedAccount,
|
||||
isReverseFromTo = isReverseFromTo,
|
||||
)
|
||||
|
||||
val fromCryptoCurrency = if (isOrderReversed) {
|
||||
dataState.toCryptoCurrency
|
||||
} else {
|
||||
dataState.fromCryptoCurrency
|
||||
}
|
||||
// assume that fromCryptoCurrency selected according reverse flag,
|
||||
// so update fee paid currency according to it
|
||||
val fromCryptoCurrency = dataState.fromCryptoCurrency
|
||||
|
||||
if (fromCryptoCurrency != null) {
|
||||
if (isApplied && fromCryptoCurrency != null) {
|
||||
Timber.i(
|
||||
"updateFeePaidCryptoCurrencyFor: id = ${fromCryptoCurrency.currency.id}, " +
|
||||
"isReverseFromTo: $isReverseFromTo",
|
||||
)
|
||||
updateFeePaidCryptoCurrencyFor(fromCryptoCurrency)
|
||||
} else {
|
||||
Timber.e("updateFeePaidCryptoCurrencyFor failed: fromCryptoCurrency is null")
|
||||
|
|
@ -594,7 +596,7 @@ internal class SwapModel @Inject constructor(
|
|||
state = state,
|
||||
selectedCurrency = addedToken,
|
||||
selectedAccount = addedAccount,
|
||||
isReverseFromTo = isOrderReversed,
|
||||
isReverseFromTo = isOrderReversed.value,
|
||||
)
|
||||
|
||||
subscribeToCoinBalanceUpdatesIfNeeded()
|
||||
|
|
@ -624,29 +626,34 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if tokens are selected and dataState is updated,
|
||||
* false if selected token is null and alert is shown with error message
|
||||
*/
|
||||
private fun applyInitialTokenChoice(
|
||||
state: TokensDataStateExpress,
|
||||
selectedCurrency: CryptoCurrencyStatus?,
|
||||
selectedAccount: Account.CryptoPortfolio?,
|
||||
isReverseFromTo: Boolean,
|
||||
) {
|
||||
): Boolean {
|
||||
// exceptional case
|
||||
if (selectedCurrency == null) {
|
||||
Timber.e("No available tokens to swap for ${initialCurrencyFrom.symbol}")
|
||||
analyticsEventHandler.send(SwapEvents.NoticeNoAvailableTokensToSwap())
|
||||
uiState = stateBuilder.createNoAvailableTokensToSwapState(
|
||||
uiStateHolder = uiState,
|
||||
fromToken = initialFromStatus,
|
||||
)
|
||||
return
|
||||
return false
|
||||
}
|
||||
isOrderReversed = isReverseFromTo
|
||||
val (fromCurrencyStatus, toCurrencyStatus) = if (isOrderReversed) {
|
||||
isOrderReversed.value = isReverseFromTo
|
||||
val (fromCurrencyStatus, toCurrencyStatus) = if (isOrderReversed.value) {
|
||||
selectedCurrency to initialFromStatus
|
||||
} else {
|
||||
initialFromStatus to selectedCurrency
|
||||
}
|
||||
val (fromAccount, toAccount) = if (canUseFromAccountCurrencyStatus) {
|
||||
if (isOrderReversed) {
|
||||
if (isOrderReversed.value) {
|
||||
selectedAccount to requireNotNull(fromAccountCurrencyStatus).account
|
||||
} else {
|
||||
requireNotNull(fromAccountCurrencyStatus).account to selectedAccount
|
||||
|
|
@ -670,7 +677,7 @@ internal class SwapModel @Inject constructor(
|
|||
toAccount = toAccount,
|
||||
)
|
||||
) {
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
startLoadingQuotes(
|
||||
|
|
@ -682,10 +689,11 @@ internal class SwapModel @Inject constructor(
|
|||
reduceBalanceBy = lastReducedBalanceBy.value,
|
||||
toProvidersList = findSwapProviders(fromCurrencyStatus, toCurrencyStatus),
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateTokensState(tokenDataState: TokensDataStateExpress) {
|
||||
val tokensDataState = if (isOrderReversed) tokenDataState.fromGroup else tokenDataState.toGroup
|
||||
val tokensDataState = if (isOrderReversed.value) tokenDataState.fromGroup else tokenDataState.toGroup
|
||||
|
||||
uiState = stateBuilder.addTokensToStateV2(
|
||||
uiState = uiState,
|
||||
|
|
@ -1278,7 +1286,7 @@ internal class SwapModel @Inject constructor(
|
|||
searchQueryState.value = searchQuery
|
||||
|
||||
val tokenDataState = dataState.tokensDataState ?: return@debounce
|
||||
val group = if (isOrderReversed) {
|
||||
val group = if (isOrderReversed.value) {
|
||||
tokenDataState.fromGroup
|
||||
} else {
|
||||
tokenDataState.toGroup
|
||||
|
|
@ -1308,7 +1316,7 @@ internal class SwapModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
val filteredTokenDataState = if (isOrderReversed) {
|
||||
val filteredTokenDataState = if (isOrderReversed.value) {
|
||||
tokenDataState.copy(
|
||||
fromGroup = tokenDataState.fromGroup.copy(
|
||||
available = available,
|
||||
|
|
@ -1355,7 +1363,7 @@ internal class SwapModel @Inject constructor(
|
|||
val fromAccount: Account.CryptoPortfolio?
|
||||
val toToken: CryptoCurrencyStatus
|
||||
val toAccount: Account.CryptoPortfolio?
|
||||
if (isOrderReversed) {
|
||||
if (isOrderReversed.value) {
|
||||
fromToken = foundToken
|
||||
fromAccount = foundAccount
|
||||
toToken = initialFromStatus
|
||||
|
|
@ -1412,6 +1420,10 @@ internal class SwapModel @Inject constructor(
|
|||
return
|
||||
}
|
||||
modelScope.launch {
|
||||
Timber.i(
|
||||
"updateFeePaidCryptoCurrencyFor: id = ${fromToken.currency.id}, " +
|
||||
"isOrderReversed: ${isOrderReversed.value}",
|
||||
)
|
||||
updateFeePaidCryptoCurrencyFor(fromToken)
|
||||
startLoadingQuotes(
|
||||
fromToken = fromToken,
|
||||
|
|
@ -1431,7 +1443,7 @@ internal class SwapModel @Inject constructor(
|
|||
tokens: TokensDataStateExpress,
|
||||
id: String,
|
||||
): Pair<CryptoCurrencyStatus?, Account.CryptoPortfolio?> {
|
||||
val accountCryptoCurrencyStatus = if (isOrderReversed) {
|
||||
val accountCryptoCurrencyStatus = if (isOrderReversed.value) {
|
||||
tokens.fromGroup
|
||||
} else {
|
||||
tokens.toGroup
|
||||
|
|
@ -1463,7 +1475,23 @@ internal class SwapModel @Inject constructor(
|
|||
feePaidCryptoCurrency = getFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyStatus = currencyStatus,
|
||||
).getOrNull() ?: currencyStatus,
|
||||
)
|
||||
.onLeft {
|
||||
Timber.e(
|
||||
"Coin balance: Unable to get fee paid crypto currency status for " +
|
||||
"${currencyStatus.currency.id}",
|
||||
)
|
||||
}
|
||||
.onRight { status ->
|
||||
if (status == null) {
|
||||
Timber.e(
|
||||
"Coin balance: Fee paid crypto currency status is null " +
|
||||
"for ${currencyStatus.currency.id}",
|
||||
)
|
||||
}
|
||||
}
|
||||
.getOrNull()
|
||||
?: currencyStatus,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1509,7 +1537,11 @@ internal class SwapModel @Inject constructor(
|
|||
toCryptoCurrency = newToToken,
|
||||
toAccount = newToAccount,
|
||||
)
|
||||
isOrderReversed = !isOrderReversed
|
||||
isOrderReversed.value = !isOrderReversed.value
|
||||
Timber.i(
|
||||
"updateFeePaidCryptoCurrencyFor: id = ${newFromToken.currency.id}, " +
|
||||
"isOrderReversed: ${isOrderReversed.value}",
|
||||
)
|
||||
updateFeePaidCryptoCurrencyFor(newFromToken)
|
||||
dataState.tokensDataState?.let { tokensDataState ->
|
||||
updateTokensState(tokensDataState)
|
||||
|
|
@ -1946,13 +1978,13 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun findSwapProviders(fromToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus): List<SwapProvider> {
|
||||
val groupToFind = if (isOrderReversed) {
|
||||
val groupToFind = if (isOrderReversed.value) {
|
||||
dataState.tokensDataState?.fromGroup
|
||||
} else {
|
||||
dataState.tokensDataState?.toGroup
|
||||
} ?: return emptyList()
|
||||
|
||||
val idToFind = if (isOrderReversed) {
|
||||
val idToFind = if (isOrderReversed.value) {
|
||||
fromToken.currency.id.value
|
||||
} else {
|
||||
toToken.currency.id.value
|
||||
|
|
@ -1978,8 +2010,8 @@ internal class SwapModel @Inject constructor(
|
|||
fromAccount: Account.CryptoPortfolio?,
|
||||
toAccount: Account.CryptoPortfolio?,
|
||||
): Boolean {
|
||||
val selectedCurrency = if (isOrderReversed) fromToken else toToken
|
||||
if (isTokenAvailableForSwap(state, selectedCurrency, isOrderReversed)) return false
|
||||
val selectedCurrency = if (isOrderReversed.value) fromToken else toToken
|
||||
if (isTokenAvailableForSwap(state, selectedCurrency, isOrderReversed.value)) return false
|
||||
|
||||
analyticsEventHandler.send(
|
||||
SwapEvents.NoticeUnavailableToSwapPair(
|
||||
|
|
@ -2039,13 +2071,13 @@ internal class SwapModel @Inject constructor(
|
|||
val from = dataState.fromCryptoCurrency ?: return false
|
||||
val to = dataState.toCryptoCurrency ?: return false
|
||||
|
||||
val currenciesGroup = if (isOrderReversed) {
|
||||
val currenciesGroup = if (isOrderReversed.value) {
|
||||
dataState.tokensDataState?.toGroup
|
||||
} else {
|
||||
dataState.tokensDataState?.fromGroup
|
||||
} ?: return false
|
||||
|
||||
val chosen = if (isOrderReversed) from else to
|
||||
val chosen = if (isOrderReversed.value) from else to
|
||||
|
||||
return currenciesGroup.accountCurrencyList.flatMap { accountSwapAvailability ->
|
||||
accountSwapAvailability.currencyList.map { accountSwapCurrency ->
|
||||
|
|
@ -2310,7 +2342,10 @@ internal class SwapModel @Inject constructor(
|
|||
val feeStateUM = feeSelectorRepository.state.value as? FeeSelectorUM.Content
|
||||
|
||||
if (feeStateUM == null) {
|
||||
Timber.e("getSelectedFeeState: FeeSelectorUM is not Content: $feeStateUM, returning Legacy state")
|
||||
Timber.e(
|
||||
"getSelectedFeeState: FeeSelectorUM is not Content: ${feeSelectorRepository.state.value}, " +
|
||||
"returning Legacy state",
|
||||
)
|
||||
return TxFeeSealedState.Legacy(
|
||||
txFeeState = TxFeeState.Empty,
|
||||
selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL,
|
||||
|
|
@ -2332,7 +2367,9 @@ internal class SwapModel @Inject constructor(
|
|||
val feeStateUM = feeSelectorRepository.state.value as? FeeSelectorUM.Content
|
||||
|
||||
if (feeStateUM == null) {
|
||||
Timber.e("getSelectedFee: FeeSelectorUM is not Content: $feeStateUM, returning null")
|
||||
Timber.e(
|
||||
"getSelectedFee: FeeSelectorUM is not Content: ${feeSelectorRepository.state.value}, returning null",
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue