Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-30 14:23:50 +03:00
commit c32a5fa18d
711 changed files with 18558 additions and 4312 deletions

View file

@ -51,6 +51,7 @@ internal class DefaultFeeSelectorBlockComponent @AssistedInject constructor(
feeStateConfiguration = params.feeStateConfiguration,
feeDisplaySource = FeeSelectorParams.FeeDisplaySource.Screen,
analyticsCategoryName = params.analyticsCategoryName,
analyticsSendSource = params.analyticsSendSource,
),
onDismiss = {
model.feeSelectorBottomSheet.dismiss()

View file

@ -18,16 +18,16 @@ internal class DefaultFeeSelectorReloadTrigger @Inject constructor() :
FeeSelectorCheckReloadListener {
override val reloadTriggerFlow: SharedFlow<FeeSelectorData>
field = MutableSharedFlow()
field = MutableSharedFlow()
override val loadingStateTriggerFlow: SharedFlow<Unit>
field = MutableSharedFlow()
field = MutableSharedFlow()
override val checkReloadTriggerFlow: SharedFlow<Unit>
field = MutableSharedFlow()
field = MutableSharedFlow()
override val checkReloadResultFlow: SharedFlow<Boolean>
field = MutableSharedFlow()
field = MutableSharedFlow()
override suspend fun triggerUpdate(feeData: FeeSelectorData) {
reloadTriggerFlow.emit(feeData)

View file

@ -29,6 +29,7 @@ import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorRelo
import com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics.CommonSendFeeAnalyticEvents
import com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics.CommonSendFeeAnalyticEvents.GasPriceInserter
import com.tangem.features.send.v2.feeselector.model.transformers.*
import com.tangem.utils.TangemLinks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.MutableStateFlow
@ -36,7 +37,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.util.Locale
import javax.inject.Inject
@Suppress("LongParameterList")
@ -62,7 +62,7 @@ internal class FeeSelectorModel @Inject constructor(
val feeSelectorBottomSheet = SlotNavigation<Unit>()
val uiState: StateFlow<FeeSelectorUM>
field = MutableStateFlow<FeeSelectorUM>(params.state)
field = MutableStateFlow<FeeSelectorUM>(params.state)
init {
initAppCurrency()
@ -77,13 +77,7 @@ internal class FeeSelectorModel @Inject constructor(
}
fun onReadMoreClicked() {
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
val url = buildString {
append(FEE_READ_MORE_URL_FIRST_PART)
append(locale)
append(FEE_READ_MORE_URL_SECOND_PART)
}
urlOpener.openUrl(url)
urlOpener.openUrl(TangemLinks.FEE_BLOG_LINK)
}
private fun initAppCurrency() {
@ -156,6 +150,7 @@ internal class FeeSelectorModel @Inject constructor(
CommonSendFeeAnalyticEvents.SelectedFee(
categoryName = params.analyticsCategoryName,
feeType = feeSelectorUM.toAnalyticType(),
source = params.analyticsSendSource,
),
)
val isCustomFeeEdited = feeSelectorUM.selectedFeeItem.fee.amount.value != feeSelectorUM.fees.normal.amount.value
@ -182,7 +177,10 @@ internal class FeeSelectorModel @Inject constructor(
fun showFeeSelector() {
analyticsEventHandler.send(
CommonSendAnalyticEvents.FeeScreenOpened(categoryName = params.analyticsCategoryName),
CommonSendAnalyticEvents.FeeScreenOpened(
categoryName = params.analyticsCategoryName,
source = params.analyticsSendSource,
),
)
analyticsEventHandler.send(
CommonSendAnalyticEvents.ScreenReopened(
@ -245,11 +243,4 @@ internal class FeeSelectorModel @Inject constructor(
)
}
}
private companion object {
const val RU_LOCALE = "ru"
const val EN_LOCALE = "en"
const val FEE_READ_MORE_URL_FIRST_PART = "https://tangem.com/"
const val FEE_READ_MORE_URL_SECOND_PART = "/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/"
}
}

View file

@ -93,6 +93,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
analyticsEventHandler.send(
CommonSendAnalyticEvents.ConfirmationScreenOpened(
categoryName = model.analyticCategoryName,
source = model.analyticsSendSource,
),
)
if (model.currentRoute.value.isEditMode) {
@ -101,19 +102,28 @@ internal class DefaultSendComponent @AssistedInject constructor(
}
is SendAmountComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.AmountScreenOpened(categoryName = model.analyticCategoryName),
CommonSendAnalyticEvents.AmountScreenOpened(
categoryName = model.analyticCategoryName,
source = model.analyticsSendSource,
),
)
activeComponent.updateState(model.uiState.value.amountUM)
}
is DefaultSendDestinationComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.AddressScreenOpened(categoryName = model.analyticCategoryName),
CommonSendAnalyticEvents.AddressScreenOpened(
categoryName = model.analyticCategoryName,
source = model.analyticsSendSource,
),
)
activeComponent.updateState(model.uiState.value.destinationUM)
}
is SendFeeComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.FeeScreenOpened(categoryName = model.analyticCategoryName),
CommonSendAnalyticEvents.FeeScreenOpened(
categoryName = model.analyticCategoryName,
source = model.analyticsSendSource,
),
)
}
}
@ -155,6 +165,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
currentRoute = model.currentRoute.filterIsInstance<CommonSendRoute.Destination>(),
isBalanceHidingFlow = model.isBalanceHiddenFlow,
analyticsCategoryName = model.analyticCategoryName,
analyticsSendSource = model.analyticsSendSource,
title = resourceReference(R.string.common_address),
userWalletId = params.userWalletId,
cryptoCurrency = params.currency,
@ -177,6 +188,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
callback = model,
predefinedValues = model.predefinedValues,
isRedesignEnabled = model.uiState.value.isRedesignEnabled,
analyticsSendSource = model.analyticsSendSource,
),
)
}
@ -204,6 +216,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
sendAmount = sendAmount,
destinationAddress = destinationAddress,
callback = model,
analyticsSendSource = model.analyticsSendSource,
),
)
} else {
@ -238,6 +251,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
onSendTransaction = {
innerRouter.replaceAll(CommonSendRoute.ConfirmSuccess)
},
analyticsSendSource = model.analyticsSendSource,
),
feeSelectorComponentFactory = feeSelectorComponentFactory,
)
@ -268,6 +282,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
params = SendDestinationComponentParams.DestinationBlockParams(
state = model.uiState.value.destinationUM,
analyticsCategoryName = model.analyticCategoryName,
analyticsSendSource = model.analyticsSendSource,
userWalletId = model.userWallet.walletId,
cryptoCurrency = cryptoCurrencyStatus.currency,
blockClickEnableFlow = MutableStateFlow(true),

View file

@ -17,6 +17,7 @@ import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.SendNotificationsComponent
import com.tangem.features.send.v2.api.SendNotificationsComponent.Params.NotificationData
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.SendDestinationComponentParams.DestinationBlockParams
@ -50,6 +51,7 @@ internal class SendConfirmComponent(
params = DestinationBlockParams(
state = model.uiState.value.destinationUM,
analyticsCategoryName = params.analyticsCategoryName,
analyticsSendSource = params.analyticsSendSource,
userWalletId = params.userWallet.walletId,
cryptoCurrency = params.cryptoCurrencyStatus.currency,
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
@ -73,6 +75,7 @@ internal class SendConfirmComponent(
cryptoCurrency = params.cryptoCurrencyStatus.currency,
cryptoCurrencyStatusFlow = params.cryptoCurrencyStatusFlow,
isBalanceHidingFlow = params.isBalanceHidingFlow,
analyticsSendSource = params.analyticsSendSource,
),
onResult = model::onAmountResult,
onClick = model::showEditAmount,
@ -90,6 +93,7 @@ internal class SendConfirmComponent(
sendAmount = model.confirmData.enteredAmount.orZero(),
destinationAddress = model.confirmData.enteredDestination.orEmpty(),
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
analyticsSendSource = params.analyticsSendSource,
onLoadFee = params.onLoadFee,
),
onResult = model::onFeeResult,
@ -106,6 +110,7 @@ internal class SendConfirmComponent(
feeStateConfiguration = model.feeStateConfiguration,
feeDisplaySource = FeeSelectorParams.FeeDisplaySource.Screen,
analyticsCategoryName = params.analyticsCategoryName,
analyticsSendSource = params.analyticsSendSource,
),
onResult = model::onFeeResult,
)
@ -165,6 +170,7 @@ internal class SendConfirmComponent(
data class Params(
val state: SendUM,
val analyticsCategoryName: String,
val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val userWallet: UserWallet,
val cryptoCurrencyStatus: CryptoCurrencyStatus,
val feeCryptoCurrencyStatus: CryptoCurrencyStatus,

View file

@ -127,7 +127,7 @@ internal class SendConfirmModel @Inject constructor(
val uiState = _uiState.asStateFlow()
val isBalanceHiddenFlow: StateFlow<Boolean>
field = MutableStateFlow(false)
field = MutableStateFlow(false)
private val amountState
get() = uiState.value.amountUM as? AmountState.Data
@ -317,7 +317,7 @@ internal class SendConfirmModel @Inject constructor(
null
}
val amount = receivingAmount?.convertToSdkAmount(cryptoCurrency)
val amount = receivingAmount?.convertToSdkAmount(cryptoCurrencyStatus)
saveBlockchainErrorUseCase(
error = BlockchainErrorInfo(
@ -331,7 +331,7 @@ internal class SendConfirmModel @Inject constructor(
""
},
amount = amount?.value?.stripZeroPlainString() ?: "unknown",
fee = feeValue?.convertToSdkAmount(cryptoCurrency)
fee = feeValue?.convertToSdkAmount(cryptoCurrencyStatus)
?.value?.stripZeroPlainString() ?: "unknown",
),
)
@ -424,7 +424,7 @@ internal class SendConfirmModel @Inject constructor(
modelScope.launch {
createTransferTransactionUseCase(
amount = receivingAmount.convertToSdkAmount(cryptoCurrency),
amount = receivingAmount.convertToSdkAmount(cryptoCurrencyStatus),
fee = fee,
memo = memo,
nonce = nonce,

View file

@ -104,12 +104,13 @@ internal class SendModel @Inject constructor(
private val cryptoCurrency = params.currency
val analyticCategoryName = CommonSendAnalyticEvents.SEND_CATEGORY
val analyticsSendSource = CommonSendAnalyticEvents.CommonSendSource.Send
val uiState: StateFlow<SendUM>
field = MutableStateFlow(initialState())
field = MutableStateFlow(initialState())
val isBalanceHiddenFlow: StateFlow<Boolean>
field = MutableStateFlow(false)
field = MutableStateFlow(false)
val initialRoute = if (params.amount == null) {
if (uiState.value.isRedesignEnabled) {
@ -260,10 +261,11 @@ internal class SendModel @Inject constructor(
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
val predefinedValues = predefinedValues
val cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value
val transferTransaction = if (predefinedValues is PredefinedValues.Content.Deeplink) {
val predefinedAmount = predefinedValues.amount.parseBigDecimalOrNull()?.convertToSdkAmount(cryptoCurrency)
val predefinedAmount = predefinedValues.amount.parseBigDecimalOrNull()
createTransferTransactionUseCase(
amount = predefinedAmount ?: error("Invalid amount"),
amount = predefinedAmount?.convertToSdkAmount(cryptoCurrencyStatus) ?: error("Invalid amount"),
memo = predefinedValues.memo,
destination = predefinedValues.address,
userWalletId = userWallet.walletId,
@ -277,7 +279,7 @@ internal class SendModel @Inject constructor(
val enteredAmount = amountUM.amountTextField.cryptoAmount.value ?: error("Invalid amount")
createTransferTransactionUseCase(
amount = enteredAmount.convertToSdkAmount(cryptoCurrency),
amount = enteredAmount.convertToSdkAmount(cryptoCurrencyStatus),
memo = enteredMemo,
destination = enteredDestinationAddress,
userWalletId = userWallet.walletId,

View file

@ -81,10 +81,10 @@ internal class SendConfirmSuccessModel @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,
)).takeIf { params.txUrl.isNotEmpty() },
textReference = resourceReference(R.string.common_share),
iconRes = R.drawable.ic_share_24,
onClick = ::onShareClick,
)).takeIf { params.txUrl.isNotEmpty() },
),
),
)

View file

@ -49,6 +49,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
private val stackNavigation = StackNavigation<CommonSendRoute>()
private val analyticsCategoryName = CommonSendAnalyticEvents.NFT_SEND_CATEGORY
private val analyticsSendSource = CommonSendAnalyticEvents.CommonSendSource.NFT
private val innerRouter = InnerRouter<CommonSendRoute>(
stackNavigation = stackNavigation,
@ -83,7 +84,10 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
when (val activeComponent = stack.active.instance) {
is NFTSendConfirmComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.ConfirmationScreenOpened(categoryName = analyticsCategoryName),
CommonSendAnalyticEvents.ConfirmationScreenOpened(
categoryName = analyticsCategoryName,
source = analyticsSendSource,
),
)
if (model.currentRouteFlow.value.isEditMode) {
activeComponent.updateState(model.uiState.value)
@ -91,13 +95,19 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
}
is DefaultSendDestinationComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.AddressScreenOpened(categoryName = analyticsCategoryName),
CommonSendAnalyticEvents.AddressScreenOpened(
categoryName = analyticsCategoryName,
source = analyticsSendSource,
),
)
activeComponent.updateState(model.uiState.value.destinationUM)
}
is SendFeeComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.FeeScreenOpened(categoryName = analyticsCategoryName),
CommonSendAnalyticEvents.FeeScreenOpened(
categoryName = analyticsCategoryName,
source = analyticsSendSource,
),
)
}
}
@ -135,6 +145,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
isBalanceHidingFlow = model.isBalanceHiddenFlow,
title = resourceReference(R.string.nft_send),
analyticsCategoryName = analyticsCategoryName,
analyticsSendSource = analyticsSendSource,
userWalletId = params.userWalletId,
cryptoCurrency = model.cryptoCurrency,
callback = model,
@ -159,6 +170,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
onLoadFee = model::loadFee,
destinationAddress = destinationAddress,
callback = model,
analyticsSendSource = analyticsSendSource,
),
)
} else {
@ -181,6 +193,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
currentRoute = model.currentRouteFlow.filterIsInstance<CommonSendRoute.Confirm>(),
isBalanceHidingFlow = model.isBalanceHiddenFlow,
onLoadFee = model::loadFee,
analyticsSendSource = analyticsSendSource,
onSendTransaction = { innerRouter.replaceAll(CommonSendRoute.ConfirmSuccess) },
),
)
@ -198,6 +211,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
params = NFTSendSuccessComponent.Params(
nftSendUMFlow = model.uiState,
analyticsCategoryName = analyticsCategoryName,
analyticsSendSource = analyticsSendSource,
userWallet = model.userWallet,
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
nftAsset = params.nftAsset,

View file

@ -20,6 +20,7 @@ import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.nft.component.NFTDetailsBlockComponent
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.params.FeeSelectorParams.FeeStateConfiguration
@ -57,6 +58,7 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
params = DestinationBlockParams(
state = model.uiState.value.destinationUM,
analyticsCategoryName = params.analyticsCategoryName,
analyticsSendSource = params.analyticsSendSource,
userWalletId = params.userWallet.walletId,
cryptoCurrency = params.cryptoCurrencyStatus.currency,
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
@ -79,6 +81,7 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
onLoadFee = params.onLoadFee,
destinationAddress = model.confirmData.enteredDestination.orEmpty(),
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
analyticsSendSource = params.analyticsSendSource,
),
onResult = model::onFeeResult,
onClick = model::showEditFee,
@ -94,6 +97,7 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
feeStateConfiguration = FeeStateConfiguration.None,
feeDisplaySource = FeeSelectorParams.FeeDisplaySource.Screen,
analyticsCategoryName = params.analyticsCategoryName,
analyticsSendSource = params.analyticsSendSource,
),
onResult = model::onFeeResult,
)
@ -162,6 +166,7 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
data class Params(
val state: NFTSendUM,
val analyticsCategoryName: String,
val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val userWallet: UserWallet,
val appCurrency: AppCurrency,
val nftAsset: NFTAsset,

View file

@ -88,10 +88,10 @@ internal class NFTSendModel @Inject constructor(
private val nftAsset = params.nftAsset
val uiState: StateFlow<NFTSendUM>
field = MutableStateFlow(initialState())
field = MutableStateFlow(initialState())
val isBalanceHiddenFlow: StateFlow<Boolean>
field = MutableStateFlow(false)
field = MutableStateFlow(false)
var cryptoCurrency: CryptoCurrency by Delegates.notNull()
var userWallet: UserWallet by Delegates.notNull()

View file

@ -14,6 +14,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.models.NFTAsset
import com.tangem.features.nft.component.NFTDetailsBlockComponent
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.subcomponents.destination.SendDestinationBlockComponent
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
@ -54,6 +55,7 @@ internal class NFTSendSuccessComponent @AssistedInject constructor(
params = DestinationBlockParams(
state = model.uiState.value.destinationUM,
analyticsCategoryName = params.analyticsCategoryName,
analyticsSendSource = params.analyticsSendSource,
userWalletId = params.userWallet.walletId,
cryptoCurrency = params.cryptoCurrencyStatus.currency,
blockClickEnableFlow = MutableStateFlow(false),
@ -77,6 +79,7 @@ internal class NFTSendSuccessComponent @AssistedInject constructor(
data class Params(
val nftSendUMFlow: StateFlow<NFTSendUM>,
val analyticsCategoryName: String,
val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val currentRoute: Flow<CommonSendRoute>,
val cryptoCurrencyStatus: CryptoCurrencyStatus,
val userWallet: UserWallet,

View file

@ -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.models.wallet.UserWalletId
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.entity.PredefinedValues
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent.ModelCallback
@ -15,6 +16,7 @@ internal sealed class SendAmountComponentParams {
abstract val state: AmountState
abstract val analyticsCategoryName: String
abstract val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource
abstract val userWalletId: UserWalletId
abstract val appCurrency: AppCurrency
abstract val predefinedValues: PredefinedValues
@ -33,6 +35,7 @@ internal sealed class SendAmountComponentParams {
override val cryptoCurrency: CryptoCurrency,
override val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
override val isBalanceHidingFlow: StateFlow<Boolean>,
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val callback: ModelCallback,
val currentRoute: StateFlow<CommonSendRoute>,
) : SendAmountComponentParams()
@ -47,6 +50,7 @@ internal sealed class SendAmountComponentParams {
override val cryptoCurrency: CryptoCurrency,
override val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
override val isBalanceHidingFlow: StateFlow<Boolean>,
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val userWallet: UserWallet,
val blockClickEnableFlow: StateFlow<Boolean>,
) : SendAmountComponentParams()

View file

@ -79,7 +79,7 @@ internal class SendAmountModel @Inject constructor(
private var isAvailableForSwap: Boolean = false
val isSendWithSwapAvailable: StateFlow<Boolean>
field = MutableStateFlow(false)
field = MutableStateFlow(false)
private val analyticsCategoryName = params.analyticsCategoryName
private var cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus(
@ -246,6 +246,7 @@ internal class SendAmountModel @Inject constructor(
categoryName = analyticsCategoryName,
token = params.cryptoCurrency.symbol,
blockchain = params.cryptoCurrency.network.name,
source = params.analyticsSendSource,
),
)
}

View file

@ -3,6 +3,7 @@ package com.tangem.features.send.v2.subcomponents.destination.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE
import com.tangem.core.analytics.models.AnalyticsParam.Key.VALIDATION
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
internal sealed class SendDestinationAnalyticEvents(
category: String,
@ -15,13 +16,15 @@ internal sealed class SendDestinationAnalyticEvents(
/** Address to send entered */
data class AddressEntered(
override val categoryName: String,
val source: EnterAddressSource,
val method: EnterAddressSource,
val isValid: Boolean,
val source: CommonSendAnalyticEvents.CommonSendSource,
) : SendDestinationAnalyticEvents(
category = categoryName,
event = "Address Entered",
params = mapOf(
SOURCE to source.name,
SOURCE to source.analyticsName,
"Method" to method.name,
VALIDATION to if (isValid) "Success" else "Fail",
),
)

View file

@ -275,7 +275,8 @@ internal class SendDestinationModel @Inject constructor(
analyticsEventHandler.send(
SendDestinationAnalyticEvents.AddressEntered(
categoryName = analyticsCategoryName,
source = it,
source = params.analyticsSendSource,
method = it,
isValid = addressValidationResult.isRight(),
),
)

View file

@ -6,6 +6,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import kotlinx.coroutines.flow.Flow
@ -23,6 +24,7 @@ internal sealed class SendFeeComponentParams {
abstract val sendAmount: BigDecimal
abstract val destinationAddress: String
abstract val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>
abstract val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource
data class FeeParams(
override val state: FeeUM,
@ -34,6 +36,7 @@ internal sealed class SendFeeComponentParams {
override val sendAmount: BigDecimal,
override val destinationAddress: String,
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val currentRoute: Flow<CommonSendRoute.Fee>,
val callback: SendFeeComponent.ModelCallback,
) : SendFeeComponentParams()
@ -48,6 +51,7 @@ internal sealed class SendFeeComponentParams {
override val sendAmount: BigDecimal,
override val destinationAddress: String,
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
val blockClickEnableFlow: StateFlow<Boolean>,
) : SendFeeComponentParams()
}

View file

@ -22,13 +22,13 @@ import com.tangem.features.send.v2.subcomponents.fee.model.transformers.*
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import com.tangem.utils.TangemLinks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.util.Locale
import javax.inject.Inject
@Suppress("LongParameterList")
@ -136,13 +136,7 @@ internal class SendFeeModel @Inject constructor(
}
override fun onReadMoreClick() {
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
val url = buildString {
append(FEE_READ_MORE_URL_FIRST_PART)
append(locale)
append(FEE_READ_MORE_URL_SECOND_PART)
}
urlOpener.openUrl(url)
urlOpener.openUrl(TangemLinks.FEE_BLOG_LINK)
}
override fun onNextClick() {
@ -162,6 +156,7 @@ internal class SendFeeModel @Inject constructor(
CommonSendFeeAnalyticEvents.SelectedFee(
categoryName = analyticsCategoryName,
feeType = feeSelectorUM.selectedType.toAnalyticType(feeSelectorUM),
source = params.analyticsSendSource,
),
)
@ -297,11 +292,4 @@ internal class SendFeeModel @Inject constructor(
)
}.launchIn(modelScope)
}
private companion object {
const val RU_LOCALE = "ru"
const val EN_LOCALE = "en"
const val FEE_READ_MORE_URL_FIRST_PART = "https://tangem.com/"
const val FEE_READ_MORE_URL_SECOND_PART = "/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/"
}
}

View file

@ -287,7 +287,7 @@ internal class NotificationsModel @Inject constructor(
) {
val validationError = validateTransactionUseCase(
userWalletId = userWalletId,
amount = enteredAmount.convertToSdkAmount(currency),
amount = enteredAmount.convertToSdkAmount(cryptoCurrencyStatus),
fee = fee,
memo = memo,
destination = destinationAddress,