From fa6a757af56fe6db61ee262bc48a09b8cc6e3177 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 29 Nov 2023 15:10:44 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../components/appbar/AppBarWithBackButton.kt | 15 ++++--- .../feature/swap/domain/SwapInteractorImpl.kt | 39 ++++++++++------- .../feature/swap/domain/models/ui/TxState.kt | 1 + .../swap/models/SwapSuccessStateHolder.kt | 5 ++- .../tangem/feature/swap/ui/StateBuilder.kt | 43 +++++++++---------- .../feature/swap/ui/SwapSuccessScreen.kt | 19 +++----- .../feature/swap/viewmodels/SwapViewModel.kt | 7 ++- 7 files changed, 67 insertions(+), 62 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButton.kt index da053a53f7..afb57565f8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/appbar/AppBarWithBackButton.kt @@ -3,14 +3,13 @@ package com.tangem.core.ui.components.appbar import androidx.annotation.DrawableRes import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* import androidx.compose.material.Icon import androidx.compose.material.Text +import androidx.compose.material.ripple.rememberRipple import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -49,7 +48,11 @@ fun AppBarWithBackButton( contentDescription = null, modifier = Modifier .size(size = TangemTheme.dimens.size24) - .clickable { onBackClick() }, + .clickable( + indication = rememberRipple(bounded = false), + interactionSource = remember { MutableInteractionSource() }, + onClick = onBackClick, + ), tint = TangemTheme.colors.icon.primary1, ) if (!text.isNullOrBlank()) { 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 da5dd7b595..c219a29944 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 @@ -213,7 +213,10 @@ internal class SwapInteractorImpl @Inject constructor( return when (result) { is SendTxResult.Success -> { allowPermissionsHandler.addAddressToInProgress(permissionOptions.forTokenContractAddress) - TxState.TxSent(txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath) ?: "") + TxState.TxSent( + txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath).orEmpty(), + timestamp = System.currentTimeMillis(), + ) } SendTxResult.UserCancelledError -> TxState.UserCancelled is SendTxResult.BlockchainSdkError -> TxState.BlockchainError @@ -370,7 +373,7 @@ internal class SwapInteractorImpl @Inject constructor( currencyToGet = currencyToGet, amount = amount, fee = fee, - providerId = swapProvider.providerId, + swapProvider = swapProvider, userWalletId = requireNotNull(getSelectedWallet()).walletId, ) } @@ -455,7 +458,8 @@ internal class SwapInteractorImpl @Inject constructor( swapData.toTokenAmount, currencyToGet.symbol, ), - txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath) ?: "", + txAddress = userWalletManager.getLastTransactionHash(networkId, derivationPath).orEmpty(), + timestamp = System.currentTimeMillis(), ) } SendTxResult.UserCancelledError -> TxState.UserCancelled @@ -471,7 +475,7 @@ internal class SwapInteractorImpl @Inject constructor( currencyToGet: CryptoCurrencyStatus, amount: SwapAmount, fee: TxFee, - providerId: String, + swapProvider: SwapProvider, userWalletId: UserWalletId, ): TxState { val exchangeData = repository.getExchangeData( @@ -481,7 +485,7 @@ internal class SwapInteractorImpl @Inject constructor( toNetwork = currencyToGet.currency.network.backendId, fromAmount = amount.toStringWithRightOffset(), fromDecimals = amount.decimals, - providerId = providerId, + providerId = swapProvider.providerId, rateType = RateType.FLOAT, toAddress = currencyToGet.value.networkAddress?.defaultAddress ?: "", ) @@ -501,14 +505,17 @@ internal class SwapInteractorImpl @Inject constructor( network = currencyToSend.currency.network, ) - return result.fold(ifLeft = { - when (it) { - is SendTransactionError.NetworkError -> TxState.NetworkError - is SendTransactionError.DataError -> TxState.BlockchainError - SendTransactionError.DemoCardError -> TxState.UnknownError - else -> TxState.UnknownError - } - }, ifRight = { + return result.fold( + ifLeft = { + when (it) { + is SendTransactionError.NetworkError -> TxState.NetworkError + is SendTransactionError.DataError -> TxState.BlockchainError + SendTransactionError.DemoCardError -> TxState.UnknownError + else -> TxState.UnknownError + } + }, + ifRight = { + val timestamp = System.currentTimeMillis() TxState.TxSent( fromAmount = amountFormatter.formatSwapAmountToUI( amount, @@ -521,9 +528,11 @@ internal class SwapInteractorImpl @Inject constructor( txAddress = userWalletManager.getLastTransactionHash( currencyToSend.currency.network.backendId, derivationPath, - ) ?: "", + ).orEmpty(), + timestamp = timestamp, ) - },) + }, + ) } @Deprecated("used in old swap mechanism") diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt index ca95f626e3..0a0f5b5b2a 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/TxState.kt @@ -6,6 +6,7 @@ sealed class TxState { val fromAmount: String? = null, val toAmount: String? = null, val txAddress: String, + val timestamp: Long, ) : TxState() object UserCancelled : TxState() diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt index 640c4809d3..814723462c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt @@ -2,14 +2,15 @@ package com.tangem.feature.swap.models import com.tangem.core.ui.components.currency.tokenicon.TokenIconState import com.tangem.core.ui.extensions.TextReference -import com.tangem.feature.swap.domain.models.domain.SwapProvider data class SwapSuccessStateHolder( val timestamp: Long, val txUrl: String, val fee: TextReference, val rate: TextReference, - val selectedProvider: SwapProvider, + val providerName: TextReference, + val providerType: TextReference, + val providerIcon: String, val fromTokenAmount: TextReference, val toTokenAmount: TextReference, val fromTokenFiatAmount: TextReference, 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 7d965aa10f..3d230f08a8 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 @@ -20,7 +20,6 @@ import com.tangem.feature.swap.domain.models.ui.* import com.tangem.feature.swap.models.* import com.tangem.feature.swap.models.states.* import com.tangem.feature.swap.presentation.R -import com.tangem.feature.swap.viewmodels.SwapProcessDataState import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import java.math.BigDecimal @@ -459,39 +458,37 @@ internal class StateBuilder( ) } + @Suppress("LongParameterList") fun createSuccessState( uiState: SwapStateHolder, txState: TxState.TxSent, - dataState: SwapProcessDataState, + fromAmount: BigDecimal, + toAmount: BigDecimal, txUrl: String, onSecondaryBtnClick: () -> Unit, ): SwapStateHolder { - val fromToken = requireNotNull(uiState.sendCardData as? SwapCardState.SwapCardData) - val toToken = requireNotNull(uiState.receiveCardData as? SwapCardState.SwapCardData) - val fromTokenIconState = fromToken.token?.let(iconStateConverter::convert) - val toTokenIconState = toToken.token?.let(iconStateConverter::convert) + val providerState = uiState.providerState as ProviderState.Content + val fromToken = requireNotNull((uiState.sendCardData as? SwapCardState.SwapCardData)?.token) + val toToken = requireNotNull((uiState.receiveCardData as? SwapCardState.SwapCardData)?.token) + val fromTokenIconState = iconStateConverter.convert(fromToken) + val toTokenIconState = iconStateConverter.convert(toToken) val fee = uiState.fee as? FeeItemState.Content ?: return uiState - val fromCryptoCurrencyStatus = requireNotNull(fromToken.token) - val toCryptoCurrencyStatus = requireNotNull(toToken.token) - val rate = txState.toAmount?.toBigDecimal()?.divide( - txState.fromAmount?.toBigDecimal(), - toCryptoCurrencyStatus.currency.decimals, - RoundingMode.HALF_UP, - ) - val fromCurrencySymbol = fromCryptoCurrencyStatus.currency.symbol - val toCurrencySymbol = toCryptoCurrencyStatus.currency.symbol + val fromFiatAmount = getFormattedFiatAmount(fromToken.value.fiatRate?.multiply(fromAmount)) + val toFiatAmount = getFormattedFiatAmount(toToken.value.fiatRate?.multiply(toAmount)) return uiState.copy( successState = SwapSuccessStateHolder( - timestamp = System.currentTimeMillis(), + timestamp = txState.timestamp, txUrl = txUrl, - selectedProvider = requireNotNull(dataState.selectedProvider), + providerName = TextReference.Str(providerState.name), + providerType = TextReference.Str(providerState.type), + providerIcon = providerState.iconUrl, fee = TextReference.Str("${fee.amountCrypto} ${fee.symbolCrypto} (${fee.amountFiatFormatted})"), - rate = TextReference.Str("1 $fromCurrencySymbol ≈ $rate $toCurrencySymbol"), - fromTokenAmount = TextReference.Str("${txState.fromAmount.orEmpty()} ${fromToken.tokenCurrency}}"), - toTokenAmount = TextReference.Str("${txState.toAmount.orEmpty()} ${toToken.tokenCurrency}}"), - fromTokenFiatAmount = TextReference.Str(fromToken.amountEquivalent.orEmpty()), - toTokenFiatAmount = TextReference.Str(toToken.amountEquivalent.orEmpty()), + rate = TextReference.Str(providerState.rate), + fromTokenAmount = TextReference.Str(txState.fromAmount.orEmpty()), + toTokenAmount = TextReference.Str(txState.toAmount.orEmpty()), + fromTokenFiatAmount = TextReference.Str(fromFiatAmount), + toTokenFiatAmount = TextReference.Str(toFiatAmount), fromTokenIconState = fromTokenIconState, toTokenIconState = toTokenIconState, onSecondaryButtonClick = onSecondaryBtnClick, @@ -892,7 +889,7 @@ internal class StateBuilder( return BigDecimalFormatter.formatFiatAmount(fiatAmount, appCurrency.code, appCurrency.symbol) } - private fun getFormattedFiatAmount(amount: BigDecimal): String { + private fun getFormattedFiatAmount(amount: BigDecimal?): String { val appCurrency = appCurrencyProvider() return BigDecimalFormatter.formatFiatAmount(amount, appCurrency.code, appCurrency.symbol) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt index 909239af13..ffb9334830 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt @@ -23,7 +23,6 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.shareText import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.domain.models.domain.ExchangeProviderType -import com.tangem.feature.swap.domain.models.domain.SwapProvider import com.tangem.feature.swap.models.SwapSuccessStateHolder import com.tangem.feature.swap.presentation.R @@ -60,7 +59,7 @@ private fun SwapSuccessScreenContent(state: SwapSuccessStateHolder, padding: Pad .background(TangemTheme.colors.background.secondary) .padding(horizontal = TangemTheme.dimens.spacing16), ) { - TransactionDoneTitle(titleRes = R.string.swapping_success_view_title, date = 0L) + TransactionDoneTitle(titleRes = R.string.swapping_success_view_title, date = state.timestamp) SpacerH16() InputRowImage( title = TextReference.Res(R.string.swapping_success_from_title), @@ -83,9 +82,9 @@ private fun SwapSuccessScreenContent(state: SwapSuccessStateHolder, padding: Pad ) SpacerH16() InputRowBestRate( - imageUrl = state.selectedProvider.imageLarge, - title = TextReference.Str(state.selectedProvider.name), - titleExtra = TextReference.Str(state.selectedProvider.type.name), + imageUrl = state.providerIcon, + title = state.providerName, + titleExtra = state.providerType, subtitle = state.rate, modifier = Modifier .clip(TangemTheme.shapes.roundedCornersXMedium) @@ -153,13 +152,9 @@ private val state = SwapSuccessStateHolder( timestamp = 0L, txUrl = "https://www.google.com/#q=nam", fee = TextReference.Str("1 000 DAI ~ 1 000 MATIC"), - selectedProvider = SwapProvider( - providerId = "1inch", - rateTypes = listOf(), - name = "1inch", - type = ExchangeProviderType.DEX, - imageLarge = "", - ), + providerName = TextReference.Str("1inch"), + providerType = TextReference.Str(ExchangeProviderType.DEX.name), + providerIcon = "", fromTokenAmount = TextReference.Str("1 000 DAI"), toTokenAmount = TextReference.Str("1 000 MATIC"), fromTokenFiatAmount = TextReference.Str("1 000 $"), 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 a577a98dfe..9c25f78b14 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 @@ -27,9 +27,7 @@ import com.tangem.feature.swap.presentation.SwapFragment import com.tangem.feature.swap.router.SwapNavScreen import com.tangem.feature.swap.router.SwapRouter import com.tangem.feature.swap.ui.StateBuilder -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import com.tangem.utils.coroutines.Debouncer -import com.tangem.utils.coroutines.runCatching +import com.tangem.utils.coroutines.* import com.tangem.utils.isNullOrZero import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.* @@ -401,7 +399,8 @@ internal class SwapViewModel @Inject constructor( uiState = stateBuilder.createSuccessState( uiState = uiState, txState = it, - dataState = dataState, + fromAmount = dataState.amount?.toBigDecimal() ?: BigDecimal.ZERO, + toAmount = dataState.swapDataModel?.toTokenAmount?.value ?: BigDecimal.ZERO, txUrl = url, onSecondaryBtnClick = { val txHash = it.txAddress