diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt
index 072a7389f6..b377102b35 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt
@@ -66,10 +66,12 @@ fun NotificationWithBackground(config: NotificationConfig, modifier: Modifier =
Image(
painter = painterResource(config.iconResId),
contentDescription = null,
- modifier = Modifier.constrainAs(iconRef) {
- start.linkTo(parent.start, spacing12)
- linkTo(titleRef.top, subtitleRef.bottom, bias = 0.1f)
- },
+ modifier = Modifier
+ .size(TangemTheme.dimens.size34)
+ .constrainAs(iconRef) {
+ start.linkTo(parent.start, spacing12)
+ linkTo(titleRef.top, subtitleRef.bottom, bias = 0.1f)
+ },
)
Text(
text = config.title.resolveReference(),
@@ -147,7 +149,7 @@ private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvid
NotificationConfig(
title = resourceReference(id = R.string.main_swap_promotion_title),
subtitle = resourceReference(id = R.string.main_swap_promotion_message),
- iconResId = R.drawable.ic_swap_promo_34,
+ iconResId = R.drawable.img_swap_promo,
backgroundResId = R.drawable.img_swap_promo_banner_background,
),
NotificationConfig(
@@ -158,7 +160,7 @@ private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvid
"currencies between any chains you wish. Commission free period " +
"till Dec 31.",
),
- iconResId = R.drawable.ic_swap_promo_34,
+ iconResId = R.drawable.img_swap_promo,
backgroundResId = R.drawable.img_swap_promo_banner_background,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = resourceReference(id = R.string.token_swap_promotion_button),
diff --git a/core/ui/src/main/res/drawable/ic_swap_promo_34.xml b/core/ui/src/main/res/drawable/ic_swap_promo_34.xml
deleted file mode 100644
index 3c279910c8..0000000000
--- a/core/ui/src/main/res/drawable/ic_swap_promo_34.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
diff --git a/core/ui/src/main/res/drawable/img_swap_promo.webp b/core/ui/src/main/res/drawable/img_swap_promo.webp
new file mode 100644
index 0000000000..4f5bd02d24
Binary files /dev/null and b/core/ui/src/main/res/drawable/img_swap_promo.webp differ
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt
index f658706441..3090438e08 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt
@@ -16,6 +16,8 @@ import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.domain.api.SwapRepository
import com.tangem.feature.swap.domain.models.domain.LeastTokenInfo
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import com.tangem.utils.coroutines.runCatching
+import com.tangem.utils.isNullOrZero
import kotlinx.coroutines.flow.*
import java.math.BigDecimal
@@ -89,30 +91,36 @@ class GetCurrencyWarningsUseCase(
cryptoStatuses.fold(
ifLeft = { null },
ifRight = { cryptoCurrencyStatuses ->
- val pairs = swapRepository.getPairs(
- LeastTokenInfo(
- contractAddress = (currency as? CryptoCurrency.Token)?.contractAddress ?: "0",
- network = currency.network.backendId,
- ),
- cryptoCurrencyStatuses.map { it.currency },
- )
+ val pairs = runCatching(dispatchers.io) {
+ swapRepository.getPairs(
+ LeastTokenInfo(
+ contractAddress = (currency as? CryptoCurrency.Token)?.contractAddress ?: "0",
+ network = currency.network.backendId,
+ ),
+ cryptoCurrencyStatuses.map { it.currency },
+ )
+ }.getOrNull()?.pairs ?: emptyList()
+
val filteredCurrencies = cryptoCurrencyStatuses.filterNot {
- it.currency.network.backendId == currency.network.backendId
+ it.currency.id == currency.id
}
- val currencyPairs = pairs.pairs.filter {
+ val currencyPairs = pairs.filter {
it.from.network == currency.network.backendId ||
it.to.network == currency.network.backendId
}
val isExchangeable = currencyPairs.any { pair ->
- val availablePair = if (currencyStatus.value.amount.isZero()) {
- filteredCurrencies.filterNot { it.value.amount.isZero() }
+ val availablePair = if (currencyStatus.value.amount.isNullOrZero()) {
+ filteredCurrencies.filterNot { it.value.amount.isNullOrZero() }
} else {
filteredCurrencies
}
availablePair
.any {
- it.currency.network.backendId == pair.to.network ||
- it.currency.network.backendId == pair.from.network
+ (
+ it.currency.network.backendId == pair.to.network ||
+ it.currency.network.backendId == pair.from.network
+ ) &&
+ !it.value.amount.isNullOrZero()
}
}
if (isExchangeable) {
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 3754e0c835..631d3e6d51 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
@@ -102,15 +102,15 @@ internal class SwapInteractorImpl @Inject constructor(
currency = currency,
leastPairs = pairsLeast.pairs,
cryptoCurrenciesList = walletCurrencyStatusesExceptInitial,
- tokenInfoForFilter = { it.from },
- tokenInfoForAvailable = { it.to },
+ tokenInfoForFilter = { it.to },
+ tokenInfoForAvailable = { it.from },
),
toGroup = getToCurrenciesGroup(
currency = currency,
leastPairs = pairsLeast.pairs,
cryptoCurrenciesList = walletCurrencyStatusesExceptInitial,
- tokenInfoForFilter = { it.to },
- tokenInfoForAvailable = { it.from },
+ tokenInfoForFilter = { it.from },
+ tokenInfoForAvailable = { it.to },
),
allProviders = pairsLeast.allProviders,
)
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 6f42bbd1d2..895fcb1ea5 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
@@ -2,10 +2,7 @@ package com.tangem.feature.swap.converters
import com.tangem.common.Provider
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
-import com.tangem.core.ui.extensions.getTintForTokenIcon
-import com.tangem.core.ui.extensions.networkIconResId
-import com.tangem.core.ui.extensions.stringReference
-import com.tangem.core.ui.extensions.tryGetBackgroundForTokenIcon
+import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
@@ -15,6 +12,7 @@ import com.tangem.feature.swap.domain.models.ui.CurrenciesGroup
import com.tangem.feature.swap.models.SwapSelectTokenStateHolder
import com.tangem.feature.swap.models.TokenBalanceData
import com.tangem.feature.swap.models.TokenToSelectState
+import com.tangem.feature.swap.presentation.R
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toImmutableList
@@ -26,8 +24,12 @@ class TokensDataConverter(
) : Converter {
override fun convert(value: CurrenciesGroup): SwapSelectTokenStateHolder {
- val availableTitle = TokenToSelectState.Title(stringReference("My tokens")) // todo replace with resource
- val unavailableTitle = TokenToSelectState.Title(stringReference("My tokens")) // todo replace with resource
+ val availableTitle = TokenToSelectState.Title(
+ resourceReference(R.string.exchange_tokens_available_tokens_header),
+ )
+ val unavailableTitle = TokenToSelectState.Title(
+ resourceReference(R.string.exchange_tokens_available_tokens_header),
+ )
return SwapSelectTokenStateHolder(
availableTokens = value.available.map { tokenWithBalanceToTokenToSelect(it, true) }
.toMutableList()
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 ae4d9ba3cf..1502568f92 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
@@ -19,7 +19,7 @@ data class SwapStateHolder(
val blockchainId: String, // not the same as networkId, its local id in app
val warnings: List = emptyList(),
val alert: SwapWarning.GenericWarning? = null,
- val updateInProgress: Boolean = false,
+ val changeCardsButtonState: ChangeCardsButtonState = ChangeCardsButtonState.ENABLED,
val providerState: ProviderState,
val fee: FeeItemState = FeeItemState.Empty,
@@ -131,4 +131,8 @@ sealed interface SwapWarning {
enum class GenericWarningType {
NETWORK, OTHER
+}
+
+enum class ChangeCardsButtonState {
+ ENABLED, DISABLED, UPDATE_IN_PROGRESS
}
\ No newline at end of file
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 18933ba236..e66df2962d 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
@@ -84,7 +84,7 @@ internal class StateBuilder(
onBackClicked = actions.onBackClicked,
onChangeCardsClicked = actions.onChangeCardsClicked,
onMaxAmountSelected = actions.onMaxAmountSelected,
- updateInProgress = true,
+ changeCardsButtonState = ChangeCardsButtonState.UPDATE_IN_PROGRESS,
onShowPermissionBottomSheet = actions.openPermissionBottomSheet,
providerState = ProviderState.Empty(),
)
@@ -138,7 +138,7 @@ internal class StateBuilder(
loading = false,
onClick = { },
),
- updateInProgress = false,
+ changeCardsButtonState = ChangeCardsButtonState.DISABLED,
)
}
@@ -186,7 +186,7 @@ internal class StateBuilder(
swapButton = SwapButton(enabled = false, loading = true, onClick = {}),
providerState = ProviderState.Loading(),
permissionState = uiStateHolder.permissionState,
- updateInProgress = true,
+ changeCardsButtonState = ChangeCardsButtonState.UPDATE_IN_PROGRESS,
)
}
@@ -207,6 +207,7 @@ internal class StateBuilder(
bestRatedProviderId: String,
isManyProviders: Boolean,
selectedFeeType: FeeType,
+ isReverseSwapPossible: Boolean,
): SwapStateHolder {
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
@@ -257,7 +258,11 @@ internal class StateBuilder(
loading = false,
onClick = actions.onSwapClick,
),
- updateInProgress = false,
+ changeCardsButtonState = if (isReverseSwapPossible) {
+ ChangeCardsButtonState.ENABLED
+ } else {
+ ChangeCardsButtonState.DISABLED
+ },
providerState = swapProvider.convertToContentClickableProviderState(
isBestRate = bestRatedProviderId == swapProvider.providerId,
fromTokenInfo = quoteModel.fromTokenInfo,
@@ -354,12 +359,14 @@ internal class StateBuilder(
}
}
+ @Suppress("LongParameterList")
fun createQuotesErrorState(
uiStateHolder: SwapStateHolder,
swapProvider: SwapProvider,
fromToken: TokenSwapInfo,
toToken: CryptoCurrencyStatus?,
dataError: DataError,
+ isReverseSwapPossible: Boolean,
): SwapStateHolder {
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
@@ -409,7 +416,11 @@ internal class StateBuilder(
loading = false,
onClick = actions.onSwapClick,
),
- updateInProgress = false,
+ changeCardsButtonState = if (isReverseSwapPossible) {
+ ChangeCardsButtonState.ENABLED
+ } else {
+ ChangeCardsButtonState.DISABLED
+ },
providerState = providerState,
)
}
@@ -475,6 +486,7 @@ internal class StateBuilder(
fun createQuotesEmptyAmountState(
uiStateHolder: SwapStateHolder,
emptyAmountState: SwapState.EmptyAmountState,
+ isReverseSwapPossible: Boolean,
): SwapStateHolder {
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
@@ -514,7 +526,11 @@ internal class StateBuilder(
loading = false,
onClick = { },
),
- updateInProgress = false,
+ changeCardsButtonState = if (isReverseSwapPossible) {
+ ChangeCardsButtonState.ENABLED
+ } else {
+ ChangeCardsButtonState.DISABLED
+ },
providerState = ProviderState.Empty(),
)
}
@@ -538,7 +554,7 @@ internal class StateBuilder(
fun createSilentLoadState(uiState: SwapStateHolder): SwapStateHolder {
return uiState.copy(
- updateInProgress = true,
+ changeCardsButtonState = ChangeCardsButtonState.UPDATE_IN_PROGRESS,
)
}
@@ -713,7 +729,7 @@ internal class StateBuilder(
onClick = onAlertClick,
type = if (txState is TxState.NetworkError) GenericWarningType.NETWORK else GenericWarningType.OTHER,
),
- updateInProgress = false,
+ changeCardsButtonState = ChangeCardsButtonState.ENABLED,
)
}
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 8d1fe2e6df..360cd4e016 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
@@ -195,23 +195,34 @@ private fun SwapButton(state: SwapStateHolder, modifier: Modifier = Modifier) {
contentColor = TangemTheme.colors.text.primary1,
modifier = modifier.size(TangemTheme.dimens.size48),
onClick = state.onChangeCardsClicked,
- enabled = !state.updateInProgress,
+ enabled = state.changeCardsButtonState == ChangeCardsButtonState.ENABLED,
) {
- if (state.updateInProgress) {
- CircularProgressIndicator(
- modifier = Modifier
- .size(TangemTheme.dimens.size16)
- .padding(TangemTheme.dimens.spacing14),
- color = TangemTheme.colors.icon.primary1,
- strokeWidth = TangemTheme.dimens.size2,
- )
- } else {
- Icon(
- painter = painterResource(id = R.drawable.ic_exchange_vertical_24),
- contentDescription = null,
- tint = TangemTheme.colors.text.primary1,
- modifier = Modifier.padding(TangemTheme.dimens.spacing12),
- )
+ when (state.changeCardsButtonState) {
+ ChangeCardsButtonState.UPDATE_IN_PROGRESS -> {
+ CircularProgressIndicator(
+ modifier = Modifier
+ .size(TangemTheme.dimens.size16)
+ .padding(TangemTheme.dimens.spacing14),
+ color = TangemTheme.colors.icon.primary1,
+ strokeWidth = TangemTheme.dimens.size2,
+ )
+ }
+ ChangeCardsButtonState.ENABLED -> {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_exchange_vertical_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.text.primary1,
+ modifier = Modifier.padding(TangemTheme.dimens.spacing12),
+ )
+ }
+ ChangeCardsButtonState.DISABLED -> {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_exchange_vertical_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.text.disabled,
+ modifier = Modifier.padding(TangemTheme.dimens.spacing12),
+ )
+ }
}
}
}
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 a36badc51e..b7606f80d0 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
@@ -60,8 +60,8 @@ internal class SwapViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel(), DefaultLifecycleObserver {
- private val initialCryptoCurrency: CryptoCurrency = savedStateHandle[SwapFragment.CURRENCY_BUNDLE_KEY]
- ?: error("no expected parameter CryptoCurrency found`")
+ private val initialCryptoCurrency: CryptoCurrency =
+ savedStateHandle[SwapFragment.CURRENCY_BUNDLE_KEY] ?: error("no expected parameter CryptoCurrency found`")
private lateinit var initialCryptoCurrencyStatus: CryptoCurrencyStatus
private var isBalanceHidden = true
@@ -114,15 +114,12 @@ internal class SwapViewModel @Inject constructor(
}
override fun onCreate(owner: LifecycleOwner) {
- getBalanceHidingSettingsUseCase()
- .flowWithLifecycle(owner.lifecycle)
- .onEach {
- isBalanceHidden = it.isBalanceHidden
- withContext(dispatchers.main) {
- uiState = stateBuilder.updateBalanceHiddenState(uiState, isBalanceHidden)
- }
+ getBalanceHidingSettingsUseCase().flowWithLifecycle(owner.lifecycle).onEach {
+ isBalanceHidden = it.isBalanceHidden
+ withContext(dispatchers.main) {
+ uiState = stateBuilder.updateBalanceHiddenState(uiState, isBalanceHidden)
}
- .launchIn(viewModelScope)
+ }.launchIn(viewModelScope)
}
override fun onCleared() {
@@ -175,19 +172,18 @@ internal class SwapViewModel @Inject constructor(
selectedCurrency = null,
)
- uiState =
- stateBuilder.createInitialErrorState(
- uiState,
- (it as? ExpressException)?.dataError?.code ?: DataError.UnknownError.code,
- ) {
- uiState = stateBuilder.createInitialLoadingState(
- initialCurrency = initialCryptoCurrency,
- networkInfo = blockchainInteractor.getBlockchainInfo(
- initialCryptoCurrency.network.backendId,
- ),
- )
- initTokens()
- }
+ uiState = stateBuilder.createInitialErrorState(
+ uiState,
+ (it as? ExpressException)?.dataError?.code ?: DataError.UnknownError.code,
+ ) {
+ uiState = stateBuilder.createInitialLoadingState(
+ initialCurrency = initialCryptoCurrency,
+ networkInfo = blockchainInteractor.getBlockchainInfo(
+ initialCryptoCurrency.network.backendId,
+ ),
+ )
+ initTokens()
+ }
}
}
}
@@ -216,7 +212,7 @@ internal class SwapViewModel @Inject constructor(
}
private fun updateTokensState(dataState: TokensDataStateExpress) {
- val tokensDataState = if (!isOrderReversed) dataState.toGroup else dataState.fromGroup
+ val tokensDataState = if (isOrderReversed) dataState.fromGroup else dataState.toGroup
uiState = stateBuilder.addTokensToState(
uiState = uiState,
tokensDataState = tokensDataState,
@@ -295,8 +291,7 @@ internal class SwapViewModel @Inject constructor(
if (providersState.isNotEmpty()) {
val (provider, state) = updateLoadedQuotes(providersState)
setupLoadedState(provider, state, fromToken)
- val successStates = providersState
- .getLastLoadedSuccessStates()
+ val successStates = providersState.getLastLoadedSuccessStates()
val pricesLowerBest = getPricesLowerBest(successStates)
uiState = stateBuilder.updateProvidersBottomSheetContent(
uiState = uiState,
@@ -329,6 +324,7 @@ internal class SwapViewModel @Inject constructor(
bestRatedProviderId = bestRatedProviderId,
isManyProviders = dataState.lastLoadedSwapStates.size > 1,
selectedFeeType = dataState.selectedFee?.feeType ?: FeeType.NORMAL,
+ isReverseSwapPossible = isReverseSwapPossible(),
)
if (uiState.warnings.any { it is SwapWarning.UnableToCoverFeeWarning }) {
analyticsEventHandler.send(
@@ -343,6 +339,7 @@ internal class SwapViewModel @Inject constructor(
uiState = stateBuilder.createQuotesEmptyAmountState(
uiStateHolder = uiState,
emptyAmountState = state,
+ isReverseSwapPossible = isReverseSwapPossible(),
)
}
is SwapState.SwapError -> {
@@ -353,6 +350,7 @@ internal class SwapViewModel @Inject constructor(
fromToken = state.fromTokenInfo,
toToken = dataState.toCryptoCurrency,
dataError = state.error,
+ isReverseSwapPossible = isReverseSwapPossible(),
)
sendErrorAnalyticsEvent(state.error, provider)
}
@@ -419,16 +417,15 @@ internal class SwapViewModel @Inject constructor(
}
private fun selectDefaultFee(state: SwapState.QuotesLoadedState): TxFee? {
- return dataState.selectedFee
- ?: when (val txFee = state.txFee) {
- TxFeeState.Empty -> null
- is TxFeeState.MultipleFeeState -> {
- txFee.normalFee
- }
- is TxFeeState.SingleFeeState -> {
- txFee.fee
- }
+ return dataState.selectedFee ?: when (val txFee = state.txFee) {
+ TxFeeState.Empty -> null
+ is TxFeeState.MultipleFeeState -> {
+ txFee.normalFee
}
+ is TxFeeState.SingleFeeState -> {
+ txFee.fee
+ }
+ }
}
@Suppress("LongMethod")
@@ -453,58 +450,56 @@ internal class SwapViewModel @Inject constructor(
includeFeeInAmount = lastLoadedQuotesState.preparedSwapConfigState.includeFeeInAmount,
fee = requireNotNull(dataState.selectedFee),
)
- }
- .onSuccess {
- when (it) {
- is TxState.TxSent -> {
- val url = blockchainInteractor.getExplorerTransactionLink(
- networkId = dataState.networkId,
- txAddress = it.txAddress,
- )
- uiState = stateBuilder.createSuccessState(
- uiState = uiState,
- txState = it,
- dataState = dataState,
- txUrl = url,
- onExploreClick = {
- val txHash = it.txAddress
- if (txHash.isNotEmpty()) {
- swapRouter.openUrl(url)
- }
+ }.onSuccess {
+ when (it) {
+ is TxState.TxSent -> {
+ val url = blockchainInteractor.getExplorerTransactionLink(
+ networkId = dataState.networkId,
+ txAddress = it.txAddress,
+ )
+ uiState = stateBuilder.createSuccessState(
+ uiState = uiState,
+ txState = it,
+ dataState = dataState,
+ txUrl = url,
+ onExploreClick = {
+ val txHash = it.txAddress
+ if (txHash.isNotEmpty()) {
+ swapRouter.openUrl(url)
+ }
+ analyticsEventHandler.send(
+ event = SwapEvents.ButtonExplore(initialCryptoCurrency.symbol),
+ )
+ },
+ onStatusClick = {
+ val txExternalUrl = it.txExternalUrl
+ if (!txExternalUrl.isNullOrBlank()) {
+ swapRouter.openUrl(txExternalUrl)
analyticsEventHandler.send(
- event = SwapEvents.ButtonExplore(initialCryptoCurrency.symbol),
+ event = SwapEvents.ButtonStatus(initialCryptoCurrency.symbol),
)
- },
- onStatusClick = {
- val txExternalUrl = it.txExternalUrl
- if (!txExternalUrl.isNullOrBlank()) {
- swapRouter.openUrl(txExternalUrl)
- analyticsEventHandler.send(
- event = SwapEvents.ButtonStatus(initialCryptoCurrency.symbol),
- )
- }
- },
- )
- sendSuccessEvent()
+ }
+ },
+ )
+ sendSuccessEvent()
- swapRouter.openScreen(SwapNavScreen.Success)
- }
- is TxState.UserCancelled -> {
- startLoadingQuotesFromLastState()
- }
- else -> {
- startLoadingQuotesFromLastState()
- uiState = stateBuilder.createErrorTransaction(uiState, it) {
- uiState = stateBuilder.clearAlert(uiState)
- }
+ swapRouter.openScreen(SwapNavScreen.Success)
+ }
+ is TxState.UserCancelled -> {
+ startLoadingQuotesFromLastState()
+ }
+ else -> {
+ startLoadingQuotesFromLastState()
+ uiState = stateBuilder.createErrorTransaction(uiState, it) {
+ uiState = stateBuilder.clearAlert(uiState)
}
}
}
- .onFailure {
- Timber.e(it)
- startLoadingQuotesFromLastState()
- makeDefaultAlert()
- }
+ }.onFailure {
+ Timber.e(it)
+ startLoadingQuotesFromLastState()
+ makeDefaultAlert()
+ }
}
}
@@ -540,8 +535,7 @@ internal class SwapViewModel @Inject constructor(
"dataState.approveDataModel might not be null"
},
forTokenContractAddress = (dataState.fromCryptoCurrency?.currency as? CryptoCurrency.Token)
- ?.contractAddress
- ?: "",
+ ?.contractAddress ?: "",
fromToken = requireNotNull(dataState.fromCryptoCurrency?.currency) {
"dataState.fromCurrency might not be null"
},
@@ -554,25 +548,23 @@ internal class SwapViewModel @Inject constructor(
},
),
)
- }
- .onSuccess {
- when (it) {
- is TxState.TxSent -> {
- uiState = stateBuilder.loadingPermissionState(uiState)
- uiState = stateBuilder.dismissBottomSheet(uiState)
- startLoadingQuotesFromLastState(isSilent = true)
- }
- is TxState.UserCancelled -> Unit
- else -> {
- uiState = stateBuilder.createErrorTransaction(uiState, it) {
- uiState = stateBuilder.clearAlert(uiState)
- }
+ }.onSuccess {
+ when (it) {
+ is TxState.TxSent -> {
+ uiState = stateBuilder.loadingPermissionState(uiState)
+ uiState = stateBuilder.dismissBottomSheet(uiState)
+ startLoadingQuotesFromLastState(isSilent = true)
+ }
+ is TxState.UserCancelled -> Unit
+ else -> {
+ uiState = stateBuilder.createErrorTransaction(uiState, it) {
+ uiState = stateBuilder.clearAlert(uiState)
}
}
}
- .onFailure {
- makeDefaultAlert()
- }
+ }.onFailure {
+ makeDefaultAlert()
+ }
}
}
@@ -653,12 +645,17 @@ internal class SwapViewModel @Inject constructor(
private fun onChangeCardsClicked() {
val newFromToken = dataState.toCryptoCurrency
val newToToken = dataState.fromCryptoCurrency
+
if (newFromToken != null && newToToken != null) {
dataState = dataState.copy(
fromCryptoCurrency = newFromToken,
toCryptoCurrency = newToToken,
)
isOrderReversed = !isOrderReversed
+ dataState.tokensDataState?.let {
+ updateTokensState(it)
+ }
+
val decimals = newFromToken.currency.decimals
lastAmount.value = cutAmountWithDecimals(decimals, lastAmount.value)
uiState = stateBuilder.updateSwapAmount(
@@ -783,8 +780,8 @@ internal class SwapViewModel @Inject constructor(
},
onClickFee = {
val selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL
- val txFeeState = dataState.getCurrentLoadedSwapState()?.txFee as? TxFeeState.MultipleFeeState
- ?: return@UiActions
+ val txFeeState =
+ dataState.getCurrentLoadedSwapState()?.txFee as? TxFeeState.MultipleFeeState ?: return@UiActions
uiState = stateBuilder.showSelectFeeBottomSheet(
uiState = uiState,
selectedFee = selectedFee,
@@ -862,9 +859,7 @@ internal class SwapViewModel @Inject constructor(
private fun findBestQuoteProvider(state: SuccessLoadedSwapData): SwapProvider? {
// finding best quotes
return state.minByOrNull {
- if (!it.value.fromTokenInfo.amountFiat.isNullOrZero() &&
- !it.value.toTokenInfo.amountFiat.isNullOrZero()
- ) {
+ if (!it.value.fromTokenInfo.amountFiat.isNullOrZero() && !it.value.toTokenInfo.amountFiat.isNullOrZero()) {
it.value.fromTokenInfo.amountFiat.divide(
it.value.toTokenInfo.amountFiat,
it.value.toTokenInfo.cryptoCurrencyStatus.currency.decimals,
@@ -894,15 +889,13 @@ internal class SwapViewModel @Inject constructor(
}
private fun createSelectedAppCurrencyFlow(): StateFlow {
- return getSelectedAppCurrencyUseCase()
- .map { maybeAppCurrency ->
- maybeAppCurrency.getOrElse { AppCurrency.Default }
- }
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.Eagerly,
- initialValue = AppCurrency.Default,
- )
+ return getSelectedAppCurrencyUseCase().map { maybeAppCurrency ->
+ maybeAppCurrency.getOrElse { AppCurrency.Default }
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.Eagerly,
+ initialValue = AppCurrency.Default,
+ )
}
private fun findSwapProviders(fromToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus): List {
@@ -931,11 +924,27 @@ internal class SwapViewModel @Inject constructor(
}
private fun Map.getLastLoadedSuccessStates(): SuccessLoadedSwapData {
- return this
- .filter { it.value is SwapState.QuotesLoadedState }
+ return this.filter { it.value is SwapState.QuotesLoadedState }
.mapValues { it.value as SwapState.QuotesLoadedState }
}
+ private fun isReverseSwapPossible(): Boolean {
+ val from = dataState.fromCryptoCurrency ?: return false
+ val to = dataState.toCryptoCurrency ?: return false
+
+ val currenciesGroup = if (isOrderReversed) {
+ dataState.tokensDataState?.toGroup
+ } else {
+ dataState.tokensDataState?.fromGroup
+ } ?: return false
+
+ val chosen = if (isOrderReversed) from else to
+
+ return currenciesGroup.available
+ .map { it.currencyStatus.currency }
+ .contains(chosen.currency)
+ }
+
companion object {
private const val loggingTag = "SwapViewModel"
private const val INITIAL_AMOUNT = ""
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt
index fe9ef56abc..dbe63a69f8 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt
@@ -46,7 +46,7 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
config = NotificationConfig(
title = resourceReference(id = R.string.token_swap_promotion_title),
subtitle = resourceReference(id = R.string.token_swap_promotion_message),
- iconResId = R.drawable.ic_swap_promo_34,
+ iconResId = R.drawable.img_swap_promo,
backgroundResId = R.drawable.img_swap_promo_banner_background,
onCloseClick = onCloseClick,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt
index 6aeebbc6c7..7f6bfd6b46 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt
@@ -173,7 +173,7 @@ sealed class WalletNotification(val config: NotificationConfig) {
config = NotificationConfig(
title = resourceReference(id = R.string.main_swap_promotion_title),
subtitle = resourceReference(id = R.string.main_swap_promotion_message),
- iconResId = R.drawable.ic_swap_promo_34,
+ iconResId = R.drawable.img_swap_promo,
backgroundResId = R.drawable.img_swap_promo_banner_background,
onCloseClick = onCloseClick,
),