Updated on 2026-08-14
This commit is contained in:
commit
c32a5fa18d
711 changed files with 18558 additions and 4312 deletions
|
|
@ -45,19 +45,19 @@ internal class DefaultSwapAmountUpdateTrigger @Inject constructor() :
|
|||
SwapAmountReduceListener {
|
||||
|
||||
override val updateAmountTriggerFlow: SharedFlow<Pair<String, Boolean>>
|
||||
field = MutableSharedFlow<Pair<String, Boolean>>()
|
||||
field = MutableSharedFlow<Pair<String, Boolean>>()
|
||||
|
||||
override val reduceToTriggerFlow: SharedFlow<BigDecimal>
|
||||
field = MutableSharedFlow<BigDecimal>()
|
||||
field = MutableSharedFlow<BigDecimal>()
|
||||
|
||||
override val reduceByTriggerFlow: SharedFlow<ReduceByData>
|
||||
field = MutableSharedFlow<ReduceByData>()
|
||||
field = MutableSharedFlow<ReduceByData>()
|
||||
|
||||
override val ignoreReduceTriggerFlow: SharedFlow<Unit>
|
||||
field = MutableSharedFlow<Unit>()
|
||||
field = MutableSharedFlow<Unit>()
|
||||
|
||||
override val reloadQuotesTriggerFlow: Flow<Unit>
|
||||
field = MutableSharedFlow<Unit>()
|
||||
field = MutableSharedFlow<Unit>()
|
||||
|
||||
override suspend fun triggerUpdateAmount(amountValue: String, isEnterInFiatSelected: Boolean) {
|
||||
updateAmountTriggerFlow.emit(amountValue to isEnterInFiatSelected)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.swap.models.SwapDirection
|
||||
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
||||
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
|
||||
import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -15,6 +16,7 @@ internal sealed class SwapAmountComponentParams {
|
|||
|
||||
abstract val amountUM: SwapAmountUM
|
||||
abstract val analyticsCategoryName: String
|
||||
abstract val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource
|
||||
abstract val userWallet: UserWallet
|
||||
abstract val swapDirection: SwapDirection
|
||||
abstract val isBalanceHidingFlow: StateFlow<Boolean>
|
||||
|
|
@ -31,6 +33,7 @@ internal sealed class SwapAmountComponentParams {
|
|||
override val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
|
||||
override val secondaryCryptoCurrency: CryptoCurrency?,
|
||||
override val filterProviderTypes: List<ExpressProviderType> = emptyList(),
|
||||
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
|
||||
val title: TextReference,
|
||||
val callback: SwapAmountComponent.ModelCallback,
|
||||
val currentRoute: Flow<SendWithSwapRoute>,
|
||||
|
|
@ -45,6 +48,7 @@ internal sealed class SwapAmountComponentParams {
|
|||
override val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
|
||||
override val secondaryCryptoCurrency: CryptoCurrency?,
|
||||
override val filterProviderTypes: List<ExpressProviderType> = emptyList(),
|
||||
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
|
||||
val blockClickEnableFlow: StateFlow<Boolean>,
|
||||
) : SwapAmountComponentParams()
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
private var showBestRateAnimation: Boolean = false
|
||||
|
||||
val uiState: StateFlow<SwapAmountUM>
|
||||
field = MutableStateFlow(params.amountUM)
|
||||
field = MutableStateFlow(params.amountUM)
|
||||
|
||||
private val amountDebouncer = Debouncer()
|
||||
private val quoteTaskScheduler = SingleTaskScheduler<Unit>()
|
||||
|
|
@ -224,6 +224,7 @@ internal class SwapAmountModel @Inject constructor(
|
|||
categoryName = params.analyticsCategoryName,
|
||||
token = primaryCryptoCurrency.symbol,
|
||||
blockchain = primaryCryptoCurrency.network.name,
|
||||
source = params.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
uiState.transformerUpdate(
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ internal class SwapChooseProviderModel @Inject constructor(
|
|||
}
|
||||
|
||||
val uiState: StateFlow<SwapChooseProviderBottomSheetContent>
|
||||
field: MutableStateFlow<SwapChooseProviderBottomSheetContent> = MutableStateFlow(getInitialState())
|
||||
field: MutableStateFlow<SwapChooseProviderBottomSheetContent> = MutableStateFlow(getInitialState())
|
||||
|
||||
fun onProviderClick(quoteUM: SwapQuoteUM) {
|
||||
params.callback.onProviderResult(quoteUM)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ internal class DefaultSwapChooseTokenNetworkTrigger @Inject constructor() :
|
|||
SwapChooseTokenNetworkListener {
|
||||
|
||||
override val swapChooseTokenNetworkResultFlow: SharedFlow<SwapChooseTokenTriggerData>
|
||||
field = MutableSharedFlow<SwapChooseTokenTriggerData>()
|
||||
field = MutableSharedFlow<SwapChooseTokenTriggerData>()
|
||||
|
||||
override suspend fun trigger(
|
||||
swapCurrencies: SwapCurrencies,
|
||||
|
|
|
|||
|
|
@ -46,20 +46,20 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
|
|||
private val params: SwapChooseTokenNetworkComponent.Params = paramsContainer.require()
|
||||
|
||||
val uiState: StateFlow<SwapChooseTokenNetworkUM>
|
||||
field: MutableStateFlow<SwapChooseTokenNetworkUM> = MutableStateFlow(
|
||||
SwapChooseTokenNetworkUM(
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = params.onDismiss,
|
||||
content = SwapChooseTokenNetworkContentUM.Loading(
|
||||
messageContent = getErrorMessage(
|
||||
tokenName = params.token.name,
|
||||
onDismiss = params.onDismiss,
|
||||
field: MutableStateFlow<SwapChooseTokenNetworkUM> = MutableStateFlow(
|
||||
SwapChooseTokenNetworkUM(
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = params.onDismiss,
|
||||
content = SwapChooseTokenNetworkContentUM.Loading(
|
||||
messageContent = getErrorMessage(
|
||||
tokenName = params.token.name,
|
||||
onDismiss = params.onDismiss,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
init {
|
||||
initContent()
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ internal class DefaultSwapNotificationsUpdateTrigger @Inject constructor() :
|
|||
SwapNotificationsUpdateTrigger {
|
||||
|
||||
override val updateTriggerFlow: SharedFlow<SwapNotificationData>
|
||||
field = MutableSharedFlow<SwapNotificationData>()
|
||||
field = MutableSharedFlow<SwapNotificationData>()
|
||||
|
||||
override val hasErrorFlow: SharedFlow<Boolean>
|
||||
field = MutableSharedFlow<Boolean>()
|
||||
field = MutableSharedFlow<Boolean>()
|
||||
|
||||
override suspend fun callbackHasError(hasError: Boolean) {
|
||||
hasErrorFlow.emit(hasError)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ internal class SwapNotificationsModel @Inject constructor(
|
|||
private var notificationData = params.swapNotificationData
|
||||
|
||||
val uiState: StateFlow<ImmutableList<NotificationUM>>
|
||||
field = MutableStateFlow<ImmutableList<NotificationUM>>(persistentListOf())
|
||||
field = MutableStateFlow<ImmutableList<NotificationUM>>(persistentListOf())
|
||||
|
||||
init {
|
||||
subscribeToNotificationUpdateTrigger()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.decompose.getEmptyComposableContentComponent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.swap.models.R
|
||||
import com.tangem.domain.swap.models.SwapDirection
|
||||
|
|
@ -85,13 +84,19 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
|
|||
when (val activeComponent = stack.active.instance) {
|
||||
is SwapAmountComponent -> {
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.AmountScreenOpened(categoryName = model.analyticCategoryName),
|
||||
CommonSendAnalyticEvents.AmountScreenOpened(
|
||||
categoryName = model.analyticCategoryName,
|
||||
source = model.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
activeComponent.updateState(model.uiState.value.amountUM)
|
||||
}
|
||||
is SendDestinationComponent -> {
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.AddressScreenOpened(categoryName = model.analyticCategoryName),
|
||||
CommonSendAnalyticEvents.AddressScreenOpened(
|
||||
categoryName = model.analyticCategoryName,
|
||||
source = model.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
activeComponent.updateState(model.uiState.value.destinationUM)
|
||||
}
|
||||
|
|
@ -99,6 +104,7 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
|
|||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.ConfirmationScreenOpened(
|
||||
categoryName = model.analyticCategoryName,
|
||||
source = model.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
if (model.currentRoute.value.isEditMode) {
|
||||
|
|
@ -146,15 +152,16 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
|
|||
callback = model,
|
||||
userWallet = model.userWallet,
|
||||
filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES,
|
||||
analyticsSendSource = model.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getDestinationComponent(factoryContext: AppComponentContext): ComposableContentComponent {
|
||||
val amountContentUM = model.uiState.value.amountUM as? SwapAmountUM.Content
|
||||
?: return getEmptyComposableContentComponent()
|
||||
?: return ComposableContentComponent.EMPTY
|
||||
val secondaryCryptoCurrency = amountContentUM.secondaryCryptoCurrencyStatus?.currency
|
||||
?: return getEmptyComposableContentComponent()
|
||||
?: return ComposableContentComponent.EMPTY
|
||||
|
||||
return sendDestinationComponentFactory.create(
|
||||
context = factoryContext,
|
||||
|
|
@ -163,6 +170,7 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
|
|||
currentRoute = model.currentRoute.filterIsInstance<DestinationRoute>(),
|
||||
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
||||
analyticsCategoryName = model.analyticCategoryName,
|
||||
analyticsSendSource = model.analyticsSendSource,
|
||||
title = resourceReference(R.string.common_address),
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = secondaryCryptoCurrency,
|
||||
|
|
@ -184,6 +192,7 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
|
|||
analyticsCategoryName = model.analyticCategoryName,
|
||||
primaryCryptoCurrencyStatusFlow = model.primaryCryptoCurrencyStatusFlow,
|
||||
primaryFeePaidCurrencyStatusFlow = model.primaryFeePaidCurrencyStatusFlow,
|
||||
analyticsSendSource = model.analyticsSendSource,
|
||||
swapDirection = SwapDirection.Direct,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.swap.models.SwapDirection
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
import com.tangem.features.send.v2.api.SendNotificationsComponent
|
||||
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
||||
import com.tangem.features.send.v2.api.entity.PredefinedValues
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams.*
|
||||
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationBlockComponent
|
||||
|
|
@ -62,6 +63,7 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
|
|||
isBalanceHidingFlow = params.isBalanceHidingFlow,
|
||||
swapDirection = params.swapDirection,
|
||||
filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES,
|
||||
analyticsSendSource = params.analyticsSendSource,
|
||||
),
|
||||
onResult = model::onAmountResult,
|
||||
onClick = model::showEditAmount,
|
||||
|
|
@ -72,6 +74,7 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
|
|||
params = SendDestinationComponentParams.DestinationBlockParams(
|
||||
state = model.uiState.value.destinationUM,
|
||||
analyticsCategoryName = params.analyticsCategoryName,
|
||||
analyticsSendSource = params.analyticsSendSource,
|
||||
userWalletId = params.userWallet.walletId,
|
||||
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
|
||||
cryptoCurrency = model.secondaryCurrency,
|
||||
|
|
@ -91,6 +94,7 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
|
|||
feeStateConfiguration = FeeStateConfiguration.ExcludeLow,
|
||||
feeDisplaySource = FeeDisplaySource.Screen,
|
||||
analyticsCategoryName = params.analyticsCategoryName,
|
||||
analyticsSendSource = params.analyticsSendSource,
|
||||
),
|
||||
onResult = model::onFeeResult,
|
||||
)
|
||||
|
|
@ -166,6 +170,7 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
|
|||
data class Params(
|
||||
val sendWithSwapUM: SendWithSwapUM,
|
||||
val analyticsCategoryName: String,
|
||||
val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
|
||||
val userWallet: UserWallet,
|
||||
val appCurrency: AppCurrency,
|
||||
val currentRoute: Flow<SendWithSwapRoute>,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
|
|||
private val params: SendWithSwapConfirmComponent.Params = paramsContainer.require()
|
||||
|
||||
val uiState: StateFlow<SendWithSwapUM>
|
||||
field = MutableStateFlow(params.sendWithSwapUM)
|
||||
field = MutableStateFlow(params.sendWithSwapUM)
|
||||
|
||||
val primaryCurrencyStatus: CryptoCurrencyStatus = params.primaryCryptoCurrencyStatusFlow.value
|
||||
val secondaryCurrencyStatus: CryptoCurrencyStatus? = amountUM?.secondaryCryptoCurrencyStatus
|
||||
|
|
@ -227,7 +227,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
|
|||
estimateFeeUseCase(
|
||||
amount = amountValue,
|
||||
userWallet = params.userWallet,
|
||||
cryptoCurrency = primaryCurrencyStatus.currency,
|
||||
cryptoCurrencyStatus = primaryCurrencyStatus,
|
||||
).map {
|
||||
it.patchTransactionFeeForSwap(INCREASE_GAS_LIMIT_FOR_CEX)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ internal class SwapTransactionSender @AssistedInject constructor(
|
|||
}
|
||||
|
||||
val txData = createTransferTransactionUseCase(
|
||||
amount = fromAmount.convertToSdkAmount(fromStatus.currency),
|
||||
amount = fromAmount.convertToSdkAmount(fromStatus),
|
||||
fee = fee,
|
||||
memo = swapTransaction.txExtraId,
|
||||
destination = swapTransaction.txTo,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ internal class SendWithSwapModel @Inject constructor(
|
|||
private val params: SendWithSwapComponent.Params = paramsContainer.require()
|
||||
|
||||
val analyticCategoryName = CommonSendAnalyticEvents.SEND_CATEGORY
|
||||
val analyticsSendSource = CommonSendAnalyticEvents.CommonSendSource.SendWithSwap
|
||||
val initialRoute = SendWithSwapRoute.Amount(false)
|
||||
val currentRoute = MutableStateFlow<SendWithSwapRoute>(initialRoute)
|
||||
|
||||
|
|
@ -67,26 +68,26 @@ internal class SendWithSwapModel @Inject constructor(
|
|||
var appCurrency: AppCurrency = AppCurrency.Default
|
||||
|
||||
val uiState: StateFlow<SendWithSwapUM>
|
||||
field = MutableStateFlow(initialState())
|
||||
field = MutableStateFlow(initialState())
|
||||
|
||||
val isBalanceHiddenFlow: StateFlow<Boolean>
|
||||
field = MutableStateFlow(false)
|
||||
field = MutableStateFlow(false)
|
||||
|
||||
val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
|
||||
field = MutableStateFlow(
|
||||
CryptoCurrencyStatus(
|
||||
currency = params.currency,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
),
|
||||
)
|
||||
field = MutableStateFlow(
|
||||
CryptoCurrencyStatus(
|
||||
currency = params.currency,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
),
|
||||
)
|
||||
|
||||
val primaryFeePaidCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
|
||||
field = MutableStateFlow(
|
||||
CryptoCurrencyStatus(
|
||||
currency = params.currency,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
),
|
||||
)
|
||||
field = MutableStateFlow(
|
||||
CryptoCurrencyStatus(
|
||||
currency = params.currency,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
),
|
||||
)
|
||||
|
||||
init {
|
||||
initUserWallet()
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ internal class SendWithSwapSuccessModel @Inject constructor(
|
|||
iconRes = R.drawable.ic_web_24,
|
||||
onClick = ::onExploreClick,
|
||||
) to NavigationButton(
|
||||
textReference = resourceReference(R.string.common_share),
|
||||
iconRes = R.drawable.ic_share_24,
|
||||
onClick = ::onShareClick,
|
||||
)).takeUnless { confirmUM?.txUrl.isNullOrBlank() },
|
||||
textReference = resourceReference(R.string.common_share),
|
||||
iconRes = R.drawable.ic_share_24,
|
||||
onClick = ::onShareClick,
|
||||
)).takeUnless { confirmUM?.txUrl.isNullOrBlank() },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ private fun SendWithSwapSuccessContent_Preview() {
|
|||
fees = TransactionFee.Single(
|
||||
normal = Fee.Common(
|
||||
BigDecimal.ONE.convertToSdkAmount(
|
||||
SwapAmountContentPreview.cryptoCurrencyStatus.currency,
|
||||
SwapAmountContentPreview.cryptoCurrencyStatus,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -315,7 +315,7 @@ private fun SendWithSwapSuccessContent_Preview() {
|
|||
selectedFeeItem = FeeItem.Market(
|
||||
Fee.Common(
|
||||
BigDecimal.ONE.convertToSdkAmount(
|
||||
SwapAmountContentPreview.cryptoCurrencyStatus.currency,
|
||||
SwapAmountContentPreview.cryptoCurrencyStatus,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue