Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-06 14:13:17 +03:00
commit 74522f0304
27 changed files with 216 additions and 109 deletions

View file

@ -11,10 +11,13 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
@ -47,6 +50,7 @@ fun SearchBar(
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val focusRequester = remember { FocusRequester() }
val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
@ -60,6 +64,7 @@ fun SearchBar(
state.onActiveChange(false)
}
}
.focusRequester(focusRequester)
.testTag(SelectCountryBottomSheetTestTags.SEARCH_BAR),
enabled = enabled,
value = state.query,
@ -92,6 +97,10 @@ fun SearchBar(
)
},
)
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
@Suppress("LongParameterList")

View file

@ -13,11 +13,17 @@ interface ChooseManagedTokensComponent : ComposableContentComponent {
val selectedCurrency: CryptoCurrency?,
val source: Source,
val showSendViaSwapNotification: Boolean,
val callback: ModelCallback? = null,
)
enum class Source {
SendViaSwap,
}
interface ModelCallback {
fun onResult()
fun onBack()
}
interface Factory : ComponentFactory<Params, ChooseManagedTokensComponent>
}

View file

@ -70,7 +70,7 @@ internal class DefaultChooseManagedTokensComponent @AssistedInject constructor(
cryptoCurrency = cryptoCurrency,
shouldResetNavigation = params.selectedCurrency != null,
)
router.pop()
params.callback?.onResult() ?: router.pop()
}
},
),

View file

@ -89,13 +89,13 @@ internal class ChooseManagedTokensModel @Inject constructor(
return ChooseManagedTokenUM(
notificationUM = getNotification(),
readContent = ManageTokensUM.ReadContent(
popBack = router::pop,
popBack = { params.callback?.onBack() ?: router.pop() },
isInitialBatchLoading = true,
isNextBatchLoading = false,
items = getLoadingItems(),
topBar = ManageTokensTopBarUM.ReadContent(
title = resourceReference(R.string.common_choose_token),
onBackButtonClick = router::pop,
onBackButtonClick = { params.callback?.onBack() ?: router.pop() },
),
search = SearchBarUM(
placeholderText = resourceReference(R.string.common_search),

View file

@ -16,6 +16,7 @@ dependencies {
/** Core */
implementation(projects.core.decompose)
implementation(projects.core.ui)
implementation(projects.core.analytics.models)
/** Common */
implementation(projects.common.ui)

View file

@ -1,4 +1,4 @@
package com.tangem.features.send.v2.common.analytics
package com.tangem.features.send.v2.api.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN
@ -6,9 +6,9 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
/**
* Send screen analytics
* Send analytics
*/
internal sealed class CommonSendAnalyticEvents(
sealed class CommonSendAnalyticEvents(
category: String,
event: String,
params: Map<String, String> = mapOf(),
@ -114,12 +114,26 @@ internal sealed class CommonSendAnalyticEvents(
),
)
/** Token chosen to convert with sending */
data class TokenChosen(
val categoryName: String,
val token: String,
val blockchain: String,
) : CommonSendAnalyticEvents(
category = categoryName,
event = "Token chosen",
params = mapOf(
TOKEN_PARAM to token,
BLOCKCHAIN to blockchain,
),
)
companion object {
const val SEND_CATEGORY = "Token / Send"
const val NFT_SEND_CATEGORY = "NFT"
}
internal enum class SendScreenSource {
enum class SendScreenSource {
Address,
Amount,
Fee,

View file

@ -1,9 +1,9 @@
package com.tangem.features.send.v2.subcomponents.amount.analytics
package com.tangem.features.send.v2.api.subcomponents.amount.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam.Key.TYPE
internal sealed class SendAmountAnalyticEvents(
sealed class CommonSendAmountAnalyticEvents(
category: String,
event: String,
params: Map<String, String> = mapOf(),
@ -13,7 +13,7 @@ internal sealed class SendAmountAnalyticEvents(
data class SelectedCurrency(
val categoryName: String,
val type: SelectedCurrencyType,
) : SendAmountAnalyticEvents(
) : CommonSendAmountAnalyticEvents(
category = categoryName,
event = "Selected Currency",
params = mapOf(TYPE to type.value),
@ -22,9 +22,9 @@ internal sealed class SendAmountAnalyticEvents(
/** Max amount button clicked */
data class MaxAmountButtonClicked(
val categoryName: String,
) : SendAmountAnalyticEvents(category = categoryName, event = "Max Amount Taped")
) : CommonSendAmountAnalyticEvents(category = categoryName, event = "Max Amount Taped")
internal enum class SelectedCurrencyType(val value: String) {
enum class SelectedCurrencyType(val value: String) {
Token("Token"),
AppCurrency("App Currency"),
}

View file

@ -1,9 +1,9 @@
package com.tangem.features.send.v2.subcomponents.fee.analytics
package com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
internal sealed class SendFeeAnalyticEvents(
sealed class CommonSendFeeAnalyticEvents(
category: String,
event: String,
params: Map<String, String> = mapOf(),
@ -15,7 +15,7 @@ internal sealed class SendFeeAnalyticEvents(
data class SelectedFee(
override val categoryName: String,
val feeType: AnalyticsParam.FeeType,
) : SendFeeAnalyticEvents(
) : CommonSendFeeAnalyticEvents(
category = categoryName,
event = "Fee Selected",
params = mapOf("Fee Type" to feeType.value),
@ -24,7 +24,7 @@ internal sealed class SendFeeAnalyticEvents(
/** Custom fee selected */
data class CustomFeeButtonClicked(
override val categoryName: String,
) : SendFeeAnalyticEvents(
) : CommonSendFeeAnalyticEvents(
category = categoryName,
event = "Custom Fee Clicked",
)
@ -32,7 +32,7 @@ internal sealed class SendFeeAnalyticEvents(
/** Custom fee edited */
data class GasPriceInserter(
override val categoryName: String,
) : SendFeeAnalyticEvents(
) : CommonSendFeeAnalyticEvents(
category = categoryName,
event = "Gas Price Inserted",
)

View file

@ -21,6 +21,7 @@ dependencies {
implementation(projects.features.txhistory.api)
implementation(projects.features.nft.api)
implementation(projects.features.swapV2.api)
implementation(projects.features.manageTokens.api)
/** Libs */
implementation(projects.libs.crypto)

View file

@ -1,18 +1,29 @@
package com.tangem.features.send.v2.entrypoint
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.stack.Children
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
import com.arkivanov.decompose.extensions.compose.stack.animation.plus
import com.arkivanov.decompose.extensions.compose.stack.animation.slide
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
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.features.managetokens.component.ChooseManagedTokensComponent
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.api.SendEntryPointComponent
import com.tangem.features.send.v2.entrypoint.model.SendEntryPoint
import com.tangem.features.send.v2.entrypoint.model.SendEntryPointModel
import com.tangem.features.swap.v2.api.SendWithSwapComponent
import dagger.assisted.Assisted
@ -24,9 +35,17 @@ internal class DefaultSendEntryPointComponent @AssistedInject constructor(
@Assisted private val params: SendEntryPointComponent.Params,
sendWithSwapComponentFactory: SendWithSwapComponent.Factory,
sendComponentFactory: SendComponent.Factory,
private val chooseManagedTokensComponentFactory: ChooseManagedTokensComponent.Factory,
) : SendEntryPointComponent, AppComponentContext by appComponentContext {
private val model: SendEntryPointModel = getOrCreateModel(params = params)
private val stackNavigation = StackNavigation<SendEntryRoute>()
private val innerRouter = InnerRouter<SendEntryRoute>(
stackNavigation = stackNavigation,
popCallback = { onChildBack() },
)
private val model: SendEntryPointModel = getOrCreateModel(params = params, router = innerRouter)
private val sendWithSwapComponent = sendWithSwapComponentFactory.create(
context = child("sendEntrySendWithSwap"),
@ -46,18 +65,76 @@ internal class DefaultSendEntryPointComponent @AssistedInject constructor(
),
)
private val childStack = childStack(
key = "sendEntryStack",
source = stackNavigation,
serializer = null,
initialConfiguration = SendEntryRoute.Send,
handleBackButton = true,
childFactory = { configuration, factoryContext ->
getChildComponent(
configuration = configuration,
factoryContext = childByContext(
componentContext = factoryContext,
router = innerRouter,
),
)
},
)
@Composable
override fun Content(modifier: Modifier) {
val sendEntryState by model.sendEntryPointState.collectAsStateWithLifecycle()
val childStackValue by childStack.subscribeAsState()
sendComponent.Content(modifier)
Children(
stack = childStackValue,
animation = stackAnimation { child ->
when (child.configuration) {
SendEntryRoute.Send,
SendEntryRoute.SendWithSwap,
-> fade()
is SendEntryRoute.ChooseToken -> slide(orientation = Orientation.Vertical) + fade()
}
},
) { child ->
child.instance.Content(modifier.fillMaxSize())
}
}
AnimatedVisibility(
visible = sendEntryState == SendEntryPoint.SendWithSwap,
enter = fadeIn(),
exit = fadeOut(),
) {
sendWithSwapComponent.Content(modifier)
private fun getChildComponent(
configuration: SendEntryRoute,
factoryContext: AppComponentContext,
): ComposableContentComponent = when (configuration) {
is SendEntryRoute.ChooseToken -> getManagedTokensComponent(
componentContext = factoryContext,
showSendViaSwapNotification = configuration.showSendViaSwapNotification,
)
SendEntryRoute.Send -> sendComponent
SendEntryRoute.SendWithSwap -> sendWithSwapComponent
}
private fun getManagedTokensComponent(
componentContext: ComponentContext,
showSendViaSwapNotification: Boolean,
): ChooseManagedTokensComponent {
return chooseManagedTokensComponentFactory.create(
context = childByContext(componentContext),
params = ChooseManagedTokensComponent.Params(
userWalletId = params.userWalletId,
initialCurrency = params.cryptoCurrency,
source = ChooseManagedTokensComponent.Source.SendViaSwap,
selectedCurrency = null,
showSendViaSwapNotification = showSendViaSwapNotification,
callback = model,
),
)
}
private fun onChildBack() {
if (childStack.value.backStack.isEmpty()) {
router.pop()
} else {
stackNavigation.pop()
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.features.send.v2.entrypoint
import com.tangem.core.decompose.navigation.Route
internal sealed class SendEntryRoute : Route {
data object Send : SendEntryRoute()
data object SendWithSwap : SendEntryRoute()
data class ChooseToken(
val showSendViaSwapNotification: Boolean,
) : SendEntryRoute()
}

View file

@ -1,90 +1,74 @@
package com.tangem.features.send.v2.entrypoint.model
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.common.ui.notifications.NotificationId
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.navigation.Router
import com.tangem.domain.notifications.ShouldShowNotificationUseCase
import com.tangem.features.managetokens.component.ChooseManagedTokensComponent
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.api.SendEntryPointComponent
import com.tangem.features.send.v2.entrypoint.SendEntryRoute
import com.tangem.features.send.v2.subcomponents.amount.SendAmountUpdateTrigger
import com.tangem.features.swap.v2.api.SendWithSwapComponent
import com.tangem.features.swap.v2.api.choosetoken.SwapChooseTokenNetworkListener
import com.tangem.features.swap.v2.api.subcomponents.SwapAmountUpdateTrigger
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import jakarta.inject.Inject
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Suppress("LongParameterList")
@ModelScoped
internal class SendEntryPointModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
val appRouter: AppRouter,
private val swapChooseTokenNetworkListener: SwapChooseTokenNetworkListener,
val router: Router,
private val sendAmountUpdateTrigger: SendAmountUpdateTrigger,
private val swapAmountUpdateTrigger: SwapAmountUpdateTrigger,
private val shouldShowNotificationUseCase: ShouldShowNotificationUseCase,
) : Model(), SendComponent.ModelCallback, SendWithSwapComponent.ModelCallback {
) : Model(),
SendComponent.ModelCallback,
SendWithSwapComponent.ModelCallback,
ChooseManagedTokensComponent.ModelCallback {
private val params: SendEntryPointComponent.Params = paramsContainer.require()
val sendEntryPointState: StateFlow<SendEntryPoint>
field = MutableStateFlow(SendEntryPoint.SendVanilla)
private var swapChooseTokenListenerJobHolder = JobHolder()
private var lastSavedAmount = ""
override fun onConvertToAnotherToken(lastAmount: String) {
lastSavedAmount = lastAmount
modelScope.launch {
val showSendViaSwapNotification = shouldShowNotificationUseCase(
NotificationId.SendViaSwapTokenSelectorNotification.key,
)
appRouter.push(
AppRoute.ChooseManagedTokens(
userWalletId = params.userWalletId,
initialCurrency = params.cryptoCurrency,
selectedCurrency = null,
source = AppRoute.ChooseManagedTokens.Source.SendViaSwap,
router.push(
SendEntryRoute.ChooseToken(
showSendViaSwapNotification = showSendViaSwapNotification,
),
)
observeChooseSelectToken(lastAmount)
}
}
override fun onCloseSwap(lastAmount: String) {
lastSavedAmount = lastAmount
modelScope.launch {
if (lastAmount.isNotBlank()) {
sendAmountUpdateTrigger.triggerUpdateAmount(lastAmount)
}
triggerScreenUpdate(SendEntryPoint.SendVanilla)
router.replaceAll(SendEntryRoute.Send)
}
}
private fun observeChooseSelectToken(lastAmount: String) {
swapChooseTokenNetworkListener.swapChooseTokenNetworkResultFlow
.onEach { currency ->
if (lastAmount.isNotBlank()) {
swapAmountUpdateTrigger.triggerUpdateAmount(lastAmount)
}
triggerScreenUpdate(SendEntryPoint.SendWithSwap)
@Suppress("MagicNumber")
override fun onResult() {
modelScope.launch {
if (lastSavedAmount.isNotBlank()) {
swapAmountUpdateTrigger.triggerUpdateAmount(lastSavedAmount)
}
.launchIn(modelScope)
.saveIn(swapChooseTokenListenerJobHolder)
// Workaround in order to execute correct exit animation on SendEntryRoute.ChooseToken
router.pop()
delay(10L)
router.replaceAll(SendEntryRoute.SendWithSwap)
}
}
private fun triggerScreenUpdate(entry: SendEntryPoint) {
swapChooseTokenListenerJobHolder.cancel()
sendEntryPointState.update { entry }
override fun onBack() {
router.pop()
}
}
enum class SendEntryPoint {
SendVanilla,
SendWithSwap,
}

View file

@ -24,10 +24,10 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.SendContent
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R

View file

@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TYPE
import com.tangem.core.analytics.models.AnalyticsParam.Key.NONCE
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
import com.tangem.core.ui.extensions.capitalize
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
/**
* Send screen analytics

View file

@ -38,6 +38,8 @@ import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.utils.convertToSdkAmount
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.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback
import com.tangem.features.send.v2.api.entity.FeeNonce
import com.tangem.features.send.v2.api.params.FeeSelectorParams.FeeStateConfiguration
@ -48,8 +50,6 @@ import com.tangem.features.send.v2.api.subcomponents.notifications.SendNotificat
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.SendBalanceUpdater
import com.tangem.features.send.v2.common.SendConfirmAlertFactory
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.send.analytics.SendAnalyticHelper

View file

@ -14,10 +14,10 @@ import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.utils.formatFooterFiatFee
import com.tangem.features.send.v2.api.utils.getTronTokenFeeSendingText
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.checkIfFeeTooHigh
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM

View file

@ -12,12 +12,12 @@ import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.subcomponents.feeSelector.utils.FeeCalculationUtils
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.api.utils.formatFooterFiatFee
import com.tangem.features.send.v2.api.utils.getTronTokenFeeSendingText
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.toPersistentList

View file

@ -41,6 +41,8 @@ import com.tangem.domain.wallets.models.GetUserWalletError
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.entity.PredefinedValues
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponent
@ -48,8 +50,6 @@ import com.tangem.features.send.v2.api.subcomponents.destination.entity.Destinat
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.CommonSendRoute.*
import com.tangem.features.send.v2.common.SendConfirmAlertFactory
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.send.confirm.SendConfirmComponent
import com.tangem.features.send.v2.send.success.SendConfirmSuccessComponent

View file

@ -12,14 +12,17 @@ import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.send.success.SendConfirmSuccessComponent
import com.tangem.features.send.v2.send.ui.state.SendUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
@Stable

View file

@ -20,10 +20,10 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.nft.component.NFTDetailsBlockComponent
import com.tangem.features.send.v2.api.NFTSendComponent
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.SendContent
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R

View file

@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TYPE
import com.tangem.core.analytics.models.AnalyticsParam.Key.NONCE
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
import com.tangem.core.ui.extensions.capitalize
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
/**
* Send screen analytics

View file

@ -22,23 +22,23 @@ 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.wallet.UserWallet
import com.tangem.domain.models.wallet.requireColdWallet
import com.tangem.domain.settings.IsSendTapHelpEnabledUseCase
import com.tangem.domain.settings.NeverShowTapHelpUseCase
import com.tangem.domain.transaction.usecase.CreateNFTTransferTransactionUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.models.wallet.requireColdWallet
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
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.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.v2.api.subcomponents.notifications.SendNotificationsUpdateListener
import com.tangem.features.send.v2.api.subcomponents.notifications.SendNotificationsUpdateTrigger
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.SendBalanceUpdater
import com.tangem.features.send.v2.common.SendConfirmAlertFactory
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.sendnft.analytics.NFTSendAnalyticHelper

View file

@ -10,10 +10,10 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.utils.formatFooterFiatFee
import com.tangem.features.send.v2.api.utils.getTronTokenFeeSendingText
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.checkIfFeeTooHigh
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM

View file

@ -30,14 +30,14 @@ import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.features.send.v2.api.entity.PredefinedValues
import com.tangem.features.send.v2.api.subcomponents.amount.analytics.CommonSendAmountAnalyticEvents
import com.tangem.features.send.v2.api.subcomponents.amount.analytics.CommonSendAmountAnalyticEvents.SelectedCurrencyType
import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorReloadTrigger
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParams
import com.tangem.features.send.v2.subcomponents.amount.SendAmountReduceListener
import com.tangem.features.send.v2.subcomponents.amount.SendAmountUpdateListener
import com.tangem.features.send.v2.subcomponents.amount.analytics.SendAmountAnalyticEvents
import com.tangem.features.send.v2.subcomponents.amount.analytics.SendAmountAnalyticEvents.SelectedCurrencyType
import com.tangem.features.send.v2.subcomponents.fee.SendFeeData
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadTrigger
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -218,7 +218,7 @@ internal class SendAmountModel @Inject constructor(
),
)
analyticsEventHandler.send(
SendAmountAnalyticEvents.MaxAmountButtonClicked(categoryName = analyticsCategoryName),
CommonSendAmountAnalyticEvents.MaxAmountButtonClicked(categoryName = analyticsCategoryName),
)
}
@ -229,7 +229,7 @@ internal class SendAmountModel @Inject constructor(
override fun onAmountNext() {
(uiState.value as? AmountState.Data)?.amountTextField?.isFiatValue?.let { isFiatSelected ->
analyticsEventHandler.send(
SendAmountAnalyticEvents.SelectedCurrency(
CommonSendAmountAnalyticEvents.SelectedCurrency(
categoryName = analyticsCategoryName,
type = if (isFiatSelected) {
SelectedCurrencyType.AppCurrency

View file

@ -26,12 +26,12 @@ import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.api.entity.PredefinedValues
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.destination.analytics.EnterAddressSource
import com.tangem.features.send.v2.subcomponents.destination.analytics.SendDestinationAnalyticEvents

View file

@ -11,14 +11,13 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.NonceInserted
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics.CommonSendFeeAnalyticEvents
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadListener
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadListener
import com.tangem.features.send.v2.subcomponents.fee.analytics.SendFeeAnalyticEvents
import com.tangem.features.send.v2.subcomponents.fee.analytics.SendFeeAnalyticEvents.GasPriceInserter
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
@ -112,7 +111,7 @@ internal class SendFeeModel @Inject constructor(
updateFeeNotifications()
if (feeType == FeeType.Custom) {
analyticsEventHandler.send(
SendFeeAnalyticEvents.CustomFeeButtonClicked(categoryName = analyticsCategoryName),
CommonSendFeeAnalyticEvents.CustomFeeButtonClicked(categoryName = analyticsCategoryName),
)
}
}
@ -155,10 +154,12 @@ internal class SendFeeModel @Inject constructor(
val isCustomFeeEdited =
feeSelectorUM.selectedFee?.amount?.value != feeSelectorUM.fees.normal.amount.value
if (feeSelectorUM.selectedType == FeeType.Custom && isCustomFeeEdited) {
analyticsEventHandler.send(GasPriceInserter(categoryName = analyticsCategoryName))
analyticsEventHandler.send(
CommonSendFeeAnalyticEvents.GasPriceInserter(categoryName = analyticsCategoryName),
)
}
analyticsEventHandler.send(
SendFeeAnalyticEvents.SelectedFee(
CommonSendFeeAnalyticEvents.SelectedFee(
categoryName = analyticsCategoryName,
feeType = feeSelectorUM.selectedType.toAnalyticType(feeSelectorUM),
),
@ -166,7 +167,7 @@ internal class SendFeeModel @Inject constructor(
if (feeSelectorUM.nonce != null) {
analyticsEventHandler.send(
NonceInserted(
CommonSendAnalyticEvents.NonceInserted(
categoryName = analyticsCategoryName,
token = cryptoCurrencyStatus.currency.symbol,
blockchain = cryptoCurrencyStatus.currency.network.name,

View file

@ -80,8 +80,8 @@ reownWeb3 = "1.1.2"
prettyLogger = "2.2.0"
okHttp-prettyLogging = "3.1.0"
chucker = "4.0.0"
mlKit-barcodeScanning = "17.2.0"
androidXCamera = "1.3.0"
mlKit-barcodeScanning = "17.3.0"
androidXCamera = "1.4.2"
listenableFuture = "1.0"
swipeRefreshLayout = "1.1.0"
web3j = "4.12.3-SNAPSHOT"