Updated on 2026-08-14
This commit is contained in:
parent
469c0a4317
commit
6c8285847f
11 changed files with 347 additions and 12 deletions
|
|
@ -19,6 +19,7 @@ import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
|
|||
import com.tangem.features.onramp.component.*
|
||||
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
|
||||
import com.tangem.features.send.api.SendComponent
|
||||
import com.tangem.features.send.v2.api.NFTSendComponent
|
||||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
import com.tangem.features.staking.api.StakingComponent
|
||||
import com.tangem.features.swap.SwapComponent
|
||||
|
|
@ -86,6 +87,7 @@ internal class ChildFactory @Inject constructor(
|
|||
private val nftCollectionsComponentFactory: NFTCollectionsComponent.Factory,
|
||||
private val nftReceiveComponentFactory: NFTReceiveComponent.Factory,
|
||||
private val nftDetailsComponentFactory: NFTDetailsComponent.Factory,
|
||||
private val nftSendComponentFactory: NFTSendComponent.Factory,
|
||||
private val testerRouter: TesterRouter,
|
||||
private val routingFeatureToggles: RoutingFeatureToggles,
|
||||
private val walletConnectFeatureToggles: WalletConnectFeatureToggles,
|
||||
|
|
@ -423,6 +425,17 @@ internal class ChildFactory @Inject constructor(
|
|||
params = NFTDetailsComponent.Params(userWalletId = route.userWalletId, nftAsset = route.nftAsset),
|
||||
componentFactory = nftDetailsComponentFactory,
|
||||
)
|
||||
is AppRoute.NFTSend -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = NFTSendComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
nftAsset = route.nftAsset,
|
||||
nftCollectionName = route.nftCollectionName,
|
||||
),
|
||||
componentFactory = nftSendComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.OnboardingNote,
|
||||
is AppRoute.SaveWallet,
|
||||
is AppRoute.OnboardingOther,
|
||||
|
|
@ -775,6 +788,17 @@ internal class ChildFactory @Inject constructor(
|
|||
params = NFTDetailsComponent.Params(userWalletId = route.userWalletId, nftAsset = route.nftAsset),
|
||||
componentFactory = nftDetailsComponentFactory,
|
||||
)
|
||||
is AppRoute.NFTSend -> {
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = NFTSendComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
nftAsset = route.nftAsset,
|
||||
nftCollectionName = route.nftCollectionName,
|
||||
),
|
||||
componentFactory = nftSendComponentFactory,
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,4 +295,11 @@ sealed class AppRoute(val path: String) : Route {
|
|||
val userWalletId: UserWalletId,
|
||||
val nftAsset: NFTAsset,
|
||||
) : AppRoute(path = "/nft_details/${userWalletId.stringValue}/${nftAsset.collectionId}/${nftAsset.id.stringValue}")
|
||||
|
||||
@Serializable
|
||||
data class NFTSend(
|
||||
val userWalletId: UserWalletId,
|
||||
val nftAsset: NFTAsset,
|
||||
val nftCollectionName: String,
|
||||
) : AppRoute(path = "/send/nft/${userWalletId.stringValue}/$nftCollectionName/${nftAsset.id}")
|
||||
}
|
||||
|
|
@ -16,4 +16,5 @@ dependencies {
|
|||
/** Domain models */
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.nft.models)
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
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.nft.models.NFTAsset
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface NFTSendComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val nftAsset: NFTAsset,
|
||||
val nftCollectionName: String,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, NFTSendComponent>
|
||||
}
|
||||
|
|
@ -2,9 +2,11 @@ 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.send.DefaultSendComponent
|
||||
import com.tangem.features.send.v2.sendnft.DefaultNFTSendComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -29,4 +31,8 @@ internal interface SendFeatureModuleBinds {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun provideSendComponentFactory(impl: DefaultSendComponent.Factory): SendComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun provideNFTSendComponentFactory(impl: DefaultNFTSendComponent.Factory): NFTSendComponent.Factory
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@ package com.tangem.features.send.v2.di
|
|||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.send.v2.send.confirm.model.SendConfirmModel
|
||||
import com.tangem.features.send.v2.send.model.SendModel
|
||||
import com.tangem.features.send.v2.subcomponents.amount.model.SendAmountModel
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.SendDestinationModel
|
||||
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeModel
|
||||
|
|
@ -18,11 +16,6 @@ import dagger.multibindings.IntoMap
|
|||
@InstallIn(ModelComponent::class)
|
||||
internal interface SendModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SendModel::class)
|
||||
fun provideSendModel(model: SendModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SendAmountModel::class)
|
||||
|
|
@ -38,11 +31,6 @@ internal interface SendModelModule {
|
|||
@ClassKey(SendFeeModel::class)
|
||||
fun provideSendFeeModel(model: SendFeeModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SendConfirmModel::class)
|
||||
fun provideSendConfirmModel(model: SendConfirmModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(NotificationsModel::class)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.send.v2.send.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.send.v2.send.confirm.model.SendConfirmModel
|
||||
import com.tangem.features.send.v2.send.model.SendModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface SendModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SendModel::class)
|
||||
fun provideSendModel(model: SendModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SendConfirmModel::class)
|
||||
fun provideSendConfirmModel(model: SendConfirmModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.tangem.features.send.v2.sendnft
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.send.v2.api.NFTSendComponent
|
||||
import com.tangem.features.send.v2.sendnft.model.NFTSendModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: NFTSendComponent.Params,
|
||||
) : NFTSendComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
// private val stackNavigation = StackNavigation<NFTSendRoute>()
|
||||
//
|
||||
// private val innerRouter = InnerRouter<NFTSendRoute>(
|
||||
// stackNavigation = stackNavigation,
|
||||
// popCallback = { onChildBack() },
|
||||
// )
|
||||
|
||||
// private val initialRoute = NFTSendRoute.Empty
|
||||
// private val currentRouteFlow = MutableStateFlow<NFTSendRoute>(initialRoute)
|
||||
|
||||
private val model: NFTSendModel = getOrCreateModel(params = params/*, router = innerRouter*/)
|
||||
|
||||
// private val childStack = childStack(
|
||||
// key = "NFTSendInnerStack",
|
||||
// source = stackNavigation,
|
||||
// serializer = null,
|
||||
// initialConfiguration = initialRoute,
|
||||
// handleBackButton = true,
|
||||
// childFactory = { configuration, factoryContext ->
|
||||
// // todo
|
||||
// ComposableContentComponent { }
|
||||
// },
|
||||
// )
|
||||
|
||||
init {
|
||||
// childStack.subscribe(
|
||||
// lifecycle = lifecycle,
|
||||
// mode = ObserveLifecycleMode.CREATE_DESTROY,
|
||||
// ) { stack ->
|
||||
// componentScope.launch {
|
||||
// when (val activeComponent = stack.active.instance) {
|
||||
// is SendDestinationComponent -> {
|
||||
// // analyticsEventHandler.send(SendAnalyticEvents.AddressScreenOpened)
|
||||
// activeComponent.updateState(model.uiState.value.destinationUM)
|
||||
// }
|
||||
// is SendFeeComponent -> {
|
||||
// // analyticsEventHandler.send(SendAnalyticEvents.FeeScreenOpened)
|
||||
// }
|
||||
// }
|
||||
// currentRouteFlow.emit(stack.active.configuration)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
// val stackState by childStack.subscribeAsState()
|
||||
// val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
BackHandler(onBack = ::onChildBack)
|
||||
// TODO
|
||||
}
|
||||
|
||||
private fun onChildBack() {
|
||||
// TODO
|
||||
// val isEmptyRoute = childStack.value.active.configuration == NFTSendRoute.Empty
|
||||
// val isEmptyStack = childStack.value.backStack.isEmpty()
|
||||
// val isSuccess = model.uiState.value.confirmUM is ConfirmUM.Success
|
||||
//
|
||||
// if (isEmptyRoute || isEmptyStack || isSuccess) {
|
||||
// router.pop()
|
||||
// } else {
|
||||
// stackNavigation.pop()
|
||||
// }
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : NFTSendComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: NFTSendComponent.Params): DefaultNFTSendComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.send.v2.sendnft.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.send.v2.sendnft.model.NFTSendModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface NFTSendModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(NFTSendModel::class)
|
||||
fun provideNFTSendModel(model: NFTSendModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
package com.tangem.features.send.v2.sendnft.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
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.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.send.v2.api.NFTSendComponent
|
||||
import com.tangem.features.send.v2.common.NavigationUM
|
||||
import com.tangem.features.send.v2.send.confirm.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.sendnft.ui.state.NFTSendUM
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponent
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponent
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
internal interface SendNFTComponentCallback :
|
||||
SendFeeComponent.ModelCallback,
|
||||
SendDestinationComponent.ModelCallback
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class NFTSendModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase,
|
||||
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
|
||||
) : Model(), SendNFTComponentCallback {
|
||||
|
||||
val params: NFTSendComponent.Params = paramsContainer.require()
|
||||
private val userWalletId = params.userWalletId
|
||||
|
||||
private val _uiState = MutableStateFlow(initialState())
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
private val _isBalanceHiddenFlow = MutableStateFlow(false)
|
||||
val isBalanceHiddenFlow = _isBalanceHiddenFlow.asStateFlow()
|
||||
|
||||
var cryptoCurrency: CryptoCurrency by Delegates.notNull()
|
||||
var userWallet: UserWallet by Delegates.notNull()
|
||||
var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
var feeCryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
var appCurrency: AppCurrency = AppCurrency.Default
|
||||
|
||||
init {
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
initAppCurrency()
|
||||
}
|
||||
|
||||
override fun onNavigationResult(navigationUM: NavigationUM) {
|
||||
_uiState.update { it.copy(navigationUM = navigationUM) }
|
||||
}
|
||||
|
||||
override fun onDestinationResult(destinationUM: DestinationUM) {
|
||||
_uiState.update { it.copy(destinationUM = destinationUM) }
|
||||
|
||||
// todo
|
||||
}
|
||||
|
||||
override fun onFeeResult(feeUM: FeeUM) {
|
||||
_uiState.update { it.copy(feeUM = feeUM) }
|
||||
router.pop()
|
||||
}
|
||||
|
||||
private fun initAppCurrency() {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
modelScope.launch {
|
||||
getUserWalletUseCase(params.userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
|
||||
// cryptoCurrency = getCryptoCurrenciesUseCase(userWalletId).getOrNull()
|
||||
// ?.filterIsInstance<CryptoCurrency.Coin>()
|
||||
// ?.firstOrNull { it.network == nftAsset.network }
|
||||
// ?: return@launch
|
||||
|
||||
getCurrenciesStatusUpdates(
|
||||
isSingleWalletWithToken = wallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
|
||||
)
|
||||
},
|
||||
ifLeft = {
|
||||
// sendConfirmAlertFactory.getGenericErrorState(::onFailedTxEmailClick)
|
||||
return@launch
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrenciesStatusUpdates(isSingleWalletWithToken: Boolean) {
|
||||
getCurrencyStatusUpdatesUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = isSingleWalletWithToken,
|
||||
).onEach { maybeCryptoCurrency ->
|
||||
maybeCryptoCurrency.fold(
|
||||
ifRight = { cryptoStatus ->
|
||||
cryptoCurrencyStatus = cryptoStatus
|
||||
feeCryptoCurrencyStatus = getFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyStatus = cryptoStatus,
|
||||
).getOrNull() ?: cryptoStatus
|
||||
|
||||
// router.push(NFTSendRoute.Destination(isEditMode = false))
|
||||
},
|
||||
ifLeft = {
|
||||
// sendConfirmAlertFactory.getGenericErrorState {
|
||||
// onFailedTxEmailClick(it.toString())
|
||||
// }
|
||||
},
|
||||
)
|
||||
}.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun initialState(): NFTSendUM = NFTSendUM(
|
||||
destinationUM = DestinationUM.Empty(),
|
||||
feeUM = FeeUM.Empty(),
|
||||
confirmUM = ConfirmUM.Empty,
|
||||
navigationUM = NavigationUM.Empty,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.send.v2.sendnft.ui.state
|
||||
|
||||
import com.tangem.features.send.v2.common.NavigationUM
|
||||
import com.tangem.features.send.v2.send.confirm.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
|
||||
|
||||
internal data class NFTSendUM(
|
||||
val destinationUM: DestinationUM,
|
||||
val feeUM: FeeUM,
|
||||
val confirmUM: ConfirmUM,
|
||||
val navigationUM: NavigationUM,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue