Updated on 2026-08-14
This commit is contained in:
parent
b08892762c
commit
f095f3a508
24 changed files with 184 additions and 26 deletions
|
|
@ -88,18 +88,27 @@ internal class DefaultFeeSelectorComponent @AssistedInject constructor(
|
|||
)
|
||||
|
||||
return when (config) {
|
||||
FeeSelectorRoute.NetworkFee -> feeExtendedSelectorComponentFactory.create(
|
||||
appComponentContext = appComponentContext,
|
||||
params = componentParams,
|
||||
)
|
||||
FeeSelectorRoute.ChooseSpeed -> feeSpeedSelectorComponentFactory.create(
|
||||
appComponentContext = appComponentContext,
|
||||
params = componentParams,
|
||||
)
|
||||
FeeSelectorRoute.ChooseToken -> feeTokenSelectorComponentFactory.create(
|
||||
appComponentContext = appComponentContext,
|
||||
params = componentParams,
|
||||
)
|
||||
FeeSelectorRoute.NetworkFee -> {
|
||||
model.onFeeScreenOpened()
|
||||
feeExtendedSelectorComponentFactory.create(
|
||||
appComponentContext = appComponentContext,
|
||||
params = componentParams,
|
||||
)
|
||||
}
|
||||
FeeSelectorRoute.ChooseSpeed -> {
|
||||
model.onChooseSpeedScreenOpened()
|
||||
feeSpeedSelectorComponentFactory.create(
|
||||
appComponentContext = appComponentContext,
|
||||
params = componentParams,
|
||||
)
|
||||
}
|
||||
FeeSelectorRoute.ChooseToken -> {
|
||||
model.onChooseTokenScreenOpened()
|
||||
feeTokenSelectorComponentFactory.create(
|
||||
appComponentContext = appComponentContext,
|
||||
params = componentParams,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,12 +58,6 @@ internal class FeeSelectorBlockModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun showFeeSelector() {
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.FeeScreenOpened(
|
||||
categoryName = params.analyticsCategoryName,
|
||||
source = params.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.ScreenReopened(
|
||||
categoryName = params.analyticsCategoryName,
|
||||
|
|
|
|||
|
|
@ -153,13 +153,15 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
categoryName = params.analyticsCategoryName,
|
||||
feeType = feeSelectorUM.toAnalyticType(),
|
||||
source = params.analyticsSendSource,
|
||||
feeToken = feeSelectorUM.feeExtraInfo.feeCryptoCurrencyStatus.currency.symbol,
|
||||
),
|
||||
)
|
||||
val isCustomFeeEdited = feeSelectorUM.selectedFeeItem.fee.amount.value != feeSelectorUM.fees.normal.amount.value
|
||||
if (feeSelectorUM.selectedFeeItem is FeeItem.Custom && isCustomFeeEdited) {
|
||||
analyticsEventHandler.send(GasPriceInserter(categoryName = params.analyticsCategoryName))
|
||||
}
|
||||
if (feeSelectorUM.feeNonce is FeeNonce.Nonce) {
|
||||
val nonceField = feeSelectorUM.feeNonce as? FeeNonce.Nonce
|
||||
if (nonceField != null && nonceField.nonce != null) {
|
||||
analyticsEventHandler.send(
|
||||
NonceInserted(
|
||||
categoryName = params.analyticsCategoryName,
|
||||
|
|
@ -268,12 +270,11 @@ internal class FeeSelectorLogic @AssistedInject constructor(
|
|||
|
||||
private suspend fun getSelectedTokenStatus(tokenId: CryptoCurrency.ID): Either<GetFeeError, CryptoCurrencyStatus> =
|
||||
either {
|
||||
val feeTokenId = tokenId
|
||||
if (params.feeCryptoCurrencyStatus.currency.id != feeTokenId) {
|
||||
if (params.feeCryptoCurrencyStatus.currency.id != tokenId) {
|
||||
getSingleCryptoCurrencyStatusUseCase
|
||||
.invokeMultiWalletSync(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrencyId = feeTokenId,
|
||||
cryptoCurrencyId = tokenId,
|
||||
).getOrElse {
|
||||
raise(GetFeeError.DataError(IllegalStateException("No token found for id: $tokenId")))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package com.tangem.features.send.v2.feeselector.model
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.utils.stack
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
|
||||
import com.tangem.features.send.v2.api.entity.FeeItem
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.params.FeeSelectorParams
|
||||
|
|
@ -23,6 +25,7 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
feeSelectorLogicFactory: FeeSelectorLogic.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model(), FeeSelectorIntents {
|
||||
|
||||
private val params = paramsContainer.require<FeeSelectorParams.FeeSelectorDetailsParams>()
|
||||
|
|
@ -78,6 +81,42 @@ internal class FeeSelectorModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onFeeScreenOpened() {
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.FeeSummaryScreenOpened(
|
||||
categoryName = params.analyticsCategoryName,
|
||||
source = params.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onChooseSpeedScreenOpened() {
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.FeeScreenOpened(
|
||||
categoryName = params.analyticsCategoryName,
|
||||
source = params.analyticsSendSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onChooseTokenScreenOpened() {
|
||||
analyticsEventHandler.send(
|
||||
CommonSendAnalyticEvents.FeeTokenScreenOpened(
|
||||
categoryName = params.analyticsCategoryName,
|
||||
source = params.analyticsSendSource,
|
||||
availableTokens = getAvailableTokensString(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAvailableTokensString(): String {
|
||||
return (uiState.value as? FeeSelectorUM.Content)
|
||||
?.feeExtraInfo
|
||||
?.availableFeeCurrencies
|
||||
?.joinToString(", ") { it.currency.symbol }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
private fun contentState(): FeeSelectorUM.Content {
|
||||
val currentState = uiState.value
|
||||
require(currentState is FeeSelectorUM.Content) { "Current state must be FeeSelectorUM.Content" }
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ internal fun FeeSelectorModalBottomSheet(
|
|||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
text = stringResourceSafe(R.string.common_confirm),
|
||||
text = stringResourceSafe(R.string.common_apply),
|
||||
onClick = feeSelectorIntents::onDoneClick,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ internal sealed class SendAnalyticEvents(
|
|||
val blockchain: String,
|
||||
val isNonceNotEmpty: Boolean,
|
||||
private val ensStatus: AnalyticsParam.EmptyFull,
|
||||
private val feeToken: String,
|
||||
val derivationIndex: Int?,
|
||||
) : SendAnalyticEvents(
|
||||
event = "Transaction Sent Screen Opened",
|
||||
|
|
|
|||
|
|
@ -18,10 +18,16 @@ internal class SendAnalyticHelper @Inject constructor(
|
|||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) {
|
||||
|
||||
fun sendSuccessAnalytics(cryptoCurrency: CryptoCurrency, sendUM: SendUM, account: Account.CryptoPortfolio?) {
|
||||
fun sendSuccessAnalytics(
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
sendUM: SendUM,
|
||||
feeToken: CryptoCurrency,
|
||||
account: Account.CryptoPortfolio?,
|
||||
) {
|
||||
val destinationUM = sendUM.destinationUM as? DestinationUM.Content
|
||||
val feeSelectorUM = sendUM.feeSelectorUM as? FeeSelectorUM.Content ?: return
|
||||
val feeType = feeSelectorUM.toAnalyticType()
|
||||
val feeTokenSymbol = feeToken.symbol
|
||||
val isNotMainAccount = account != null && !account.isMainAccount
|
||||
val derivationIndex = if (isNotMainAccount) account.derivationIndex.value else null
|
||||
analyticsEventHandler.send(
|
||||
|
|
@ -32,6 +38,7 @@ internal class SendAnalyticHelper @Inject constructor(
|
|||
isNonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
|
||||
ensStatus = getEnsStatus(sendUM),
|
||||
derivationIndex = derivationIndex,
|
||||
feeToken = feeTokenSymbol,
|
||||
),
|
||||
)
|
||||
analyticsEventHandler.send(
|
||||
|
|
@ -40,6 +47,7 @@ internal class SendAnalyticHelper @Inject constructor(
|
|||
blockchain = cryptoCurrency.network.name,
|
||||
token = cryptoCurrency.symbol,
|
||||
feeType = feeType,
|
||||
feeToken = feeTokenSymbol,
|
||||
),
|
||||
memoType = getSendTransactionMemoType(destinationUM?.memoTextField),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
|
||||
private suspend fun sendTransaction(txData: TransactionData.Uncompiled) {
|
||||
val feeExtended = feeUMV2?.feeExtraInfo?.transactionFeeExtended
|
||||
val feeToken = getCurrencyStatusForFeePayment().currency
|
||||
|
||||
val isFeeInTokenCurrency = feeExtended?.transactionFee?.normal is Fee.Ethereum.TokenCurrency
|
||||
|
||||
|
|
@ -433,6 +434,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
cryptoCurrency = cryptoCurrency,
|
||||
sendUM = uiState.value,
|
||||
account = params.accountFlow.value,
|
||||
feeToken = feeToken,
|
||||
)
|
||||
params.callback.onResult(uiState.value)
|
||||
params.onSendTransaction()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import arrow.core.Either
|
|||
import arrow.core.getOrElse
|
||||
import arrow.core.left
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.navigationButtons.NavigationUM
|
||||
|
|
@ -28,6 +29,7 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
|||
import com.tangem.domain.feedback.models.BlockchainErrorInfo
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.account.Account
|
||||
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.isMultiCurrency
|
||||
|
|
@ -72,6 +74,7 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM as FeeSelectorUMRedesigned
|
||||
|
||||
internal interface SendComponentCallback :
|
||||
SendAmountComponent.ModelCallback,
|
||||
|
|
@ -452,6 +455,17 @@ internal class SendModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun getSelectedFeeToken(): CryptoCurrency {
|
||||
val feeUMV2 = uiState.value.feeSelectorUM as? FeeSelectorUMRedesigned.Content
|
||||
val feeExtended = feeUMV2?.feeExtraInfo?.transactionFeeExtended
|
||||
val isFeeInTokenCurrency = feeExtended?.transactionFee?.normal is Fee.Ethereum.TokenCurrency
|
||||
return if (isFeeInTokenCurrency) {
|
||||
feeUMV2.feeExtraInfo.feeCryptoCurrencyStatus.currency
|
||||
} else {
|
||||
feeCryptoCurrencyStatusFlow.value.currency
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getFeeCurrencyStatus(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
isMultiCurrency: Boolean,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ internal class NFTSendAnalyticHelper @Inject constructor(
|
|||
blockchain = cryptoCurrency.network.name,
|
||||
token = NFT_SEND_CATEGORY, // should send "NFT" in token param
|
||||
feeType = feeType,
|
||||
feeToken = cryptoCurrency.symbol,
|
||||
),
|
||||
memoType = getSendTransactionMemoType(destinationUM?.memoTextField),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue