Updated on 2026-08-14
This commit is contained in:
parent
bb0aa53982
commit
e65bf8538b
5 changed files with 43 additions and 55 deletions
|
|
@ -28,25 +28,22 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.domain.models.account.derivationIndex
|
import com.tangem.domain.models.account.derivationIndex
|
||||||
import com.tangem.features.addressbook.AddressBookContactsBlockComponent
|
|
||||||
import com.tangem.features.addressbook.AddressBookFeatureToggles
|
|
||||||
import com.tangem.features.addressbook.AddressSelectorComponent
|
|
||||||
import com.tangem.features.send.api.FeeSelectorBlockComponent
|
import com.tangem.features.send.api.FeeSelectorBlockComponent
|
||||||
import com.tangem.features.send.api.SendComponent
|
import com.tangem.features.send.api.SendComponent
|
||||||
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
|
||||||
|
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.api.subcomponents.destination.entity.DestinationUM
|
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
|
||||||
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.SendContent
|
||||||
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.send.confirm.SendConfirmComponent
|
import com.tangem.features.send.send.confirm.SendConfirmComponent
|
||||||
import com.tangem.features.send.send.model.SendModel
|
import com.tangem.features.send.send.model.SendModel
|
||||||
import com.tangem.features.send.send.success.SendConfirmSuccessComponent
|
import com.tangem.features.send.send.success.SendConfirmSuccessComponent
|
||||||
import com.tangem.features.send.subcomponents.amount.SendAmountComponent
|
import com.tangem.features.send.subcomponents.amount.SendAmountComponent
|
||||||
import com.tangem.features.send.subcomponents.amount.SendAmountComponentParams
|
import com.tangem.features.send.subcomponents.amount.SendAmountComponentParams
|
||||||
import com.tangem.features.send.subcomponents.destination.DefaultSendDestinationBlockComponent
|
import com.tangem.features.send.subcomponents.destination.DefaultSendDestinationBlockComponent
|
||||||
import com.tangem.features.send.subcomponents.destination.DefaultSendDestinationComponent
|
|
||||||
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
|
||||||
|
|
@ -55,15 +52,13 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Suppress("LargeClass", "LongParameterList")
|
@Suppress("LargeClass")
|
||||||
internal class DefaultSendComponent @AssistedInject constructor(
|
internal class DefaultSendComponent @AssistedInject constructor(
|
||||||
@Assisted appComponentContext: AppComponentContext,
|
@Assisted appComponentContext: AppComponentContext,
|
||||||
@Assisted private val params: SendComponent.Params,
|
@Assisted private val params: SendComponent.Params,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
private val feeSelectorComponentFactory: FeeSelectorBlockComponent.Factory,
|
private val feeSelectorComponentFactory: FeeSelectorBlockComponent.Factory,
|
||||||
private val contactsBlockFactory: AddressBookContactsBlockComponent.Factory,
|
private val sendDestinationComponentFactory: SendDestinationComponent.Factory,
|
||||||
private val addressSelectorFactory: AddressSelectorComponent.Factory,
|
|
||||||
private val addressBookFeatureToggles: AddressBookFeatureToggles,
|
|
||||||
) : SendComponent, AppComponentContext by appComponentContext {
|
) : SendComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val stackNavigation = StackNavigation<CommonSendRoute>()
|
private val stackNavigation = StackNavigation<CommonSendRoute>()
|
||||||
|
|
@ -128,7 +123,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
activeComponent.updateState(model.uiState.value.amountUM)
|
activeComponent.updateState(model.uiState.value.amountUM)
|
||||||
}
|
}
|
||||||
is DefaultSendDestinationComponent -> {
|
is SendDestinationComponent -> {
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
CommonSendAnalyticEvents.AddressScreenOpened(
|
CommonSendAnalyticEvents.AddressScreenOpened(
|
||||||
categoryName = model.analyticCategoryName,
|
categoryName = model.analyticCategoryName,
|
||||||
|
|
@ -168,9 +163,9 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
||||||
is CommonSendRoute.ConfirmSuccess -> getConfirmSuccessComponent(factoryContext)
|
is CommonSendRoute.ConfirmSuccess -> getConfirmSuccessComponent(factoryContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDestinationComponent(factoryContext: AppComponentContext): DefaultSendDestinationComponent =
|
private fun getDestinationComponent(factoryContext: AppComponentContext): SendDestinationComponent =
|
||||||
DefaultSendDestinationComponent(
|
sendDestinationComponentFactory.create(
|
||||||
appComponentContext = factoryContext,
|
context = factoryContext,
|
||||||
params = SendDestinationComponentParams.DestinationParams(
|
params = SendDestinationComponentParams.DestinationParams(
|
||||||
state = model.uiState.value.destinationUM,
|
state = model.uiState.value.destinationUM,
|
||||||
currentRoute = model.currentRoute.filterIsInstance<CommonSendRoute.Destination>(),
|
currentRoute = model.currentRoute.filterIsInstance<CommonSendRoute.Destination>(),
|
||||||
|
|
@ -182,9 +177,6 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
||||||
cryptoCurrency = params.currency,
|
cryptoCurrency = params.currency,
|
||||||
callback = model,
|
callback = model,
|
||||||
),
|
),
|
||||||
addressBookFeatureToggles = addressBookFeatureToggles,
|
|
||||||
contactsBlockFactory = contactsBlockFactory,
|
|
||||||
addressSelectorFactory = addressSelectorFactory,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getAmountComponent(factoryContext: AppComponentContext): ComposableContentComponent {
|
private fun getAmountComponent(factoryContext: AppComponentContext): ComposableContentComponent {
|
||||||
|
|
|
||||||
|
|
@ -18,36 +18,30 @@ 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.ComposableContentComponent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.features.addressbook.AddressBookContactsBlockComponent
|
|
||||||
import com.tangem.features.addressbook.AddressBookFeatureToggles
|
|
||||||
import com.tangem.features.addressbook.AddressSelectorComponent
|
|
||||||
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.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.SendContent
|
||||||
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.NFTSendConfirmComponent
|
import com.tangem.features.send.sendnft.confirm.NFTSendConfirmComponent
|
||||||
import com.tangem.features.send.sendnft.model.NFTSendModel
|
import com.tangem.features.send.sendnft.model.NFTSendModel
|
||||||
import com.tangem.features.send.sendnft.success.NFTSendSuccessComponent
|
import com.tangem.features.send.sendnft.success.NFTSendSuccessComponent
|
||||||
import com.tangem.features.send.subcomponents.destination.DefaultSendDestinationComponent
|
|
||||||
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.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
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 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 contactsBlockFactory: AddressBookContactsBlockComponent.Factory,
|
private val sendDestinationComponentFactory: SendDestinationComponent.Factory,
|
||||||
private val addressSelectorFactory: AddressSelectorComponent.Factory,
|
|
||||||
private val addressBookFeatureToggles: AddressBookFeatureToggles,
|
|
||||||
) : NFTSendComponent, AppComponentContext by appComponentContext {
|
) : NFTSendComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val stackNavigation = StackNavigation<CommonSendRoute>()
|
private val stackNavigation = StackNavigation<CommonSendRoute>()
|
||||||
|
|
@ -103,7 +97,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
activeComponent.updateState(model.uiState.value)
|
activeComponent.updateState(model.uiState.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is DefaultSendDestinationComponent -> {
|
is SendDestinationComponent -> {
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
CommonSendAnalyticEvents.AddressScreenOpened(
|
CommonSendAnalyticEvents.AddressScreenOpened(
|
||||||
categoryName = analyticsCategoryName,
|
categoryName = analyticsCategoryName,
|
||||||
|
|
@ -138,9 +132,9 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
else -> getStubComponent()
|
else -> getStubComponent()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDestinationComponent(factoryContext: AppComponentContext): DefaultSendDestinationComponent =
|
private fun getDestinationComponent(factoryContext: AppComponentContext): SendDestinationComponent =
|
||||||
DefaultSendDestinationComponent(
|
sendDestinationComponentFactory.create(
|
||||||
appComponentContext = factoryContext,
|
context = factoryContext,
|
||||||
params = SendDestinationComponentParams.DestinationParams(
|
params = SendDestinationComponentParams.DestinationParams(
|
||||||
state = model.uiState.value.destinationUM,
|
state = model.uiState.value.destinationUM,
|
||||||
currentRoute = model.currentRouteFlow.filterIsInstance<CommonSendRoute.Destination>(),
|
currentRoute = model.currentRouteFlow.filterIsInstance<CommonSendRoute.Destination>(),
|
||||||
|
|
@ -152,9 +146,6 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
|
||||||
cryptoCurrency = model.cryptoCurrency,
|
cryptoCurrency = model.cryptoCurrency,
|
||||||
callback = model,
|
callback = model,
|
||||||
),
|
),
|
||||||
addressBookFeatureToggles = addressBookFeatureToggles,
|
|
||||||
contactsBlockFactory = contactsBlockFactory,
|
|
||||||
addressSelectorFactory = addressSelectorFactory,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getConfirmComponent(factoryContext: AppComponentContext) = nftSendConfirmComponentFactory.create(
|
private fun getConfirmComponent(factoryContext: AppComponentContext) = nftSendConfirmComponentFactory.create(
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import com.arkivanov.decompose.router.slot.activate
|
||||||
import com.arkivanov.decompose.router.slot.dismiss
|
import com.arkivanov.decompose.router.slot.dismiss
|
||||||
import com.tangem.common.routing.AppRoute
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.common.routing.entity.AddressBookOpenMode
|
import com.tangem.common.routing.entity.AddressBookOpenMode
|
||||||
import com.tangem.common.ui.account.AccountIconUM
|
|
||||||
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.navigationButtons.NavigationUM
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
|
|
@ -24,7 +23,6 @@ import com.tangem.domain.addressbook.model.Contact
|
||||||
import com.tangem.domain.addressbook.usecase.GetContactsUseCase
|
import com.tangem.domain.addressbook.usecase.GetContactsUseCase
|
||||||
import com.tangem.domain.feedback.SendBackupProblemEmailUseCase
|
import com.tangem.domain.feedback.SendBackupProblemEmailUseCase
|
||||||
import com.tangem.domain.models.account.AccountStatus
|
import com.tangem.domain.models.account.AccountStatus
|
||||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
|
||||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.CryptoCurrencyAddress
|
import com.tangem.domain.models.network.CryptoCurrencyAddress
|
||||||
|
|
@ -160,9 +158,7 @@ internal class SendDestinationModel @Inject constructor(
|
||||||
.onEach {
|
.onEach {
|
||||||
val content = uiState.value as? DestinationUM.Content ?: return@onEach
|
val content = uiState.value as? DestinationUM.Content ?: return@onEach
|
||||||
if (content.addressTextField.contactName != null) {
|
if (content.addressTextField.contactName != null) {
|
||||||
_uiState.update(SendDestinationContactTransformer(contactName = null, contactIcon = null))
|
_uiState.update(SendDestinationContactTransformer(contact = null))
|
||||||
_uiState.update(SendDestinationAddressTransformer(address = "", isPasted = false))
|
|
||||||
validate(address = "", memo = content.memoTextField?.value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
|
|
@ -478,32 +474,19 @@ internal class SendDestinationModel @Inject constructor(
|
||||||
|
|
||||||
private fun recognizeContact(type: EnterAddressSource?, isValidAddress: Boolean, address: String) {
|
private fun recognizeContact(type: EnterAddressSource?, isValidAddress: Boolean, address: String) {
|
||||||
if (type == null || type == EnterAddressSource.Contact) return
|
if (type == null || type == EnterAddressSource.Contact) return
|
||||||
val recognized = if (isValidAddress) findContactByAddress(address) else null
|
val contact = if (isValidAddress) findContactByAddress(address) else null
|
||||||
_uiState.update(SendDestinationContactTransformer(recognized?.name, recognized?.icon))
|
_uiState.update(SendDestinationContactTransformer(contact))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findContactByAddress(address: String): RecognizedContact? {
|
private fun findContactByAddress(address: String): Contact? {
|
||||||
val networkId = cryptoCurrency.network.rawId
|
val networkId = cryptoCurrency.network.rawId
|
||||||
contacts.value.forEach { contact ->
|
return contacts.value.firstOrNull { contact ->
|
||||||
val isMatch = contact.addressEntries.any { entry ->
|
contact.addressEntries.any { entry ->
|
||||||
entry.networkId.value == networkId && entry.address.equals(address, ignoreCase = true)
|
entry.networkId.value == networkId && entry.address.equals(address, ignoreCase = true)
|
||||||
}
|
}
|
||||||
if (isMatch) {
|
|
||||||
return RecognizedContact(
|
|
||||||
name = contact.name.value,
|
|
||||||
// TODO([REDACTED_TASK_KEY]): take the color from the domain Contact once the data layer stores it.
|
|
||||||
icon = AccountIconUM.CryptoPortfolio(
|
|
||||||
value = CryptoPortfolioIcon.Icon.Letter,
|
|
||||||
color = CryptoPortfolioIcon.Color.Azure,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class RecognizedContact(val name: String, val icon: AccountIconUM.CryptoPortfolio)
|
|
||||||
|
|
||||||
private fun autoNextFromRecipient(type: EnterAddressSource, isValidAddress: Boolean, isValidMemo: Boolean) {
|
private fun autoNextFromRecipient(type: EnterAddressSource, isValidAddress: Boolean, isValidMemo: Boolean) {
|
||||||
if (type.isAutoNext && isValidAddress && isValidMemo) {
|
if (type.isAutoNext && isValidAddress && isValidMemo) {
|
||||||
saveResult()
|
saveResult()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.tangem.features.send.subcomponents.destination.model.converter
|
||||||
|
|
||||||
|
import com.tangem.common.ui.account.AccountIconUM
|
||||||
|
import com.tangem.domain.addressbook.model.Contact
|
||||||
|
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||||
|
import com.tangem.utils.converter.Converter
|
||||||
|
|
||||||
|
internal object ContactIconConverter : Converter<Contact, AccountIconUM.CryptoPortfolio> {
|
||||||
|
|
||||||
|
override fun convert(value: Contact): AccountIconUM.CryptoPortfolio = AccountIconUM.CryptoPortfolio(
|
||||||
|
value = CryptoPortfolioIcon.Icon.Letter,
|
||||||
|
color = CryptoPortfolioIcon.Color.entries.firstOrNull { it.name == value.iconColor }
|
||||||
|
?: CryptoPortfolioIcon.Color.Azure,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package com.tangem.features.send.subcomponents.destination.model.transformers
|
package com.tangem.features.send.subcomponents.destination.model.transformers
|
||||||
|
|
||||||
import com.tangem.common.ui.account.AccountIconUM
|
import com.tangem.common.ui.account.AccountIconUM
|
||||||
|
import com.tangem.domain.addressbook.model.Contact
|
||||||
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.subcomponents.destination.model.converter.ContactIconConverter
|
||||||
import com.tangem.utils.transformer.Transformer
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
|
||||||
internal class SendDestinationContactTransformer(
|
internal class SendDestinationContactTransformer(
|
||||||
|
|
@ -9,6 +11,11 @@ internal class SendDestinationContactTransformer(
|
||||||
private val contactIcon: AccountIconUM.CryptoPortfolio?,
|
private val contactIcon: AccountIconUM.CryptoPortfolio?,
|
||||||
) : Transformer<DestinationUM> {
|
) : Transformer<DestinationUM> {
|
||||||
|
|
||||||
|
constructor(contact: Contact?) : this(
|
||||||
|
contactName = contact?.name?.value,
|
||||||
|
contactIcon = contact?.let(ContactIconConverter::convert),
|
||||||
|
)
|
||||||
|
|
||||||
override fun transform(prevState: DestinationUM): DestinationUM {
|
override fun transform(prevState: DestinationUM): DestinationUM {
|
||||||
val state = prevState as? DestinationUM.Content ?: return prevState
|
val state = prevState as? DestinationUM.Content ?: return prevState
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue