Updated on 2026-08-14
This commit is contained in:
parent
b9a5220984
commit
c96e72fac4
9 changed files with 380 additions and 264 deletions
|
|
@ -4,7 +4,6 @@ import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||||
import com.arkivanov.decompose.router.stack.childStack
|
import com.arkivanov.decompose.router.stack.childStack
|
||||||
|
|
@ -16,14 +15,15 @@ import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.childByContext
|
import com.tangem.core.decompose.context.childByContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.features.send.api.NFTSendComponent
|
import com.tangem.features.send.api.NFTSendComponent
|
||||||
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
||||||
|
import com.tangem.features.send.api.subcomponents.destination.DestinationRoute
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponent
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponent
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams
|
||||||
import com.tangem.features.send.common.CommonSendRoute
|
import com.tangem.features.send.common.CommonSendRoute
|
||||||
import com.tangem.features.send.common.ui.SendContent
|
import com.tangem.features.send.common.ui.SendModularContent
|
||||||
import com.tangem.features.send.common.ui.state.ConfirmUM
|
import com.tangem.features.send.common.ui.state.ConfirmUM
|
||||||
import com.tangem.features.send.impl.R
|
import com.tangem.features.send.impl.R
|
||||||
import com.tangem.features.send.sendnft.confirm.NFTSendConfirmComponent
|
import com.tangem.features.send.sendnft.confirm.NFTSendConfirmComponent
|
||||||
|
|
@ -32,16 +32,14 @@ import com.tangem.features.send.sendnft.success.NFTSendSuccessComponent
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
internal class DefaultNFTSendComponent @AssistedInject constructor(
|
internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
@Assisted appComponentContext: AppComponentContext,
|
@Assisted appComponentContext: AppComponentContext,
|
||||||
@Assisted private val params: NFTSendComponent.Params,
|
@Assisted private val params: NFTSendComponent.Params,
|
||||||
|
private val destinationComponentFactory: SendDestinationComponent.Factory,
|
||||||
private val nftSendConfirmComponentFactory: NFTSendConfirmComponent.Factory,
|
private val nftSendConfirmComponentFactory: NFTSendConfirmComponent.Factory,
|
||||||
private val nftSendSuccessComponentFactory: NFTSendSuccessComponent.Factory,
|
private val nftSendSuccessComponentFactory: NFTSendSuccessComponent.Factory,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
private val sendDestinationComponentFactory: SendDestinationComponent.Factory,
|
|
||||||
) : NFTSendComponent, AppComponentContext by appComponentContext {
|
) : NFTSendComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val stackNavigation = StackNavigation<CommonSendRoute>()
|
private val stackNavigation = StackNavigation<CommonSendRoute>()
|
||||||
|
|
@ -77,37 +75,35 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
lifecycle = lifecycle,
|
lifecycle = lifecycle,
|
||||||
mode = ObserveLifecycleMode.CREATE_DESTROY,
|
mode = ObserveLifecycleMode.CREATE_DESTROY,
|
||||||
) { stack ->
|
) { stack ->
|
||||||
componentScope.launch {
|
when (val activeComponent = stack.active.instance) {
|
||||||
when (val activeComponent = stack.active.instance) {
|
is NFTSendConfirmComponent -> {
|
||||||
is NFTSendConfirmComponent -> {
|
val fromCurrency = model.cryptoCurrency
|
||||||
val fromCurrency = model.cryptoCurrency
|
val fromDerivationIndex = model.account?.derivationIndex?.value
|
||||||
val fromDerivationIndex = model.account?.derivationIndex?.value
|
.takeIf { model.isAccountsMode }
|
||||||
.takeIf { model.isAccountsMode }
|
analyticsEventHandler.send(
|
||||||
analyticsEventHandler.send(
|
CommonSendAnalyticEvents.ConfirmationScreenOpened(
|
||||||
CommonSendAnalyticEvents.ConfirmationScreenOpened(
|
categoryName = analyticsCategoryName,
|
||||||
categoryName = analyticsCategoryName,
|
source = analyticsSendSource,
|
||||||
source = analyticsSendSource,
|
sendBlockchain = fromCurrency.network.name,
|
||||||
sendBlockchain = fromCurrency.network.name,
|
sendToken = fromCurrency.symbol,
|
||||||
sendToken = fromCurrency.symbol,
|
fromDerivationIndex = fromDerivationIndex,
|
||||||
fromDerivationIndex = fromDerivationIndex,
|
toDerivationIndex = null,
|
||||||
toDerivationIndex = null,
|
),
|
||||||
),
|
)
|
||||||
)
|
// Push current state into a reused Confirm on (re)entry. Confirm.isEditMode is `true`
|
||||||
if (model.currentRouteFlow.value.isEditMode) {
|
if (stack.active.configuration.isEditMode) {
|
||||||
activeComponent.updateState(model.uiState.value)
|
activeComponent.updateState(model.uiState.value)
|
||||||
}
|
|
||||||
}
|
|
||||||
is SendDestinationComponent -> {
|
|
||||||
analyticsEventHandler.send(
|
|
||||||
CommonSendAnalyticEvents.AddressScreenOpened(
|
|
||||||
categoryName = analyticsCategoryName,
|
|
||||||
source = analyticsSendSource,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
activeComponent.updateState(model.uiState.value.destinationUM)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
model.currentRouteFlow.emit(stack.active.configuration)
|
is SendDestinationComponent -> {
|
||||||
|
analyticsEventHandler.send(
|
||||||
|
CommonSendAnalyticEvents.AddressScreenOpened(
|
||||||
|
categoryName = analyticsCategoryName,
|
||||||
|
source = analyticsSendSource,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
activeComponent.updateState(model.uiState.value.destinationUM)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,67 +111,71 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val stackState by childStack.subscribeAsState()
|
val stackState by childStack.subscribeAsState()
|
||||||
val state by model.uiState.collectAsStateWithLifecycle()
|
|
||||||
|
|
||||||
BackHandler(onBack = model::onBackClick)
|
BackHandler(onBack = ::onChildBack)
|
||||||
SendContent(
|
SendModularContent(stackState = stackState)
|
||||||
navigationUM = state.navigationUM,
|
|
||||||
confirmUM = state.confirmUM,
|
|
||||||
stackState = stackState,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createChild(route: CommonSendRoute, factoryContext: AppComponentContext) = when (route) {
|
private fun createChild(
|
||||||
is CommonSendRoute.Destination -> getDestinationComponent(factoryContext)
|
route: CommonSendRoute,
|
||||||
|
factoryContext: AppComponentContext,
|
||||||
|
): ComposableModularContentComponent = when (route) {
|
||||||
|
is CommonSendRoute.Destination -> getDestinationComponent(route, factoryContext)
|
||||||
CommonSendRoute.Confirm -> getConfirmComponent(factoryContext)
|
CommonSendRoute.Confirm -> getConfirmComponent(factoryContext)
|
||||||
CommonSendRoute.ConfirmSuccess -> getSuccessComponent(factoryContext)
|
CommonSendRoute.ConfirmSuccess -> getSuccessComponent(factoryContext)
|
||||||
else -> getStubComponent()
|
// Empty is the bootstrap placeholder until the currency status resolves; NFT has no Amount step.
|
||||||
|
CommonSendRoute.Empty,
|
||||||
|
is CommonSendRoute.Amount,
|
||||||
|
-> ComposableModularContentComponent.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDestinationComponent(factoryContext: AppComponentContext): SendDestinationComponent =
|
private fun getDestinationComponent(
|
||||||
sendDestinationComponentFactory.create(
|
route: DestinationRoute,
|
||||||
context = factoryContext,
|
factoryContext: AppComponentContext,
|
||||||
params = SendDestinationComponentParams.DestinationParams(
|
): ComposableModularContentComponent = destinationComponentFactory.create(
|
||||||
state = model.uiState.value.destinationUM,
|
context = factoryContext,
|
||||||
currentRoute = model.currentRouteFlow.filterIsInstance<CommonSendRoute.Destination>(),
|
params = SendDestinationComponentParams.DestinationParams(
|
||||||
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
state = model.uiState.value.destinationUM,
|
||||||
title = resourceReference(R.string.nft_send),
|
route = route,
|
||||||
analyticsCategoryName = analyticsCategoryName,
|
|
||||||
analyticsSendSource = analyticsSendSource,
|
|
||||||
userWalletId = params.userWalletId,
|
|
||||||
cryptoCurrency = model.cryptoCurrency,
|
|
||||||
callback = model,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getConfirmComponent(factoryContext: AppComponentContext) = nftSendConfirmComponentFactory.create(
|
|
||||||
appComponentContext = factoryContext,
|
|
||||||
params = NFTSendConfirmComponent.Params(
|
|
||||||
state = model.uiState.value,
|
|
||||||
analyticsCategoryName = analyticsCategoryName,
|
|
||||||
userWallet = model.userWallet,
|
|
||||||
nftAsset = params.nftAsset,
|
|
||||||
nftCollectionName = params.nftCollectionName,
|
|
||||||
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
|
|
||||||
feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus,
|
|
||||||
appCurrency = model.appCurrency,
|
|
||||||
callback = model,
|
|
||||||
currentRoute = model.currentRouteFlow.filterIsInstance<CommonSendRoute.Confirm>(),
|
|
||||||
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
||||||
onLoadFee = model::loadFee,
|
title = resourceReference(R.string.nft_send),
|
||||||
|
analyticsCategoryName = analyticsCategoryName,
|
||||||
analyticsSendSource = analyticsSendSource,
|
analyticsSendSource = analyticsSendSource,
|
||||||
account = model.account,
|
userWalletId = params.userWalletId,
|
||||||
isAccountsMode = model.isAccountsMode,
|
cryptoCurrency = model.cryptoCurrency,
|
||||||
onSendTransaction = { innerRouter.replaceAll(CommonSendRoute.ConfirmSuccess) },
|
callback = model,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getSuccessComponent(factoryContext: AppComponentContext): ComposableContentComponent {
|
private fun getConfirmComponent(factoryContext: AppComponentContext): ComposableModularContentComponent {
|
||||||
|
return nftSendConfirmComponentFactory.create(
|
||||||
|
appComponentContext = factoryContext,
|
||||||
|
params = NFTSendConfirmComponent.Params(
|
||||||
|
state = model.uiState.value,
|
||||||
|
analyticsCategoryName = analyticsCategoryName,
|
||||||
|
userWallet = model.userWallet,
|
||||||
|
nftAsset = params.nftAsset,
|
||||||
|
nftCollectionName = params.nftCollectionName,
|
||||||
|
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
|
||||||
|
feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus,
|
||||||
|
appCurrency = model.appCurrency,
|
||||||
|
callback = model,
|
||||||
|
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
||||||
|
onLoadFee = model::loadFee,
|
||||||
|
analyticsSendSource = analyticsSendSource,
|
||||||
|
account = model.account,
|
||||||
|
isAccountsMode = model.isAccountsMode,
|
||||||
|
onSendTransaction = { innerRouter.replaceAll(CommonSendRoute.ConfirmSuccess) },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSuccessComponent(factoryContext: AppComponentContext): ComposableModularContentComponent {
|
||||||
val txUrl = (model.uiState.value.confirmUM as? ConfirmUM.Success)?.txUrl
|
val txUrl = (model.uiState.value.confirmUM as? ConfirmUM.Success)?.txUrl
|
||||||
|
|
||||||
if (txUrl == null) {
|
if (txUrl == null) {
|
||||||
model.showAlertError()
|
model.showAlertError()
|
||||||
return getStubComponent()
|
return ComposableModularContentComponent.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
return nftSendSuccessComponentFactory.create(
|
return nftSendSuccessComponentFactory.create(
|
||||||
|
|
@ -189,7 +189,6 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
nftAsset = params.nftAsset,
|
nftAsset = params.nftAsset,
|
||||||
nftCollectionName = params.nftCollectionName,
|
nftCollectionName = params.nftCollectionName,
|
||||||
callback = model,
|
callback = model,
|
||||||
currentRoute = model.currentRouteFlow.filterIsInstance<CommonSendRoute.ConfirmSuccess>(),
|
|
||||||
txUrl = txUrl,
|
txUrl = txUrl,
|
||||||
account = model.account,
|
account = model.account,
|
||||||
isAccountsMode = model.isAccountsMode,
|
isAccountsMode = model.isAccountsMode,
|
||||||
|
|
@ -197,8 +196,6 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStubComponent() = ComposableContentComponent { }
|
|
||||||
|
|
||||||
private fun onChildBack() {
|
private fun onChildBack() {
|
||||||
val isEmptyRoute = childStack.value.active.configuration == CommonSendRoute.Empty
|
val isEmptyRoute = childStack.value.active.configuration == CommonSendRoute.Empty
|
||||||
val isEmptyStack = childStack.value.backStack.isEmpty()
|
val isEmptyStack = childStack.value.backStack.isEmpty()
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,28 @@
|
||||||
package com.tangem.features.send.sendnft.confirm
|
package com.tangem.features.send.sendnft.confirm
|
||||||
|
|
||||||
|
import androidx.compose.animation.*
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||||
|
import com.tangem.common.ui.footers.SendingText
|
||||||
|
import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.child
|
import com.tangem.core.decompose.context.child
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
|
||||||
|
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.extensions.wrappedList
|
import com.tangem.core.ui.extensions.wrappedList
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.models.account.Account
|
import com.tangem.domain.models.account.Account
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
|
@ -19,21 +30,20 @@ import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.nft.models.NFTAsset
|
import com.tangem.domain.nft.models.NFTAsset
|
||||||
import com.tangem.domain.transaction.error.GetFeeError
|
import com.tangem.domain.transaction.error.GetFeeError
|
||||||
import com.tangem.features.nft.component.NFTDetailsBlockComponent
|
import com.tangem.features.nft.component.NFTDetailsBlockComponent
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorBlockComponent
|
|
||||||
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent
|
|
||||||
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
||||||
import com.tangem.features.send.api.entity.PredefinedValues
|
import com.tangem.features.send.api.entity.PredefinedValues
|
||||||
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
|
||||||
|
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorBlockComponent
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.params.FeeSelectorParams
|
import com.tangem.features.send.api.subcomponents.feeSelector.params.FeeSelectorParams
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.params.FeeSelectorParams.FeeStateConfiguration
|
import com.tangem.features.send.api.subcomponents.feeSelector.params.FeeSelectorParams.FeeStateConfiguration
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
|
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent
|
||||||
import com.tangem.features.send.common.CommonSendRoute
|
|
||||||
import com.tangem.features.send.common.ui.state.ConfirmUM
|
import com.tangem.features.send.common.ui.state.ConfirmUM
|
||||||
|
import com.tangem.features.send.impl.R
|
||||||
import com.tangem.features.send.sendnft.confirm.model.NFTSendConfirmModel
|
import com.tangem.features.send.sendnft.confirm.model.NFTSendConfirmModel
|
||||||
import com.tangem.features.send.sendnft.confirm.ui.NFTSendConfirmContent
|
import com.tangem.features.send.sendnft.confirm.ui.NFTSendConfirmContent
|
||||||
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
||||||
import com.tangem.features.send.subcomponents.destination.DefaultSendDestinationBlockComponent
|
import com.tangem.features.send.subcomponents.destination.DefaultSendDestinationBlockComponent
|
||||||
import com.tangem.features.send.subcomponents.notifications.DefaultSendNotificationsComponent
|
import com.tangem.features.send.subcomponents.notifications.DefaultSendNotificationsComponent
|
||||||
import com.tangem.features.send.impl.R
|
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
|
@ -45,7 +55,7 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
|
||||||
@Assisted params: Params,
|
@Assisted params: Params,
|
||||||
nftDetailsBlockComponentFactory: NFTDetailsBlockComponent.Factory,
|
nftDetailsBlockComponentFactory: NFTDetailsBlockComponent.Factory,
|
||||||
feeSelectorComponentFactory: FeeSelectorBlockComponent.Factory,
|
feeSelectorComponentFactory: FeeSelectorBlockComponent.Factory,
|
||||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
) : ComposableModularContentComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val model: NFTSendConfirmModel = getOrCreateModel(params = params)
|
private val model: NFTSendConfirmModel = getOrCreateModel(params = params)
|
||||||
|
|
||||||
|
|
@ -129,6 +139,20 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
|
||||||
model.updateState(state)
|
model.updateState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Title() {
|
||||||
|
AppBarWithBackButtonAndIcon(
|
||||||
|
text = stringResourceSafe(R.string.nft_send),
|
||||||
|
onBackClick = {
|
||||||
|
model.onBackClick()
|
||||||
|
router.pop()
|
||||||
|
},
|
||||||
|
backIconRes = R.drawable.ic_back_24,
|
||||||
|
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||||
|
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.uiState.collectAsStateWithLifecycle()
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
@ -144,6 +168,29 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Footer() {
|
||||||
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
|
Column {
|
||||||
|
val sendingFooter = (state.confirmUM as? ConfirmUM.Content)?.sendingFooter
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = sendingFooter != null,
|
||||||
|
enter = slideInVertically(initialOffsetY = { it / 2 }) + fadeIn(),
|
||||||
|
exit = slideOutVertically(targetOffsetY = { it / 2 }) + fadeOut(),
|
||||||
|
) {
|
||||||
|
SendingText(footerText = sendingFooter ?: TextReference.EMPTY)
|
||||||
|
}
|
||||||
|
NavigationPrimaryButton(
|
||||||
|
primaryButton = model.primaryButtonUM(),
|
||||||
|
modifier = Modifier.padding(
|
||||||
|
start = 16.dp,
|
||||||
|
end = 16.dp,
|
||||||
|
bottom = 16.dp,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class Params(
|
data class Params(
|
||||||
val state: NFTSendUM,
|
val state: NFTSendUM,
|
||||||
val analyticsCategoryName: String,
|
val analyticsCategoryName: String,
|
||||||
|
|
@ -157,7 +204,6 @@ internal class NFTSendConfirmComponent @AssistedInject constructor(
|
||||||
val account: Account.CryptoPortfolio?,
|
val account: Account.CryptoPortfolio?,
|
||||||
val isAccountsMode: Boolean,
|
val isAccountsMode: Boolean,
|
||||||
val callback: ModelCallback,
|
val callback: ModelCallback,
|
||||||
val currentRoute: Flow<CommonSendRoute.Confirm>,
|
|
||||||
val isBalanceHidingFlow: StateFlow<Boolean>,
|
val isBalanceHidingFlow: StateFlow<Boolean>,
|
||||||
val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
|
val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
|
||||||
val onSendTransaction: () -> Unit,
|
val onSendTransaction: () -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import arrow.core.getOrElse
|
||||||
import com.tangem.blockchain.common.TransactionData
|
import com.tangem.blockchain.common.TransactionData
|
||||||
import com.tangem.common.routing.AppRouter
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationButton
|
import com.tangem.common.ui.navigationButtons.NavigationButton
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationUM
|
|
||||||
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
|
|
@ -32,28 +31,28 @@ import com.tangem.domain.transaction.usecase.CreateNFTTransferTransactionUseCase
|
||||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||||
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
|
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
|
||||||
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent
|
|
||||||
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent.Params.NotificationData
|
|
||||||
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
||||||
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents.SendScreenSource
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents.SendScreenSource
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.callbacks.FeeSelectorModelCallback
|
|
||||||
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorCheckReloadListener
|
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorCheckReloadListener
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorCheckReloadTrigger
|
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorCheckReloadTrigger
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorReloadTrigger
|
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorReloadTrigger
|
||||||
|
import com.tangem.features.send.api.subcomponents.feeSelector.callbacks.FeeSelectorModelCallback
|
||||||
|
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent
|
||||||
|
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent.Params.NotificationData
|
||||||
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsUpdateListener
|
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsUpdateListener
|
||||||
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsUpdateTrigger
|
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsUpdateTrigger
|
||||||
import com.tangem.features.send.common.CommonSendRoute
|
import com.tangem.features.send.common.CommonSendRoute
|
||||||
import com.tangem.features.send.common.SendBalanceUpdater
|
import com.tangem.features.send.common.SendBalanceUpdater
|
||||||
import com.tangem.features.send.common.SendConfirmAlertFactory
|
import com.tangem.features.send.common.SendConfirmAlertFactory
|
||||||
import com.tangem.features.send.common.ui.state.ConfirmUM
|
import com.tangem.features.send.common.ui.state.ConfirmUM
|
||||||
|
import com.tangem.features.send.impl.R
|
||||||
import com.tangem.features.send.sendnft.analytics.NFTSendAnalyticHelper
|
import com.tangem.features.send.sendnft.analytics.NFTSendAnalyticHelper
|
||||||
import com.tangem.features.send.sendnft.confirm.NFTSendConfirmComponent
|
import com.tangem.features.send.sendnft.confirm.NFTSendConfirmComponent
|
||||||
import com.tangem.features.send.sendnft.confirm.model.transformers.NFTSendConfirmInitialStateTransformer
|
import com.tangem.features.send.sendnft.confirm.model.transformers.NFTSendConfirmInitialStateTransformer
|
||||||
import com.tangem.features.send.sendnft.confirm.model.transformers.NFTSendConfirmSendingStateTransformer
|
import com.tangem.features.send.sendnft.confirm.model.transformers.NFTSendConfirmSendingStateTransformer
|
||||||
import com.tangem.features.send.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformerV2
|
import com.tangem.features.send.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformerV2
|
||||||
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
||||||
import com.tangem.features.send.impl.R
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import com.tangem.utils.extensions.stripZeroPlainString
|
import com.tangem.utils.extensions.stripZeroPlainString
|
||||||
import com.tangem.utils.logging.TangemLogger
|
import com.tangem.utils.logging.TangemLogger
|
||||||
|
|
@ -122,7 +121,6 @@ internal class NFTSendConfirmModel @Inject constructor(
|
||||||
private var sendIdleTimer: Long = 0L
|
private var sendIdleTimer: Long = 0L
|
||||||
|
|
||||||
init {
|
init {
|
||||||
configConfirmNavigation()
|
|
||||||
subscribeOnNotificationsUpdateTrigger()
|
subscribeOnNotificationsUpdateTrigger()
|
||||||
subscribeOnCheckFeeResultUpdates()
|
subscribeOnCheckFeeResultUpdates()
|
||||||
subscribeOnTapHelpUpdates()
|
subscribeOnTapHelpUpdates()
|
||||||
|
|
@ -371,54 +369,18 @@ internal class NFTSendConfirmModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configConfirmNavigation() {
|
fun onBackClick() {
|
||||||
combine(
|
analyticsEventHandler.send(
|
||||||
flow = uiState,
|
CommonSendAnalyticEvents.CloseButtonClicked(
|
||||||
flow2 = params.currentRoute,
|
categoryName = analyticsCategoryName,
|
||||||
transform = { state, route -> state to route },
|
source = SendScreenSource.Confirm,
|
||||||
).onEach { (state, _) ->
|
isFromSummary = true,
|
||||||
val confirmUM = state.confirmUM
|
isValid = uiState.value.confirmUM.isPrimaryButtonEnabled,
|
||||||
params.callback.onResult(
|
),
|
||||||
state.copy(
|
)
|
||||||
navigationUM = NavigationUM.Content(
|
|
||||||
source = CommonSendRoute.Confirm.javaClass.simpleName,
|
|
||||||
title = resourceReference(R.string.nft_send),
|
|
||||||
subtitle = null,
|
|
||||||
backIconRes = when (confirmUM) {
|
|
||||||
is ConfirmUM.Success -> R.drawable.ic_close_24
|
|
||||||
else -> R.drawable.ic_back_24
|
|
||||||
},
|
|
||||||
backIconClick = {
|
|
||||||
analyticsEventHandler.send(
|
|
||||||
CommonSendAnalyticEvents.CloseButtonClicked(
|
|
||||||
categoryName = analyticsCategoryName,
|
|
||||||
source = SendScreenSource.Confirm,
|
|
||||||
isFromSummary = true,
|
|
||||||
isValid = confirmUM.isPrimaryButtonEnabled,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
router.pop()
|
|
||||||
},
|
|
||||||
primaryButton = primaryButtonUM(),
|
|
||||||
prevButton = null,
|
|
||||||
secondaryPairButtonsUM = (
|
|
||||||
NavigationButton(
|
|
||||||
textReference = resourceReference(R.string.common_explore),
|
|
||||||
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 as? ConfirmUM.Success)?.txUrl.isNullOrBlank() },
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}.launchIn(modelScope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun primaryButtonUM(): NavigationButton {
|
fun primaryButtonUM(): NavigationButton {
|
||||||
val confirmUM = uiState.value.confirmUM
|
val confirmUM = uiState.value.confirmUM
|
||||||
val isContent = confirmUM is ConfirmUM.Content
|
val isContent = confirmUM is ConfirmUM.Content
|
||||||
val isReadyToSend = isContent && !confirmUM.isSending
|
val isReadyToSend = isContent && !confirmUM.isSending
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ import arrow.core.Either
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
import arrow.core.left
|
import arrow.core.left
|
||||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationUM
|
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
|
import com.tangem.core.decompose.navigation.Route
|
||||||
import com.tangem.core.decompose.navigation.Router
|
import com.tangem.core.decompose.navigation.Router
|
||||||
import com.tangem.datasource.local.nft.converter.NFTSdkAssetConverter
|
import com.tangem.datasource.local.nft.converter.NFTSdkAssetConverter
|
||||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||||
|
|
@ -36,9 +36,9 @@ import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
|
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
|
||||||
import com.tangem.features.send.api.NFTSendComponent
|
import com.tangem.features.send.api.NFTSendComponent
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
|
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponent
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponent
|
||||||
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
||||||
|
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
|
||||||
import com.tangem.features.send.common.CommonSendRoute
|
import com.tangem.features.send.common.CommonSendRoute
|
||||||
import com.tangem.features.send.common.SendConfirmAlertFactory
|
import com.tangem.features.send.common.SendConfirmAlertFactory
|
||||||
import com.tangem.features.send.common.ui.state.ConfirmUM
|
import com.tangem.features.send.common.ui.state.ConfirmUM
|
||||||
|
|
@ -82,8 +82,6 @@ internal class NFTSendModel @Inject constructor(
|
||||||
|
|
||||||
val initialRoute = CommonSendRoute.Empty
|
val initialRoute = CommonSendRoute.Empty
|
||||||
|
|
||||||
val currentRouteFlow = MutableStateFlow<CommonSendRoute>(initialRoute)
|
|
||||||
|
|
||||||
private val userWalletId = params.userWalletId
|
private val userWalletId = params.userWalletId
|
||||||
private val nftAsset = params.nftAsset
|
private val nftAsset = params.nftAsset
|
||||||
|
|
||||||
|
|
@ -107,10 +105,6 @@ internal class NFTSendModel @Inject constructor(
|
||||||
initAppCurrency()
|
initAppCurrency()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNavigationResult(navigationUM: NavigationUM) {
|
|
||||||
uiState.update { it.copy(navigationUM = navigationUM) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResult(nftSendUM: NFTSendUM) {
|
override fun onResult(nftSendUM: NFTSendUM) {
|
||||||
uiState.value = nftSendUM
|
uiState.value = nftSendUM
|
||||||
}
|
}
|
||||||
|
|
@ -119,8 +113,8 @@ internal class NFTSendModel @Inject constructor(
|
||||||
uiState.update { it.copy(destinationUM = destinationUM) }
|
uiState.update { it.copy(destinationUM = destinationUM) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackClick() {
|
override fun onBackClick(currentRoute: Route) {
|
||||||
if (currentRouteFlow.value == CommonSendRoute.ConfirmSuccess) {
|
if (currentRoute == CommonSendRoute.ConfirmSuccess) {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
nftSendSuccessTrigger.triggerSuccessNFTSend()
|
nftSendSuccessTrigger.triggerSuccessNFTSend()
|
||||||
}
|
}
|
||||||
|
|
@ -128,14 +122,14 @@ internal class NFTSendModel @Inject constructor(
|
||||||
router.pop()
|
router.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNextClick() {
|
override fun onNextClick(currentRoute: Route) {
|
||||||
if (currentRouteFlow.value.isEditMode) {
|
if ((currentRoute as? CommonSendRoute)?.isEditMode == true) {
|
||||||
onBackClick()
|
onBackClick(currentRoute)
|
||||||
} else {
|
} else {
|
||||||
when (currentRouteFlow.value) {
|
when (currentRoute) {
|
||||||
is CommonSendRoute.Destination -> router.push(CommonSendRoute.Confirm)
|
is CommonSendRoute.Destination -> router.push(CommonSendRoute.Confirm)
|
||||||
CommonSendRoute.Confirm -> router.replaceAll(CommonSendRoute.ConfirmSuccess)
|
CommonSendRoute.Confirm -> router.replaceAll(CommonSendRoute.ConfirmSuccess)
|
||||||
else -> onBackClick()
|
else -> onBackClick(currentRoute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -241,6 +235,5 @@ internal class NFTSendModel @Inject constructor(
|
||||||
destinationUM = DestinationUM.Empty(),
|
destinationUM = DestinationUM.Empty(),
|
||||||
feeSelectorUM = FeeSelectorUM.Loading,
|
feeSelectorUM = FeeSelectorUM.Loading,
|
||||||
confirmUM = ConfirmUM.Empty,
|
confirmUM = ConfirmUM.Empty,
|
||||||
navigationUM = NavigationUM.Empty,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,27 @@
|
||||||
package com.tangem.features.send.sendnft.success
|
package com.tangem.features.send.sendnft.success
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.tangem.common.ui.navigationButtons.DoneButtons
|
||||||
|
import com.tangem.common.ui.navigationButtons.NavigationButton
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationModelCallback
|
import com.tangem.common.ui.navigationButtons.NavigationModelCallback
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.child
|
import com.tangem.core.decompose.context.child
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
|
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
|
||||||
|
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.domain.models.account.Account
|
import com.tangem.domain.models.account.Account
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
|
@ -19,24 +31,22 @@ import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
||||||
import com.tangem.features.send.api.entity.PredefinedValues
|
import com.tangem.features.send.api.entity.PredefinedValues
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationBlockComponent
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationBlockComponent
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
|
||||||
import com.tangem.features.send.common.CommonSendRoute
|
import com.tangem.features.send.impl.R
|
||||||
import com.tangem.features.send.sendnft.success.model.NFTSendSuccessModel
|
import com.tangem.features.send.sendnft.success.model.NFTSendSuccessModel
|
||||||
import com.tangem.features.send.sendnft.success.ui.NFTSendSuccessContent
|
import com.tangem.features.send.sendnft.success.ui.NFTSendSuccessContent
|
||||||
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
||||||
import com.tangem.features.send.impl.R
|
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
internal class NFTSendSuccessComponent @AssistedInject constructor(
|
internal class NFTSendSuccessComponent @AssistedInject constructor(
|
||||||
@Assisted appComponentContext: AppComponentContext,
|
@Assisted appComponentContext: AppComponentContext,
|
||||||
@Assisted params: Params,
|
@Assisted private val params: Params,
|
||||||
nftDetailsBlockComponentFactory: NFTDetailsBlockComponent.Factory,
|
nftDetailsBlockComponentFactory: NFTDetailsBlockComponent.Factory,
|
||||||
sendDestinationBlockComponentFactory: SendDestinationBlockComponent.Factory,
|
sendDestinationBlockComponentFactory: SendDestinationBlockComponent.Factory,
|
||||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
) : ComposableModularContentComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val model: NFTSendSuccessModel = getOrCreateModel(params = params)
|
private val model: NFTSendSuccessModel = getOrCreateModel(params = params)
|
||||||
|
|
||||||
|
|
@ -69,6 +79,19 @@ internal class NFTSendSuccessComponent @AssistedInject constructor(
|
||||||
onClick = {},
|
onClick = {},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Title() {
|
||||||
|
AppBarWithBackButtonAndIcon(
|
||||||
|
onBackClick = {
|
||||||
|
model.onBackClick()
|
||||||
|
router.pop()
|
||||||
|
},
|
||||||
|
backIconRes = R.drawable.ic_close_24,
|
||||||
|
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||||
|
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.uiState.collectAsStateWithLifecycle()
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
@ -80,11 +103,40 @@ internal class NFTSendSuccessComponent @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Footer() {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
.padding(
|
||||||
|
start = 16.dp,
|
||||||
|
end = 16.dp,
|
||||||
|
bottom = 16.dp,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
DoneButtons(
|
||||||
|
(NavigationButton(
|
||||||
|
textReference = resourceReference(R.string.common_explore),
|
||||||
|
iconRes = R.drawable.ic_web_24,
|
||||||
|
onClick = model::onExploreClick,
|
||||||
|
) to NavigationButton(
|
||||||
|
textReference = resourceReference(R.string.common_share),
|
||||||
|
iconRes = R.drawable.ic_share_24,
|
||||||
|
onClick = model::onShareClick,
|
||||||
|
)).takeIf { params.txUrl.isNotEmpty() },
|
||||||
|
)
|
||||||
|
PrimaryButton(
|
||||||
|
text = stringResourceSafe(R.string.common_close),
|
||||||
|
onClick = router::pop,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class Params(
|
data class Params(
|
||||||
val nftSendUMFlow: StateFlow<NFTSendUM>,
|
val nftSendUMFlow: StateFlow<NFTSendUM>,
|
||||||
val analyticsCategoryName: String,
|
val analyticsCategoryName: String,
|
||||||
val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
|
val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
|
||||||
val currentRoute: Flow<CommonSendRoute>,
|
|
||||||
val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
val userWallet: UserWallet,
|
val userWallet: UserWallet,
|
||||||
val nftAsset: NFTAsset,
|
val nftAsset: NFTAsset,
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,17 @@
|
||||||
package com.tangem.features.send.sendnft.success.model
|
package com.tangem.features.send.sendnft.success.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationButton
|
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationUM
|
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
import com.tangem.core.navigation.share.ShareManager
|
import com.tangem.core.navigation.share.ShareManager
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
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.api.analytics.CommonSendAnalyticEvents
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
||||||
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents.SendScreenSource
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents.SendScreenSource
|
||||||
import com.tangem.features.send.common.CommonSendRoute
|
|
||||||
import com.tangem.features.send.send.ui.state.SendUM
|
import com.tangem.features.send.send.ui.state.SendUM
|
||||||
import com.tangem.features.send.sendnft.success.NFTSendSuccessComponent
|
import com.tangem.features.send.sendnft.success.NFTSendSuccessComponent
|
||||||
import com.tangem.features.send.impl.R
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -37,71 +27,23 @@ internal class NFTSendSuccessModel @Inject constructor(
|
||||||
|
|
||||||
val uiState = params.nftSendUMFlow
|
val uiState = params.nftSendUMFlow
|
||||||
|
|
||||||
init {
|
fun onBackClick() {
|
||||||
configConfirmSuccessNavigation()
|
analyticsEventHandler.send(
|
||||||
|
CommonSendAnalyticEvents.CloseButtonClicked(
|
||||||
|
categoryName = params.analyticsCategoryName,
|
||||||
|
source = SendScreenSource.Confirm,
|
||||||
|
isFromSummary = true,
|
||||||
|
isValid = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configConfirmSuccessNavigation() {
|
fun onExploreClick() {
|
||||||
combine(
|
|
||||||
flow = uiState,
|
|
||||||
flow2 = params.currentRoute,
|
|
||||||
transform = { state, route -> state to route },
|
|
||||||
).filter { (state, route) ->
|
|
||||||
// Emit the success navigation exactly once. Building NavigationUM.Content here creates fresh
|
|
||||||
// lambdas every time, so the SendUM written back via callback.onResult is never equal to the
|
|
||||||
// previous one — without this guard the combine re-triggers itself endlessly and the success
|
|
||||||
// screen recomposes forever (never reaching Compose idle). See [REDACTED_TASK_KEY].
|
|
||||||
route is CommonSendRoute.ConfirmSuccess &&
|
|
||||||
(state.navigationUM as? NavigationUM.Content)?.source !=
|
|
||||||
CommonSendRoute.ConfirmSuccess.javaClass.simpleName
|
|
||||||
}.onEach { (state, _) ->
|
|
||||||
params.callback.onResult(
|
|
||||||
state.copy(
|
|
||||||
navigationUM = NavigationUM.Content(
|
|
||||||
source = CommonSendRoute.ConfirmSuccess.javaClass.simpleName,
|
|
||||||
title = stringReference(""),
|
|
||||||
subtitle = null,
|
|
||||||
backIconRes = R.drawable.ic_close_24,
|
|
||||||
backIconClick = {
|
|
||||||
analyticsEventHandler.send(
|
|
||||||
CommonSendAnalyticEvents.CloseButtonClicked(
|
|
||||||
categoryName = params.analyticsCategoryName,
|
|
||||||
source = SendScreenSource.Confirm,
|
|
||||||
isFromSummary = true,
|
|
||||||
isValid = true,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
params.callback.onBackClick()
|
|
||||||
},
|
|
||||||
primaryButton = NavigationButton(
|
|
||||||
textReference = resourceReference(R.string.common_close),
|
|
||||||
iconRes = null,
|
|
||||||
isEnabled = true,
|
|
||||||
isHapticClick = false,
|
|
||||||
onClick = params.callback::onBackClick,
|
|
||||||
),
|
|
||||||
prevButton = null,
|
|
||||||
secondaryPairButtonsUM = NavigationButton(
|
|
||||||
textReference = resourceReference(R.string.common_explore),
|
|
||||||
iconRes = R.drawable.ic_web_24,
|
|
||||||
onClick = ::onExploreClick,
|
|
||||||
) to NavigationButton(
|
|
||||||
textReference = resourceReference(R.string.common_share),
|
|
||||||
iconRes = R.drawable.ic_share_24,
|
|
||||||
onClick = ::onShareClick,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}.launchIn(modelScope)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onExploreClick() {
|
|
||||||
analyticsEventHandler.send(CommonSendAnalyticEvents.ExploreButtonClicked(params.analyticsCategoryName))
|
analyticsEventHandler.send(CommonSendAnalyticEvents.ExploreButtonClicked(params.analyticsCategoryName))
|
||||||
urlOpener.openUrl(params.txUrl)
|
urlOpener.openUrl(params.txUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onShareClick() {
|
fun onShareClick() {
|
||||||
analyticsEventHandler.send(CommonSendAnalyticEvents.ShareButtonClicked(params.analyticsCategoryName))
|
analyticsEventHandler.send(CommonSendAnalyticEvents.ShareButtonClicked(params.analyticsCategoryName))
|
||||||
shareManager.shareText(params.txUrl)
|
shareManager.shareText(params.txUrl)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationButtonsBlockV2
|
|
||||||
import com.tangem.core.ui.components.Fade
|
import com.tangem.core.ui.components.Fade
|
||||||
import com.tangem.core.ui.components.SpacerH
|
import com.tangem.core.ui.components.SpacerH
|
||||||
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
|
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
|
||||||
|
|
@ -23,8 +22,8 @@ import com.tangem.features.nft.component.NFTDetailsBlockComponent
|
||||||
import com.tangem.features.send.api.subcomponents.destination.SendDestinationBlockComponent
|
import com.tangem.features.send.api.subcomponents.destination.SendDestinationBlockComponent
|
||||||
import com.tangem.features.send.common.ui.FeeBlockSuccess
|
import com.tangem.features.send.common.ui.FeeBlockSuccess
|
||||||
import com.tangem.features.send.common.ui.state.ConfirmUM
|
import com.tangem.features.send.common.ui.state.ConfirmUM
|
||||||
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
|
||||||
import com.tangem.features.send.impl.R
|
import com.tangem.features.send.impl.R
|
||||||
|
import com.tangem.features.send.sendnft.ui.state.NFTSendUM
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -52,30 +51,20 @@ internal fun NFTSendSuccessContent(
|
||||||
label = "Animate success content",
|
label = "Animate success content",
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
Column {
|
Box(
|
||||||
Box(
|
modifier = Modifier
|
||||||
modifier = Modifier
|
.fillMaxWidth()
|
||||||
.weight(1f)
|
.background(TangemTheme.colors.background.tertiary),
|
||||||
.background(TangemTheme.colors.background.tertiary),
|
) {
|
||||||
) {
|
SuccessContent(
|
||||||
SuccessContent(
|
nftSendUM = nftSendUM,
|
||||||
nftSendUM = nftSendUM,
|
nftDetailsBlockComponent = nftDetailsBlockComponent,
|
||||||
nftDetailsBlockComponent = nftDetailsBlockComponent,
|
destinationBlockComponent = destinationBlockComponent,
|
||||||
destinationBlockComponent = destinationBlockComponent,
|
modifier = Modifier.fillMaxHeight(),
|
||||||
modifier = Modifier.fillMaxHeight(),
|
)
|
||||||
)
|
Fade(
|
||||||
Fade(
|
modifier = Modifier.align(Alignment.BottomCenter),
|
||||||
modifier = Modifier.align(Alignment.BottomCenter),
|
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||||
backgroundColor = TangemTheme.colors.background.tertiary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
NavigationButtonsBlockV2(
|
|
||||||
navigationUM = nftSendUM.navigationUM,
|
|
||||||
modifier = Modifier.padding(
|
|
||||||
start = 16.dp,
|
|
||||||
end = 16.dp,
|
|
||||||
bottom = 16.dp,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package com.tangem.features.send.sendnft.ui.state
|
package com.tangem.features.send.sendnft.ui.state
|
||||||
|
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationUM
|
|
||||||
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
|
|
||||||
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
||||||
|
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
|
||||||
import com.tangem.features.send.common.ui.state.ConfirmUM
|
import com.tangem.features.send.common.ui.state.ConfirmUM
|
||||||
|
|
||||||
internal data class NFTSendUM(
|
internal data class NFTSendUM(
|
||||||
val destinationUM: DestinationUM,
|
val destinationUM: DestinationUM,
|
||||||
val feeSelectorUM: FeeSelectorUM,
|
val feeSelectorUM: FeeSelectorUM,
|
||||||
val confirmUM: ConfirmUM,
|
val confirmUM: ConfirmUM,
|
||||||
val navigationUM: NavigationUM,
|
|
||||||
)
|
)
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
package com.tangem.features.send.sendnft.model
|
||||||
|
|
||||||
|
import arrow.core.left
|
||||||
|
import arrow.core.right
|
||||||
|
import com.tangem.core.decompose.model.MutableParamsContainer
|
||||||
|
import com.tangem.core.decompose.navigation.Router
|
||||||
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.nft.models.NFTAsset
|
||||||
|
import com.tangem.domain.wallets.models.errors.GetUserWalletError
|
||||||
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
|
import com.tangem.features.nft.entity.NFTSendSuccessTrigger
|
||||||
|
import com.tangem.features.send.api.NFTSendComponent
|
||||||
|
import com.tangem.features.send.common.CommonSendRoute
|
||||||
|
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.advanceUntilIdle
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.jupiter.api.AfterEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guards the NFT-send navigation refactor: [NFTSendModel.onBackClick] / [NFTSendModel.onNextClick] now
|
||||||
|
* receive the active [com.tangem.core.decompose.navigation.Route] as a parameter (instead of reading an
|
||||||
|
* internal `currentRouteFlow`). Routing is synchronous, so those assertions run without advancing; the
|
||||||
|
* one async effect — firing `NFTSendSuccessTrigger.triggerSuccessNFTSend()` when leaving the success
|
||||||
|
* screen — is verified after `advanceUntilIdle()`.
|
||||||
|
*
|
||||||
|
* `init {}` collectors are kept harmless under `advanceUntilIdle()` by stubbing the wallet lookup to the
|
||||||
|
* not-found branch (so no further currency/account fetching is reached) and the app-currency lookup.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
internal class NFTSendModelNavigationTest {
|
||||||
|
|
||||||
|
private val router: Router = mockk(relaxed = true)
|
||||||
|
private val getUserWalletUseCase: GetUserWalletUseCase = mockk(relaxed = true)
|
||||||
|
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase = mockk(relaxed = true)
|
||||||
|
private val nftSendSuccessTrigger: NFTSendSuccessTrigger = mockk(relaxed = true)
|
||||||
|
|
||||||
|
private var model: NFTSendModel? = null
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
fun tearDown() {
|
||||||
|
model?.onDestroy()
|
||||||
|
model = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN destination step WHEN onNextClick THEN pushes confirm`() = runTest {
|
||||||
|
val model = createModel(this)
|
||||||
|
|
||||||
|
model.onNextClick(CommonSendRoute.Destination(isEditMode = false))
|
||||||
|
|
||||||
|
verify(exactly = 1) { router.push(CommonSendRoute.Confirm) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN edit-mode destination WHEN onNextClick THEN pops instead of advancing`() = runTest {
|
||||||
|
val model = createModel(this)
|
||||||
|
|
||||||
|
model.onNextClick(CommonSendRoute.Destination(isEditMode = true))
|
||||||
|
|
||||||
|
verify(exactly = 1) { router.pop() }
|
||||||
|
verify(exactly = 0) { router.push(any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN destination step WHEN onBackClick THEN pops without firing success trigger`() = runTest {
|
||||||
|
val model = createModel(this)
|
||||||
|
|
||||||
|
model.onBackClick(CommonSendRoute.Destination(isEditMode = false))
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
verify(exactly = 1) { router.pop() }
|
||||||
|
coVerify(exactly = 0) { nftSendSuccessTrigger.triggerSuccessNFTSend() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN confirm-success route WHEN onBackClick THEN fires success trigger and pops`() = runTest {
|
||||||
|
val model = createModel(this)
|
||||||
|
|
||||||
|
model.onBackClick(CommonSendRoute.ConfirmSuccess)
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
coVerify(exactly = 1) { nftSendSuccessTrigger.triggerSuccessNFTSend() }
|
||||||
|
verify(exactly = 1) { router.pop() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createModel(testScope: TestScope): NFTSendModel {
|
||||||
|
every { getUserWalletUseCase(any()) } returns GetUserWalletError.UserWalletNotFound.left()
|
||||||
|
coEvery { getSelectedAppCurrencyUseCase.invokeSync() } returns AppCurrency.Default.right()
|
||||||
|
|
||||||
|
val params = NFTSendComponent.Params(
|
||||||
|
userWalletId = UserWalletId(stringValue = "0123456789"),
|
||||||
|
nftAsset = mockk<NFTAsset>(relaxed = true),
|
||||||
|
nftCollectionName = "Test Collection",
|
||||||
|
)
|
||||||
|
return NFTSendModel(
|
||||||
|
paramsContainer = MutableParamsContainer(value = params),
|
||||||
|
dispatchers = testScope.createTestingCoroutineDispatcherProvider(),
|
||||||
|
router = router,
|
||||||
|
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||||
|
getUserWalletUseCase = getUserWalletUseCase,
|
||||||
|
multiWalletCryptoCurrenciesSupplier = mockk(relaxed = true),
|
||||||
|
getFeePaidCryptoCurrencyStatusSyncUseCase = mockk(relaxed = true),
|
||||||
|
createNFTTransferTransactionUseCase = mockk(relaxed = true),
|
||||||
|
getFeeUseCase = mockk(relaxed = true),
|
||||||
|
saveBlockchainErrorUseCase = mockk(relaxed = true),
|
||||||
|
getWalletMetaInfoUseCase = mockk(relaxed = true),
|
||||||
|
sendFeedbackEmailUseCase = mockk(relaxed = true),
|
||||||
|
alertFactory = mockk(relaxed = true),
|
||||||
|
nftSendSuccessTrigger = nftSendSuccessTrigger,
|
||||||
|
isAccountsModeEnabledUseCase = mockk(relaxed = true),
|
||||||
|
getAccountCurrencyStatusUseCase = mockk(relaxed = true),
|
||||||
|
analyticsEventHandler = mockk(relaxed = true),
|
||||||
|
).also { model = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TestScope.createTestingCoroutineDispatcherProvider(): TestingCoroutineDispatcherProvider {
|
||||||
|
val testDispatcher = StandardTestDispatcher(testScheduler)
|
||||||
|
return TestingCoroutineDispatcherProvider(
|
||||||
|
main = testDispatcher,
|
||||||
|
mainImmediate = testDispatcher,
|
||||||
|
io = testDispatcher,
|
||||||
|
default = testDispatcher,
|
||||||
|
single = testDispatcher,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue