Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-20 16:21:09 +07:00
parent a0132aea5a
commit 1a9f22a4ae
2 changed files with 100 additions and 1 deletions

View file

@ -693,6 +693,32 @@ internal class StateBuilder(
)
}
fun updateSendCurrencyBalance(
uiState: SwapStateHolder,
cryptoCurrencyStatus: CryptoCurrencyStatus,
): SwapStateHolder {
if (uiState.sendCardData !is SwapCardState.SwapCardData) return uiState
return uiState.copy(
sendCardData = uiState.sendCardData.copy(
balance = cryptoCurrencyStatus.getFormattedAmount(isNeedSymbol = false),
),
)
}
fun updateReceiveCurrencyBalance(
uiState: SwapStateHolder,
cryptoCurrencyStatus: CryptoCurrencyStatus,
): SwapStateHolder {
if (uiState.receiveCardData !is SwapCardState.SwapCardData) return uiState
return uiState.copy(
receiveCardData = uiState.receiveCardData.copy(
balance = cryptoCurrencyStatus.getFormattedAmount(isNeedSymbol = false),
),
)
}
fun updateBalanceHiddenState(uiState: SwapStateHolder, isBalanceHidden: Boolean): SwapStateHolder {
if (uiState.sendCardData !is SwapCardState.SwapCardData) return uiState
if (uiState.receiveCardData !is SwapCardState.SwapCardData) return uiState

View file

@ -4,6 +4,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.*
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
@ -13,11 +14,13 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.analytics.SwapEvents
import com.tangem.feature.swap.domain.BlockchainInteractor
import com.tangem.feature.swap.domain.SwapInteractor
@ -62,6 +65,7 @@ internal class SwapViewModel @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase,
savedStateHandle: SavedStateHandle,
) : ViewModel(), DefaultLifecycleObserver {
@ -104,6 +108,9 @@ internal class SwapViewModel @Inject constructor(
(it.error is DataError.ExchangeTooSmallAmountError || it.error is DataError.ExchangeTooBigAmountError)
}
private val fromTokenBalanceJobHolder = JobHolder()
private val toTokenBalanceJobHolder = JobHolder()
val currentScreen: SwapNavScreen
get() = swapRouter.currentScreen
@ -173,6 +180,23 @@ internal class SwapViewModel @Inject constructor(
state,
),
)
val userWalletId = swapInteractor.getSelectedWallet()?.walletId ?: return@launch
(dataState.fromCryptoCurrency?.currency as? CryptoCurrency.Coin)?.let {
subscribeToCoinBalanceUpdates(
userWalletId = userWalletId,
coin = it,
isFromCurrency = true,
)
}
(dataState.toCryptoCurrency?.currency as? CryptoCurrency.Coin)?.let {
subscribeToCoinBalanceUpdates(
userWalletId = userWalletId,
coin = it,
isFromCurrency = false,
)
}
}.onFailure {
Timber.tag(loggingTag).e(it)
@ -617,7 +641,6 @@ internal class SwapViewModel @Inject constructor(
unavailable = unavailable,
afterSearch = true,
),
)
} else {
tokenDataState.copy(
@ -647,15 +670,35 @@ internal class SwapViewModel @Inject constructor(
analyticsEventHandler.send(SwapEvents.ChooseTokenScreenResult(tokenChosen = true, token = it))
}
val userWalletId = swapInteractor.getSelectedWallet()?.walletId
if (foundToken != null) {
val fromToken: CryptoCurrencyStatus
val toToken: CryptoCurrencyStatus
if (isOrderReversed) {
fromToken = foundToken.currencyStatus
toToken = initialCryptoCurrencyStatus
val newToken = fromToken.currency as? CryptoCurrency.Coin
if (userWalletId != null && newToken != null) {
subscribeToCoinBalanceUpdates(
userWalletId = userWalletId,
coin = newToken,
isFromCurrency = true,
)
}
} else {
fromToken = initialCryptoCurrencyStatus
toToken = foundToken.currencyStatus
val newToken = toToken.currency as? CryptoCurrency.Coin
if (userWalletId != null && newToken != null) {
subscribeToCoinBalanceUpdates(
userWalletId = userWalletId,
coin = newToken,
isFromCurrency = false,
)
}
}
dataState = dataState.copy(
fromCryptoCurrency = fromToken,
@ -673,6 +716,36 @@ internal class SwapViewModel @Inject constructor(
}
}
private fun subscribeToCoinBalanceUpdates(
userWalletId: UserWalletId,
coin: CryptoCurrency.Coin,
isFromCurrency: Boolean,
) {
Timber.d("Subscribe to ${coin.id} balance updates")
getCurrencyStatusUpdatesUseCase(
userWalletId = userWalletId,
currencyId = coin.id,
isSingleWalletWithTokens = false,
)
.mapNotNull { (it as? Either.Right)?.value }
.distinctUntilChanged { old, new -> old.value.amount == new.value.amount } // Check only balance changes
.onEach {
Timber.d("${coin.id} balance is ${it.value.amount}")
uiState = if (isFromCurrency) {
dataState = dataState.copy(fromCryptoCurrency = it)
stateBuilder.updateSendCurrencyBalance(uiState, it)
} else {
dataState = dataState.copy(toCryptoCurrency = it)
stateBuilder.updateReceiveCurrencyBalance(uiState, it)
}
}
.flowOn(dispatchers.main)
.launchIn(viewModelScope)
.saveIn(if (isFromCurrency) fromTokenBalanceJobHolder else toTokenBalanceJobHolder)
}
private fun onChangeCardsClicked() {
val newFromToken = dataState.toCryptoCurrency
val newToToken = dataState.fromCryptoCurrency