diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt index 40c3483f16..7496a0a8e2 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt @@ -31,6 +31,9 @@ data class ExchangeDataResponse( ) data class TxDetails( + @Json(name = "payoutAddress") + val payoutAddress: String, + @Json(name = "requestId") val requestId: String, diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 42f9f8b591..c2cdf27727 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -193,6 +193,7 @@ Вы отправляете Мои токены У вас нет добавленных токенов. Добавьте токены для обмена + Токены не найдены. Пожалуйста, попробуйте другой запрос Недоступен для обмена с %s Кроме того, в курс обмена включена комиссия сети за отправку обмененных средств на ваш адрес Статус diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 1150c0349b..94f6ed4c2e 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -192,6 +192,7 @@ You send My tokens You haven\'t added any tokens yet. Add tokens via Market to swap + No tokens found. Please try another request Cannot be swapped for %s Additionally, the network fee for sending the exchanged funds back to your address is included in the rate Status diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt index 7a4c0df381..772502d688 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt @@ -292,6 +292,9 @@ internal class DefaultSwapRepository @Inject constructor( if (txDetails.requestId != requestId) { return@withContext DataError.InvalidRequestIdError().left() } + if (toAddress != txDetails.payoutAddress) { + return@withContext DataError.InvalidPayoutAddressError().left() + } expressDataConverter.convert( ExchangeDataResponseWithTxDetails( dataResponse = response, diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt index f5901e8c69..30ea8ec4cd 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExchangeStatusConverter.kt @@ -13,7 +13,7 @@ internal class ExchangeStatusConverter : Converter, val unavailable: List, + val afterSearch: Boolean, ) \ No newline at end of file diff --git a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt index 132327e4cb..14259bc672 100644 --- a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt +++ b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt @@ -9,9 +9,8 @@ sealed class TxState { val fromAmountValue: BigDecimal? = null, val toAmount: String? = null, val toAmountValue: BigDecimal? = null, - val txAddress: String, + val txHash: String, val txExternalUrl: String? = null, - val txUrl: String? = null, val timestamp: Long, ) : TxState() diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/BlockchainInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/BlockchainInteractor.kt index 8883e0f1a3..ceab0eb503 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/BlockchainInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/BlockchainInteractor.kt @@ -11,5 +11,5 @@ interface BlockchainInteractor { */ fun getBlockchainInfo(networkId: String): NetworkInfo - fun getExplorerTransactionLink(networkId: String, txAddress: String): String + fun getExplorerTransactionLink(networkId: String, txHash: String): String } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultBlockchainInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultBlockchainInteractor.kt index 836f193fe3..ea6207fece 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultBlockchainInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultBlockchainInteractor.kt @@ -18,7 +18,7 @@ internal class DefaultBlockchainInteractor @Inject constructor( } } - override fun getExplorerTransactionLink(networkId: String, txAddress: String): String { - return transactionManager.getExplorerTransactionLink(networkId, txAddress) + override fun getExplorerTransactionLink(networkId: String, txHash: String): String { + return transactionManager.getExplorerTransactionLink(networkId, txHash) } } \ No newline at end of file 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 19a88c1d4a..aa1167d436 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 @@ -54,7 +54,6 @@ internal class SwapInteractorImpl @Inject constructor( private val dispatcher: CoroutineDispatcherProvider, private val swapTransactionRepository: SwapTransactionRepository, private val initialToCurrencyResolver: InitialToCurrencyResolver, - private val blockchainInteractor: BlockchainInteractor, ) : SwapInteractor { private val estimateFeeUseCase by lazy(LazyThreadSafetyMode.NONE) { @@ -148,6 +147,7 @@ internal class SwapInteractorImpl @Inject constructor( return CurrenciesGroup( available = availableCryptoCurrencies, unavailable = unavailableCryptoCurrencies.map { CryptoCurrencySwapInfo(it, emptyList()) }, + afterSearch = false, ) } @@ -214,7 +214,7 @@ internal class SwapInteractorImpl @Inject constructor( is SendTxResult.Success -> { allowPermissionsHandler.addAddressToInProgress(permissionOptions.forTokenContractAddress) TxState.TxSent( - txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath).orEmpty(), + txHash = userWalletManager.getLastTransactionHash(networkId, derivationPath).orEmpty(), timestamp = System.currentTimeMillis(), ) } @@ -462,7 +462,7 @@ internal class SwapInteractorImpl @Inject constructor( currencyToGet.symbol, ), toAmountValue = swapData.toTokenAmount.value, - txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath).orEmpty(), + txHash = userWalletManager.getLastTransactionHash(networkId, derivationPath).orEmpty(), timestamp = System.currentTimeMillis(), ) } @@ -536,10 +536,6 @@ internal class SwapInteractorImpl @Inject constructor( }, ifRight = { val timestamp = System.currentTimeMillis() - val txUrl = blockchainInteractor.getExplorerTransactionLink( - networkId = currencyToSend.currency.network.backendId, - txAddress = exchangeData.transaction.txTo, - ) storeSwapTransaction( currencyToSend = currencyToSend, currencyToGet = currencyToGet, @@ -547,7 +543,7 @@ internal class SwapInteractorImpl @Inject constructor( swapProvider = swapProvider, swapDataModel = exchangeData, timestamp = timestamp, - txUrl = txUrl, + txExternalUrl = externalUrl.orEmpty(), ) storeLastCryptoCurrencyId(currencyToGet.currency) TxState.TxSent( @@ -561,12 +557,11 @@ internal class SwapInteractorImpl @Inject constructor( currencyToGet.currency.symbol, ), toAmountValue = exchangeData.toTokenAmount.value, - txAddress = userWalletManager.getLastTransactionHash( + txHash = userWalletManager.getLastTransactionHash( currencyToSend.currency.network.backendId, derivationPath, ).orEmpty(), txExternalUrl = externalUrl, - txUrl = txUrl, timestamp = timestamp, ) }, @@ -601,7 +596,7 @@ internal class SwapInteractorImpl @Inject constructor( swapProvider: SwapProvider, swapDataModel: SwapDataModel, timestamp: Long, - txUrl: String, + txExternalUrl: String, ) { swapTransactionRepository.storeTransaction( userWalletId = UserWalletId(userWalletManager.getWalletId()), @@ -617,7 +612,7 @@ internal class SwapInteractorImpl @Inject constructor( providerId = swapProvider.providerId, status = ExchangeStatus.New, txId = swapDataModel.transaction.txId, - txUrl = txUrl, + txExternalUrl = txExternalUrl, ), ), ) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index 518d7c9fc8..d299f7824e 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -42,7 +42,6 @@ class SwapDomainModule { walletManagersFacade: WalletManagersFacade, coroutineDispatcherProvider: CoroutineDispatcherProvider, initialToCurrencyResolver: InitialToCurrencyResolver, - blockchainInteractor: BlockchainInteractor, ): SwapInteractor { return SwapInteractorImpl( transactionManager = transactionManager, @@ -57,7 +56,6 @@ class SwapDomainModule { dispatcher = coroutineDispatcherProvider, swapTransactionRepository = swapTransactionRepository, initialToCurrencyResolver = initialToCurrencyResolver, - blockchainInteractor = blockchainInteractor, ) } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt index 895fcb1ea5..d475bad6f2 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/converters/TokensDataConverter.kt @@ -49,6 +49,7 @@ class TokensDataConverter( .toImmutableList(), onSearchEntered = onSearchEntered, onTokenSelected = onTokenSelected, + afterSearch = value.afterSearch, ) } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt index ac6762d7b7..585afb1921 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt @@ -7,6 +7,7 @@ import kotlinx.collections.immutable.ImmutableList data class SwapSelectTokenStateHolder( val availableTokens: ImmutableList, val unavailableTokens: ImmutableList, + val afterSearch: Boolean, val onSearchEntered: (String) -> Unit, val onTokenSelected: (String) -> Unit, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt index 83d86eee5b..577c2e96af 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -72,7 +72,6 @@ sealed class SwapCardState { data class SwapButton( val enabled: Boolean, - val loading: Boolean = false, val onClick: () -> Unit, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt index 4a217bcbfe..c1a94da8f7 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt @@ -260,7 +260,9 @@ private fun ProviderLoadingState(modifier: Modifier = Modifier) { ), ) { CircularProgressIndicator( - modifier = Modifier.size(TangemTheme.dimens.size16), + modifier = Modifier + .size(TangemTheme.dimens.size16) + .align(Alignment.CenterVertically), color = TangemTheme.colors.icon.informative, strokeWidth = TangemTheme.dimens.size2, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index f02e5006fe..b7c7418dae 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -79,7 +79,7 @@ internal class StateBuilder( ), fee = FeeItemState.Empty, networkCurrency = networkInfo.blockchainCurrency, - swapButton = SwapButton(enabled = false, loading = true, onClick = {}), + swapButton = SwapButton(enabled = false, onClick = {}), onRefresh = {}, onBackClicked = actions.onBackClicked, onChangeCardsClicked = actions.onChangeCardsClicked, @@ -138,7 +138,6 @@ internal class StateBuilder( fee = FeeItemState.Empty, swapButton = SwapButton( enabled = false, - loading = false, onClick = { }, ), changeCardsButtonState = ChangeCardsButtonState.DISABLED, @@ -187,7 +186,7 @@ internal class StateBuilder( ), warnings = emptyList(), fee = FeeItemState.Empty, - swapButton = SwapButton(enabled = false, loading = true, onClick = {}), + swapButton = SwapButton(enabled = false, onClick = {}), providerState = ProviderState.Loading(), permissionState = uiStateHolder.permissionState, changeCardsButtonState = ChangeCardsButtonState.UPDATE_IN_PROGRESS, @@ -260,7 +259,6 @@ internal class StateBuilder( fee = feeState, swapButton = SwapButton( enabled = getSwapButtonEnabled(quoteModel.preparedSwapConfigState), - loading = false, onClick = actions.onSwapClick, ), changeCardsButtonState = if (isReverseSwapPossible) { @@ -454,7 +452,6 @@ internal class StateBuilder( fee = FeeItemState.Empty, swapButton = SwapButton( enabled = false, - loading = false, onClick = actions.onSwapClick, ), changeCardsButtonState = if (isReverseSwapPossible) { @@ -566,7 +563,6 @@ internal class StateBuilder( fee = FeeItemState.Empty, swapButton = SwapButton( enabled = false, - loading = false, onClick = { }, ), changeCardsButtonState = if (isReverseSwapPossible) { @@ -582,7 +578,6 @@ internal class StateBuilder( fun createSwapInProgressState(uiState: SwapStateHolder): SwapStateHolder { return uiState.copy( swapButton = uiState.swapButton.copy( - loading = true, enabled = false, ), ) @@ -737,6 +732,7 @@ internal class StateBuilder( dataState: SwapProcessDataState, onExploreClick: () -> Unit, onStatusClick: () -> Unit, + txUrl: String, ): SwapStateHolder { val fee = requireNotNull(dataState.selectedFee) val fromCryptoCurrency = requireNotNull(dataState.fromCryptoCurrency) @@ -751,7 +747,7 @@ internal class StateBuilder( return uiState.copy( successState = SwapSuccessStateHolder( timestamp = txState.timestamp, - txUrl = txState.txUrl.orEmpty(), + txUrl = txUrl, providerName = stringReference(providerState.name), providerType = stringReference(providerState.type), showStatusButton = providerState.type == ExchangeProviderType.CEX.name, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index b211130172..571a1b51f1 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -399,7 +399,6 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.swapping_insufficient_funds), enabled = false, - showProgress = state.swapButton.loading, onClick = state.swapButton.onClick, ) } @@ -408,7 +407,6 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.swapping_give_permission), enabled = true, - showProgress = state.swapButton.loading, onClick = onPermissionWarningClick, ) } @@ -418,7 +416,6 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U text = stringResource(id = R.string.common_swap), iconResId = R.drawable.ic_tangem_24, enabled = state.swapButton.enabled, - showProgress = state.swapButton.loading, onClick = state.swapButton.onClick, ) } @@ -487,7 +484,7 @@ private val state = SwapStateHolder( ), ), networkCurrency = "MATIC", - swapButton = SwapButton(enabled = true, loading = false, onClick = {}), + swapButton = SwapButton(enabled = true, onClick = {}), onRefresh = {}, onBackClicked = {}, onChangeCardsClicked = {}, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index 4057aba9af..87a82413f1 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -42,10 +42,16 @@ fun SwapSelectTokenScreen(state: SwapSelectTokenStateHolder, onBack: () -> Unit) .background(color = TangemTheme.colors.background.secondary), content = { padding -> val modifier = Modifier.padding(padding) - if (state.availableTokens.isEmpty() && state.unavailableTokens.isEmpty()) { - EmptyTokensList(modifier) - } else { - ListOfTokens(state = state, modifier = modifier) + when { + state.availableTokens.isEmpty() && state.unavailableTokens.isEmpty() && state.afterSearch -> { + TokensNotFound(modifier) + } + state.availableTokens.isEmpty() && state.unavailableTokens.isEmpty() && !state.afterSearch -> { + EmptyTokensList(modifier) + } + else -> { + ListOfTokens(state = state, modifier = modifier) + } } }, topBar = { @@ -91,6 +97,26 @@ private fun EmptyTokensList(modifier: Modifier = Modifier) { } } +@Composable +private fun TokensNotFound(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .background(TangemTheme.colors.background.secondary) + .fillMaxSize(), + ) { + Text( + modifier = Modifier + .padding(top = TangemTheme.dimens.spacing32) + .padding(horizontal = TangemTheme.dimens.spacing30) + .align(Alignment.TopCenter), + text = stringResource(id = R.string.express_token_list_empty_search), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.Center, + ) + } +} + @Composable private fun ListOfTokens(state: SwapSelectTokenStateHolder, modifier: Modifier = Modifier) { val screenBackgroundColor = TangemTheme.colors.background.secondary @@ -283,6 +309,7 @@ private fun TokenScreenPreview() { state = SwapSelectTokenStateHolder( availableTokens = listOf(title, token, token, token).toImmutableList(), unavailableTokens = listOf(title, token, token, token).toImmutableList(), + afterSearch = false, onSearchEntered = {}, onTokenSelected = {}, ), diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt index 0aec67858b..45d37e07de 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt @@ -418,7 +418,7 @@ private fun TokenIcon( contentAlignment = Alignment.Center, ) { Image( - modifier = Modifier.padding(all = TangemTheme.dimens.spacing0_5), + modifier = Modifier.padding(all = TangemTheme.dimens.spacing2), painter = painterResource(id = networkIconRes), contentDescription = null, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index a511e6ab43..955d5e5f74 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -12,8 +12,11 @@ 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.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.feature.swap.analytics.SwapEvents import com.tangem.feature.swap.domain.BlockchainInteractor import com.tangem.feature.swap.domain.SwapInteractor @@ -32,6 +35,7 @@ import com.tangem.feature.swap.ui.StateBuilder import com.tangem.utils.coroutines.* import com.tangem.utils.isNullOrZero import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -57,6 +61,7 @@ internal class SwapViewModel @Inject constructor( private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase, + private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver { @@ -93,6 +98,11 @@ internal class SwapViewModel @Inject constructor( private var isOrderReversed = false private val lastAmount = mutableStateOf(INITIAL_AMOUNT) private var swapRouter: SwapRouter by Delegates.notNull() + + private val isExchangeTooSmallAmountError: (SwapState) -> Boolean = { + it is SwapState.SwapError && it.error is DataError.ExchangeTooSmallAmountError + } + val currentScreen: SwapNavScreen get() = swapRouter.currentScreen @@ -380,13 +390,17 @@ internal class SwapViewModel @Inject constructor( } private fun selectProvider(state: Map): SwapProvider { - val stateSuccess = state.getLastLoadedSuccessStates() - return if (stateSuccess.isNotEmpty()) { + val consideredProviders = state.filter { + it.value is SwapState.QuotesLoadedState || isExchangeTooSmallAmountError(it.value) + } + + return if (consideredProviders.isNotEmpty()) { val currentSelected = dataState.selectedProvider - if (currentSelected != null && stateSuccess.keys.contains(currentSelected)) { + if (currentSelected != null && consideredProviders.keys.contains(currentSelected)) { currentSelected } else { - findBestQuoteProvider(stateSuccess) ?: stateSuccess.keys.first() + findBestQuoteProvider(consideredProviders.getLastLoadedSuccessStates()) + ?: consideredProviders.keys.first() } } else { state.keys.first() @@ -448,14 +462,19 @@ internal class SwapViewModel @Inject constructor( }.onSuccess { when (it) { is TxState.TxSent -> { + val url = blockchainInteractor.getExplorerTransactionLink( + networkId = fromCurrency.currency.network.backendId, + txHash = it.txHash, + ) + updateWalletBalance() uiState = stateBuilder.createSuccessState( uiState = uiState, txState = it, dataState = dataState, + txUrl = url, onExploreClick = { - val txUrl = it.txUrl - if (!txUrl.isNullOrBlank()) { - swapRouter.openUrl(txUrl) + if (it.txHash.isNotEmpty()) { + swapRouter.openUrl(url) } analyticsEventHandler.send( event = SwapEvents.ButtonExplore(initialCryptoCurrency.symbol), @@ -580,13 +599,16 @@ internal class SwapViewModel @Inject constructor( fromGroup = tokenDataState.fromGroup.copy( available = available, unavailable = unavailable, + afterSearch = true, ), + ) } else { tokenDataState.copy( toGroup = tokenDataState.toGroup.copy( available = available, unavailable = unavailable, + afterSearch = true, ), ) } @@ -957,10 +979,32 @@ internal class SwapViewModel @Inject constructor( } } + private fun updateWalletBalance() { + swapInteractor.getSelectedWallet()?.let { userWallet -> + dataState.fromCryptoCurrency?.currency?.network?.let { network -> + viewModelScope.launch { + withContext(NonCancellable) { + updateForBalance(userWallet, network) + } + } + } + } + } + + private suspend fun updateForBalance(userWallet: UserWallet, network: Network) { + updateDelayedCurrencyStatusUseCase( + userWalletId = userWallet.walletId, + network = network, + delayMillis = UPDATE_BALANCE_DELAY_MILLIS, + refresh = true, + ) + } + companion object { private const val loggingTag = "SwapViewModel" private const val INITIAL_AMOUNT = "" private const val UPDATE_DELAY = 10000L private const val DEBOUNCE_AMOUNT_DELAY = 1000L + private const val UPDATE_BALANCE_DELAY_MILLIS = 11000L } } \ No newline at end of file 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 fd13879bc9..514afc7709 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 @@ -66,7 +66,7 @@ internal class TokenDetailsSwapTransactionsStateConverter( SwapTransactionsState( txId = transaction.txId, provider = transaction.provider, - txUrl = transaction.status?.txUrl, + txUrl = transaction.status?.txExternalUrl, timestamp = TextReference.Str("${timestamp.toDateFormat()}, ${timestamp.toTimeFormat()}"), fiatSymbol = appCurrency.symbol, statuses = getStatuses(transaction.status?.status), @@ -74,7 +74,7 @@ internal class TokenDetailsSwapTransactionsStateConverter( activeStatus = transaction.status?.status, notification = getNotification( transaction.status?.status, - transaction.status?.txUrl, + transaction.status?.txExternalUrl, ), toCryptoCurrencyId = toCurrency.currency.id, toCryptoAmount = BigDecimalFormatter.formatCryptoAmount( @@ -112,9 +112,9 @@ internal class TokenDetailsSwapTransactionsStateConverter( return tx.copy( activeStatus = statusModel.status, hasFailed = hasFailed, - notification = getNotification(statusModel.status, statusModel.txUrl), + notification = getNotification(statusModel.status, statusModel.txExternalUrl), statuses = getStatuses(statusModel.status, hasFailed), - txUrl = statusModel.txUrl, + txUrl = statusModel.txExternalUrl, ) }