Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-18 18:55:47 +05:00
parent b7dc46ae64
commit 9df1b84404
13 changed files with 261 additions and 11 deletions

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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,
}