Updated on 2026-08-14
This commit is contained in:
parent
b7dc46ae64
commit
9df1b84404
13 changed files with 261 additions and 11 deletions
|
|
@ -24,8 +24,10 @@ import com.tangem.features.onramp.component.*
|
|||
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
|
||||
import com.tangem.features.send.v2.api.NFTSendComponent
|
||||
import com.tangem.features.send.v2.api.SendComponent
|
||||
import com.tangem.features.send.v2.api.SendEntryPointComponent
|
||||
import com.tangem.features.staking.api.StakingComponent
|
||||
import com.tangem.features.swap.SwapComponent
|
||||
import com.tangem.features.swap.v2.api.SendWithSwapComponent
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.wallet.WalletEntryComponent
|
||||
import com.tangem.features.walletconnect.components.WalletConnectEntryComponent
|
||||
|
|
@ -85,6 +87,8 @@ internal class ChildFactory @Inject constructor(
|
|||
private val createWalletSelectionComponentFactory: CreateWalletSelectionComponent.Factory,
|
||||
private val createMobileWalletComponentFactory: CreateMobileWalletComponent.Factory,
|
||||
private val addExistingWalletComponentFactory: AddExistingWalletComponent.Factory,
|
||||
private val sendWithSwapComponentFactory: SendWithSwapComponent.Factory,
|
||||
private val sendEntryPointComponentFactory: SendEntryPointComponent.Factory,
|
||||
private val walletConnectFeatureToggles: WalletConnectFeatureToggles,
|
||||
) {
|
||||
|
||||
|
|
@ -442,6 +446,26 @@ internal class ChildFactory @Inject constructor(
|
|||
componentFactory = addExistingWalletComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.SendEntryPoint -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = SendEntryPointComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
cryptoCurrency = route.currency,
|
||||
),
|
||||
componentFactory = sendEntryPointComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.SendWithSwap -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = SendWithSwapComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
currency = route.currency,
|
||||
),
|
||||
componentFactory = sendWithSwapComponentFactory,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,4 +288,18 @@ sealed class AppRoute(val path: String) : Route {
|
|||
|
||||
@Serializable
|
||||
object AddExistingWallet : AppRoute(path = "/add_existing_wallet")
|
||||
|
||||
@Serializable
|
||||
data class SendEntryPoint(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
) : AppRoute(
|
||||
path = "/send_entry_point/${userWalletId.stringValue}/${currency.id.value}?",
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SendWithSwap(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
) : AppRoute(path = "/send_with_swap/${userWalletId.stringValue}/${currency.symbol}")
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ dependencies {
|
|||
/* Project - API */
|
||||
api(projects.features.markets.api)
|
||||
api(projects.features.onramp.api)
|
||||
api(projects.features.sendV2.api)
|
||||
|
||||
/* Data */
|
||||
implementation(projects.data.common)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioData
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.TokenActionsBSContentUM
|
||||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
import com.tangem.utils.Provider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -41,6 +42,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
|
|||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val messageSender: UiMessageSender,
|
||||
private val shareManager: ShareManager,
|
||||
private val sendFeatureToggles: SendFeatureToggles,
|
||||
) {
|
||||
|
||||
private val disabledActionsInDemoMode = buildSet {
|
||||
|
|
@ -157,12 +159,18 @@ internal class TokenActionsHandler @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun onSendClick(cryptoCurrencyData: PortfolioData.CryptoCurrencyData) {
|
||||
router.push(
|
||||
val route = if (sendFeatureToggles.isSendWithSwapEnabled) {
|
||||
AppRoute.SendEntryPoint(
|
||||
userWalletId = cryptoCurrencyData.userWallet.walletId,
|
||||
currency = cryptoCurrencyData.status.currency,
|
||||
)
|
||||
} else {
|
||||
AppRoute.Send(
|
||||
userWalletId = cryptoCurrencyData.userWallet.walletId,
|
||||
currency = cryptoCurrencyData.status.currency,
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
router.push(route)
|
||||
}
|
||||
|
||||
private fun onStakeClick(cryptoCurrencyData: PortfolioData.CryptoCurrencyData) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.send.v2.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface SendEntryPointComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, SendEntryPointComponent>
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ dependencies {
|
|||
implementation(projects.features.sendV2.api)
|
||||
implementation(projects.features.txhistory.api)
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.swapV2.api)
|
||||
|
||||
/** Libs */
|
||||
implementation(projects.libs.crypto)
|
||||
|
|
@ -64,6 +65,7 @@ dependencies {
|
|||
implementation(projects.domain.nft.models)
|
||||
implementation(projects.domain.nft)
|
||||
implementation(projects.domain.notifications)
|
||||
implementation(projects.domain.swap.models)
|
||||
|
||||
|
||||
/** Compose libraries */
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@ package com.tangem.features.send.v2.di
|
|||
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.features.send.v2.DefaultSendFeatureToggles
|
||||
import com.tangem.features.send.v2.api.NFTSendComponent
|
||||
import com.tangem.features.send.v2.api.SendComponent
|
||||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
import com.tangem.features.send.v2.api.SendNotificationsComponent
|
||||
import com.tangem.features.send.v2.api.*
|
||||
import com.tangem.features.send.v2.entrypoint.DefaultSendEntryPointComponent
|
||||
import com.tangem.features.send.v2.send.DefaultSendComponent
|
||||
import com.tangem.features.send.v2.sendnft.DefaultNFTSendComponent
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.DefaultSendNotificationsComponent
|
||||
|
|
@ -43,4 +41,10 @@ internal interface SendFeatureModuleBinds {
|
|||
fun provideNotificationComponentFactory(
|
||||
impl: DefaultSendNotificationsComponent.Factory,
|
||||
): SendNotificationsComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun provideSendEntryPointComponentFactory(
|
||||
impl: DefaultSendEntryPointComponent.Factory,
|
||||
): SendEntryPointComponent.Factory
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
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.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
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
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultSendEntryPointComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: SendEntryPointComponent.Params,
|
||||
sendWithSwapComponentFactory: SendWithSwapComponent.Factory,
|
||||
sendComponentFactory: SendComponent.Factory,
|
||||
) : SendEntryPointComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: SendEntryPointModel = getOrCreateModel(params = params)
|
||||
|
||||
private val sendWithSwapComponent = sendWithSwapComponentFactory.create(
|
||||
context = child("sendEntrySendWithSwap"),
|
||||
params = SendWithSwapComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = params.cryptoCurrency,
|
||||
callback = model,
|
||||
),
|
||||
)
|
||||
|
||||
private val sendComponent = sendComponentFactory.create(
|
||||
context = child("sendEntryVanillaSend"),
|
||||
params = SendComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = params.cryptoCurrency,
|
||||
callback = model,
|
||||
),
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val sendEntryState by model.sendEntryPointState.collectAsStateWithLifecycle()
|
||||
|
||||
sendComponent.Content(modifier)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = sendEntryState == SendEntryPoint.SendWithSwap,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
sendWithSwapComponent.Content(modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : SendEntryPointComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: SendEntryPointComponent.Params,
|
||||
): DefaultSendEntryPointComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.send.v2.entrypoint.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.send.v2.entrypoint.model.SendEntryPointModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface SendEntryPointModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SendEntryPointModel::class)
|
||||
fun provideSendEntryPointModel(model: SendEntryPointModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.features.send.v2.entrypoint.model
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.features.send.v2.api.SendComponent
|
||||
import com.tangem.features.send.v2.api.SendEntryPointComponent
|
||||
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.launch
|
||||
|
||||
@ModelScoped
|
||||
internal class SendEntryPointModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
val appRouter: AppRouter,
|
||||
private val swapChooseTokenNetworkListener: SwapChooseTokenNetworkListener,
|
||||
private val sendAmountUpdateTrigger: SendAmountUpdateTrigger,
|
||||
private val swapAmountUpdateTrigger: SwapAmountUpdateTrigger,
|
||||
) : Model(), SendComponent.ModelCallback, SendWithSwapComponent.ModelCallback {
|
||||
|
||||
private val params: SendEntryPointComponent.Params = paramsContainer.require()
|
||||
|
||||
val sendEntryPointState: StateFlow<SendEntryPoint>
|
||||
field = MutableStateFlow(SendEntryPoint.SendVanilla)
|
||||
|
||||
private var swapChooseTokenListenerJobHolder = JobHolder()
|
||||
|
||||
override fun onConvertToAnotherToken(lastAmount: String) {
|
||||
appRouter.push(
|
||||
AppRoute.ChooseManagedTokens(
|
||||
userWalletId = params.userWalletId,
|
||||
initialCurrency = params.cryptoCurrency,
|
||||
source = AppRoute.ChooseManagedTokens.Source.SendViaSwap,
|
||||
),
|
||||
)
|
||||
observeChooseSelectToken(lastAmount)
|
||||
}
|
||||
|
||||
override fun onCloseSwap(lastAmount: String) {
|
||||
modelScope.launch {
|
||||
if (lastAmount.isNotBlank()) {
|
||||
sendAmountUpdateTrigger.triggerUpdateAmount(lastAmount)
|
||||
}
|
||||
triggerScreenUpdate(SendEntryPoint.SendVanilla)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeChooseSelectToken(lastAmount: String) {
|
||||
swapChooseTokenNetworkListener.swapChooseTokenNetworkResultFlow
|
||||
.onEach { currency ->
|
||||
if (lastAmount.isNotBlank()) {
|
||||
swapAmountUpdateTrigger.triggerUpdateAmount(lastAmount)
|
||||
}
|
||||
triggerScreenUpdate(SendEntryPoint.SendWithSwap)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
.saveIn(swapChooseTokenListenerJobHolder)
|
||||
}
|
||||
|
||||
private fun triggerScreenUpdate(entry: SendEntryPoint) {
|
||||
swapChooseTokenListenerJobHolder.cancel()
|
||||
sendEntryPointState.update { entry }
|
||||
}
|
||||
}
|
||||
|
||||
enum class SendEntryPoint {
|
||||
SendVanilla,
|
||||
SendWithSwap,
|
||||
}
|
||||
|
|
@ -101,5 +101,6 @@ dependencies {
|
|||
implementation(projects.features.pushNotifications.api)
|
||||
implementation(projects.features.swap.api)
|
||||
implementation(projects.features.txhistory.api)
|
||||
implementation(projects.features.sendV2.api)
|
||||
|
||||
}
|
||||
|
|
@ -80,6 +80,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBala
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory
|
||||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
|
||||
|
|
@ -137,6 +138,7 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val router: InnerTokenDetailsRouter,
|
||||
private val tokenDetailsDeepLinkActionListener: TokenDetailsDeepLinkActionListener,
|
||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
private val sendFeatureToggles: SendFeatureToggles,
|
||||
) : Model(), TokenDetailsClickIntents {
|
||||
|
||||
private val params = paramsContainer.require<TokenDetailsComponent.Params>()
|
||||
|
|
@ -564,10 +566,17 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun sendCurrency() {
|
||||
val route = AppRoute.Send(
|
||||
currency = cryptoCurrency,
|
||||
userWalletId = userWallet.walletId,
|
||||
)
|
||||
val route = if (sendFeatureToggles.isSendWithSwapEnabled) {
|
||||
AppRoute.SendEntryPoint(
|
||||
currency = cryptoCurrency,
|
||||
userWalletId = userWallet.walletId,
|
||||
)
|
||||
} else {
|
||||
AppRoute.Send(
|
||||
currency = cryptoCurrency,
|
||||
userWalletId = userWallet.walletId,
|
||||
)
|
||||
}
|
||||
|
||||
appRouter.push(route)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ dependencies {
|
|||
implementation(projects.features.walletSettings.api)
|
||||
implementation(projects.features.biometry.api)
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.sendV2.api)
|
||||
|
||||
/** Common modules */
|
||||
implementation(projects.common)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue