Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-10 18:00:43 +05:00
parent 1de582a28c
commit 6d049b8d70
19 changed files with 132 additions and 31 deletions

View file

@ -2,6 +2,7 @@ package com.tangem.features.managetokens.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.models.account.Account
interface AddCustomTokenComponent : ComposableBottomSheetComponent {
@ -9,7 +10,7 @@ interface AddCustomTokenComponent : ComposableBottomSheetComponent {
val mode: AddCustomTokenMode,
val source: ManageTokensSource,
val onDismiss: () -> Unit,
val onCurrencyAdded: () -> Unit,
val onCurrencyAdded: (account: Account?) -> Unit,
)
interface Factory : ComponentFactory<Params, AddCustomTokenComponent>

View file

@ -3,11 +3,13 @@ package com.tangem.features.managetokens.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableDialogComponent
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
internal interface CustomTokenDerivationInputComponent : ComposableDialogComponent {
data class Params(
val mode: AddCustomTokenMode,
val selectedNetwork: SelectedNetwork,
val onConfirm: (SelectedDerivationPath) -> Unit,
val onDismiss: () -> Unit,
)

View file

@ -2,6 +2,7 @@ package com.tangem.features.managetokens.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.models.account.Account
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
@ -19,7 +20,7 @@ internal interface CustomTokenSelectorComponent : ComposableContentComponent {
val mode: AddCustomTokenMode,
val selectedNetwork: SelectedNetwork,
val selectedDerivationPath: SelectedDerivationPath?,
val onDerivationPathSelected: (SelectedDerivationPath) -> Unit,
val onDerivationPathSelected: (SelectedDerivationPath, Account?) -> Unit,
) : Params()
}

View file

@ -14,6 +14,7 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.network.Network
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
import com.tangem.features.managetokens.component.AddCustomTokenComponent
@ -42,6 +43,8 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor(
step = AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR,
)
private var addedToAccount: Account? = null
private val navigation = StackNavigation<AddCustomTokenConfig>()
private val contentStack = childStack(
key = "add_custom_token_content_stack",
@ -57,6 +60,7 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor(
}
override fun dismiss() {
addedToAccount = null
params.onDismiss()
}
@ -163,12 +167,13 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor(
showForm(network = network)
}
private fun changeDerivationPath(derivationPath: SelectedDerivationPath) {
private fun changeDerivationPath(derivationPath: SelectedDerivationPath, account: Account?) {
val event = CustomTokenAnalyticsEvent.DerivationSelected(
derivationName = derivationPath.name,
source = params.source,
)
analyticsEventHandler.send(event)
addedToAccount = account
showForm(derivationPath = derivationPath)
}
@ -228,8 +233,8 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor(
}
private fun dismissAndNotify() {
params.onCurrencyAdded(addedToAccount)
dismiss()
params.onCurrencyAdded()
}
@AssistedFactory

View file

@ -108,7 +108,7 @@ internal class DefaultCustomTokenDerivationInputComponent @AssistedInject constr
val value = state.value.value.text
val model = SelectedDerivationPath(
id = null,
id = params.selectedNetwork.id,
value = Network.DerivationPath.Custom(value),
name = value,
isDefault = false,

View file

@ -42,6 +42,7 @@ internal class DefaultCustomTokenSelectorComponent @AssistedInject constructor(
context = childByContext(context),
params = CustomTokenDerivationInputComponent.Params(
mode = config.mode,
selectedNetwork = config.network,
onConfirm = model::selectCustomDerivationPath,
onDismiss = model.dialogNavigation::dismiss,
),

View file

@ -12,10 +12,16 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountName
import com.tangem.features.managetokens.component.AddCustomTokenComponent
import com.tangem.features.managetokens.component.AddCustomTokenMode
import com.tangem.features.managetokens.component.ManageTokensComponent
import com.tangem.features.managetokens.entity.managetokens.ManageTokensBottomSheetConfig
import com.tangem.features.managetokens.impl.R
import com.tangem.features.managetokens.model.ManageTokensModel
import com.tangem.features.managetokens.ui.ManageTokensScreen
import dagger.assisted.Assisted
@ -64,7 +70,20 @@ internal class DefaultManageTokensComponent @AssistedInject constructor(
mode = mode,
source = params.source,
onDismiss = model.bottomSheetNavigation::dismiss,
onCurrencyAdded = model::reloadList,
onCurrencyAdded = { account ->
val accountName = account?.accountName as? AccountName.Custom
if (accountName != null && (account as? Account.CryptoPortfolio)?.isMainAccount == false) {
messageSender.send(
SnackbarMessage(
message = resourceReference(
R.string.custom_token_another_account_snackbar_text,
wrappedList(accountName.value),
),
),
)
}
model.reloadList()
},
),
)
}

View file

@ -63,7 +63,7 @@ internal class PreviewAddCustomTokenComponent(
mode = config.mode,
selectedNetwork = config.selectedNetwork!!,
selectedDerivationPath = config.selectedDerivationPath!!,
onDerivationPathSelected = {},
onDerivationPathSelected = { _, _ -> },
),
).Content(modifier)
}

View file

@ -43,7 +43,7 @@ internal class PreviewCustomTokenSelectorComponent(
value = d.value.value.orEmpty(),
networkName = stringReference(d.name),
isSelected = d.value == params.selectedDerivationPath?.value,
onSelectedStateChange = { params.onDerivationPathSelected(d) },
onSelectedStateChange = { params.onDerivationPathSelected(d, null) },
)
}
is Params.NetworkSelector -> {

View file

@ -9,5 +9,6 @@ internal sealed class CustomTokenSelectorDialogConfig {
@Serializable
data class CustomDerivationInput(
val mode: AddCustomTokenMode,
val network: SelectedNetwork,
) : CustomTokenSelectorDialogConfig()
}

View file

@ -18,6 +18,7 @@ import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.managetokens.GetSupportedNetworksUseCase
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.network.Network
import com.tangem.features.managetokens.component.AddCustomTokenMode
@ -126,7 +127,7 @@ internal class CustomTokenSelectorModel @Inject constructor(
isDefault = true,
)
selector.onDerivationPathSelected(model)
selector.onDerivationPathSelected(model, null)
},
)
}
@ -151,7 +152,7 @@ internal class CustomTokenSelectorModel @Inject constructor(
isDefault = false,
)
selector.onDerivationPathSelected(model)
selector.onDerivationPathSelected(model, null)
},
)
}
@ -171,7 +172,10 @@ internal class CustomTokenSelectorModel @Inject constructor(
private fun showCustomDerivationInput() {
val config = when (params) {
is NetworkSelector -> return
is DerivationPathSelector -> CustomTokenSelectorDialogConfig.CustomDerivationInput(params.mode)
is DerivationPathSelector -> CustomTokenSelectorDialogConfig.CustomDerivationInput(
params.mode,
params.selectedNetwork,
)
}
dialogNavigation.activate(config)
@ -183,14 +187,14 @@ internal class CustomTokenSelectorModel @Inject constructor(
is DerivationPathSelector -> if (accountsFeatureToggles.isFeatureEnabled) {
params.checkAccountDerivation(value)
} else {
params.onDerivationPathSelected(value)
params.onDerivationPathSelected(value, null)
}
}
}
private fun DerivationPathSelector.checkAccountDerivation(derivationPath: SelectedDerivationPath) =
modelScope.launch {
val accountName = derivationPath.id
val account = derivationPath.id
?.let { Blockchain.fromId(it.rawId.value) }?.let(::AccountNodeRecognizer)
?.let { recognizer -> derivationPath.value.value?.let { recognizer.recognize(it) } }
?.let { accountNode ->
@ -199,24 +203,27 @@ internal class CustomTokenSelectorModel @Inject constructor(
val accounts = singleAccountStatusListSupplier(mode.userWalletId)
.first().accountStatuses
val account = accounts.find {
val accountStatus = accounts.find {
when (it) {
is AccountStatus.CryptoPortfolio -> it.sameNodeAndNotMain()
}
}
val accountName = when (account) {
is AccountStatus.CryptoPortfolio -> account.account.accountName.toUM()
null -> null
}
accountName
accountStatus?.account
}
val accountName = when (account) {
is Account.CryptoPortfolio -> account.accountName
null -> null
}
if (accountName == null) {
onDerivationPathSelected(derivationPath)
onDerivationPathSelected(derivationPath, null)
} else {
showAccountNameExist(
accountName = accountName.value,
onClick = { onDerivationPathSelected(derivationPath) },
accountName = accountName.toUM().value,
onClick = { onDerivationPathSelected(derivationPath, account) },
)
}
}

View file

@ -288,7 +288,7 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider :
name = "",
isDefault = false,
),
onDerivationPathSelected = {},
onDerivationPathSelected = { _, _ -> },
),
),
PreviewCustomTokenSelectorComponent(