From 099a16f2fd8620763afd5a44f022164225b4cbe4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Aug 2024 17:31:08 +0400 Subject: [PATCH 1/2] Updated on 2026-08-14 --- features/manage-tokens/impl/build.gradle.kts | 1 + .../component/CustomTokenFormComponent.kt | 6 +- .../impl/DefaultAddCustomTokenComponent.kt | 179 ++++++++++++++++++ .../impl/DefaultCustomTokenFormComponent.kt | 161 ++++++++++++++++ .../DefaultCustomTokenSelectorComponent.kt | 43 +++++ .../managetokens/di/ComponentModule.kt | 24 +++ .../customtoken/AddCustomTokenConfig.kt | 1 + .../customtoken/CustomTokenFormValues.kt | 31 +++ 8 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenFormValues.kt diff --git a/features/manage-tokens/impl/build.gradle.kts b/features/manage-tokens/impl/build.gradle.kts index 681f347d02..a8d50aa900 100644 --- a/features/manage-tokens/impl/build.gradle.kts +++ b/features/manage-tokens/impl/build.gradle.kts @@ -45,5 +45,6 @@ dependencies { /* Other */ implementation(deps.kotlin.immutable.collections) + implementation(deps.decompose.ext.compose) implementation(deps.timber) } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenFormComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenFormComponent.kt index ee90f06a95..3f6d401d30 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenFormComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenFormComponent.kt @@ -3,6 +3,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.wallets.models.UserWalletId +import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormValues import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork @@ -12,8 +13,9 @@ internal interface CustomTokenFormComponent : ComposableContentComponent { val userWalletId: UserWalletId, val network: SelectedNetwork, val derivationPath: SelectedDerivationPath, - val onSelectNetworkClick: () -> Unit, - val onSelectDerivationPathClick: () -> Unit, + val formValues: CustomTokenFormValues, + val onSelectNetworkClick: (CustomTokenFormValues) -> Unit, + val onSelectDerivationPathClick: (CustomTokenFormValues) -> Unit, ) interface Factory : ComponentFactory diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt new file mode 100644 index 0000000000..dd0faa0556 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt @@ -0,0 +1,179 @@ +package com.tangem.features.managetokens.component.impl + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children +import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.router.stack.* +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.core.ui.extensions.resourceReference +import com.tangem.features.managetokens.component.AddCustomTokenComponent +import com.tangem.features.managetokens.component.CustomTokenFormComponent +import com.tangem.features.managetokens.component.CustomTokenSelectorComponent +import com.tangem.features.managetokens.entity.customtoken.AddCustomTokenConfig +import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormValues +import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath +import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork +import com.tangem.features.managetokens.impl.R +import com.tangem.features.managetokens.ui.AddCustomTokenBottomSheet +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultAddCustomTokenComponent @AssistedInject constructor( + @Assisted context: AppComponentContext, + @Assisted private val params: AddCustomTokenComponent.Params, + private val selectorComponentFactory: CustomTokenSelectorComponent.Factory, + private val formComponentFactory: CustomTokenFormComponent.Factory, +) : AddCustomTokenComponent, AppComponentContext by context { + + private val navigation = StackNavigation() + private val contentStack = childStack( + key = "add_custom_token_content_stack", + source = navigation, + initialConfiguration = AddCustomTokenConfig( + userWalletId = params.userWalletId, + step = AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR, + popBack = ::dismiss, + ), + handleBackButton = true, + serializer = AddCustomTokenConfig.serializer(), + childFactory = ::contentChild, + ) + + override fun dismiss() { + params.onDismiss() + } + + @Composable + override fun BottomSheet() { + val config = remember { + TangemBottomSheetConfig( + isShow = true, + onDismissRequest = ::dismiss, + content = contentStack.active.configuration, + ) + } + val childStack by contentStack.subscribeAsState() + + AddCustomTokenBottomSheet( + config = config.copy( + content = childStack.active.configuration, + ), + content = { modifier -> + Children( + stack = childStack, + animation = stackAnimation(), + ) { child -> + child.instance.Content(modifier = modifier) + } + }, + ) + } + + private fun contentChild( + config: AddCustomTokenConfig, + componentContext: ComponentContext, + ): ComposableContentComponent = when (config.step) { + AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR -> { + selectorComponentFactory.create( + context = childByContext(componentContext), + params = CustomTokenSelectorComponent.Params.NetworkSelector( + userWalletId = config.userWalletId, + selectedNetwork = null, + onNetworkSelected = { network -> + showForm(network = network) + }, + ), + ) + } + AddCustomTokenConfig.Step.NETWORK_SELECTOR -> { + selectorComponentFactory.create( + context = childByContext(componentContext), + params = CustomTokenSelectorComponent.Params.NetworkSelector( + userWalletId = config.userWalletId, + selectedNetwork = config.selectedNetwork, + onNetworkSelected = { network -> + showForm(network = network) + }, + ), + ) + } + AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR -> { + selectorComponentFactory.create( + context = childByContext(componentContext), + params = CustomTokenSelectorComponent.Params.DerivationPathSelector( + userWalletId = config.userWalletId, + selectedDerivationPath = config.selectedDerivationPath, + onDerivationPathSelected = { derivationPath -> + showForm(derivationPath = derivationPath) + }, + ), + ) + } + AddCustomTokenConfig.Step.FORM -> { + formComponentFactory.create( + context = childByContext(componentContext), + params = CustomTokenFormComponent.Params( + userWalletId = config.userWalletId, + network = config.selectedNetwork ?: error("Network is not selected"), + derivationPath = config.selectedDerivationPath ?: SelectedDerivationPath( + value = config.selectedNetwork.derivationPath, + name = resourceReference(R.string.custom_token_derivation_path_default), + ), + formValues = config.formValues, + onSelectNetworkClick = ::showNetworkSelector, + onSelectDerivationPathClick = ::showDerivationPathSelector, + ), + ) + } + } + + private fun showDerivationPathSelector(formValues: CustomTokenFormValues) { + val currentConfig = contentStack.value.active.configuration + + val config = currentConfig.copy( + step = AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR, + formValues = formValues, + popBack = navigation::pop, + ) + navigation.push(config) + } + + private fun showNetworkSelector(formValues: CustomTokenFormValues) { + val currentConfig = contentStack.value.active.configuration + + val config = currentConfig.copy( + step = AddCustomTokenConfig.Step.NETWORK_SELECTOR, + formValues = formValues, + popBack = navigation::pop, + ) + navigation.push(config) + } + + private fun showForm(network: SelectedNetwork? = null, derivationPath: SelectedDerivationPath? = null) { + val currentConfig = contentStack.value.active.configuration + + val config = currentConfig.copy( + step = AddCustomTokenConfig.Step.FORM, + selectedNetwork = network ?: currentConfig.selectedNetwork, + selectedDerivationPath = derivationPath ?: currentConfig.selectedDerivationPath, + popBack = ::dismiss, + ) + navigation.replaceAll(config) + } + + @AssistedFactory + interface Factory : AddCustomTokenComponent.Factory { + override fun create( + context: AppComponentContext, + params: AddCustomTokenComponent.Params, + ): DefaultAddCustomTokenComponent + } +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt new file mode 100644 index 0000000000..982e4979e1 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt @@ -0,0 +1,161 @@ +package com.tangem.features.managetokens.component.impl + +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.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.features.managetokens.component.CustomTokenFormComponent +import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM +import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormUM +import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormValues +import com.tangem.features.managetokens.entity.customtoken.TextInputFieldUM +import com.tangem.features.managetokens.impl.R +import com.tangem.features.managetokens.ui.CustomTokenFormContent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update + +internal class DefaultCustomTokenFormComponent @AssistedInject constructor( + @Assisted context: AppComponentContext, + @Assisted private val params: CustomTokenFormComponent.Params, +) : CustomTokenFormComponent, AppComponentContext by context { + + private val state: MutableStateFlow = MutableStateFlow( + value = getInitialState(), + ) + + @Composable + override fun Content(modifier: Modifier) { + val state by state.collectAsStateWithLifecycle() + + CustomTokenFormContent( + modifier = modifier, + model = state, + ) + } + + private fun getInitialState(): CustomTokenFormUM { + return CustomTokenFormUM( + networkName = ClickableFieldUM( + label = resourceReference(R.string.custom_token_network_input_title), + value = params.network.name, + onClick = ::selectNetwork, + ), + tokenForm = getInitialTokenForm(), + derivationPath = ClickableFieldUM( + label = resourceReference(R.string.custom_token_derivation_path), + value = params.derivationPath.name, + onClick = ::selectDerivationPath, + ), + saveToken = { + // TODO: Save token: [REDACTED_JIRA] + }, + ) + } + + private fun getInitialTokenForm(): CustomTokenFormUM.TokenFormUM { + val formValues = params.formValues + + val form = CustomTokenFormUM.TokenFormUM( + contractAddress = TextInputFieldUM( + label = resourceReference(R.string.custom_token_contract_address_input_title), + placeholder = stringReference(value = "0x000000000000000000000000000..."), + onValueChange = ::updateContractAddress, + ), + name = TextInputFieldUM( + label = resourceReference(R.string.custom_token_name_input_title), + placeholder = resourceReference(R.string.custom_token_name_input_placeholder), + onValueChange = ::updateTokenName, + ), + symbol = TextInputFieldUM( + label = resourceReference(R.string.custom_token_token_symbol_input_title), + placeholder = resourceReference(R.string.custom_token_token_symbol_input_placeholder), + onValueChange = ::updateTokenSymbol, + ), + decimals = TextInputFieldUM( + label = resourceReference(R.string.custom_token_decimals_input_title), + placeholder = stringReference(value = "0"), + onValueChange = ::updateDecimals, + ), + ) + + return formValues.fillValues(form) + } + + private fun updateContractAddress(value: String) { + // TODO: Add field validation: [REDACTED_JIRA] + state.update { state -> + val tokenForm = state.tokenForm ?: return@update state + + state.copy( + tokenForm = tokenForm.copy( + contractAddress = tokenForm.contractAddress.copy(value = value), + ), + ) + } + } + + private fun updateTokenName(value: String) { + // TODO: Add field validation: [REDACTED_JIRA] + state.update { state -> + val tokenForm = state.tokenForm ?: return@update state + + state.copy( + tokenForm = tokenForm.copy( + name = tokenForm.name.copy(value = value), + ), + ) + } + } + + private fun updateTokenSymbol(value: String) { + // TODO: Add field validation: [REDACTED_JIRA] + state.update { state -> + val tokenForm = state.tokenForm ?: return@update state + + state.copy( + tokenForm = tokenForm.copy( + symbol = tokenForm.symbol.copy(value = value), + ), + ) + } + } + + private fun updateDecimals(value: String) { + // TODO: Add field validation: [REDACTED_JIRA] + state.update { state -> + val tokenForm = state.tokenForm ?: return@update state + + state.copy( + tokenForm = tokenForm.copy( + decimals = tokenForm.decimals.copy(value = value), + ), + ) + } + } + + private fun selectNetwork() { + params.onSelectNetworkClick(CustomTokenFormValues(state.value.tokenForm)) + } + + private fun selectDerivationPath() { + params.onSelectDerivationPathClick(CustomTokenFormValues(state.value.tokenForm)) + } + + @AssistedFactory + interface Factory : CustomTokenFormComponent.Factory { + override fun create( + context: AppComponentContext, + params: CustomTokenFormComponent.Params, + ): DefaultCustomTokenFormComponent + } + + private companion object { + const val FORM_VALUES_KEY = "form_values" + } +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt new file mode 100644 index 0000000000..c748d7363f --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenSelectorComponent.kt @@ -0,0 +1,43 @@ +package com.tangem.features.managetokens.component.impl + +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.features.managetokens.component.CustomTokenSelectorComponent +import com.tangem.features.managetokens.component.preview.PreviewCustomTokenSelectorComponent +import com.tangem.features.managetokens.entity.customtoken.CustomTokenSelectorUM +import com.tangem.features.managetokens.ui.CustomTokenSelectorContent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.MutableStateFlow + +internal class DefaultCustomTokenSelectorComponent @AssistedInject constructor( + @Assisted context: AppComponentContext, + @Assisted params: CustomTokenSelectorComponent.Params, +) : CustomTokenSelectorComponent, AppComponentContext by context { + + private val state: MutableStateFlow = MutableStateFlow( + value = PreviewCustomTokenSelectorComponent(params = params).previewState, + ) + + @Composable + override fun Content(modifier: Modifier) { + val state by state.collectAsStateWithLifecycle() + + CustomTokenSelectorContent( + modifier = modifier, + model = state, + ) + } + + @AssistedFactory + interface Factory : CustomTokenSelectorComponent.Factory { + override fun create( + context: AppComponentContext, + params: CustomTokenSelectorComponent.Params, + ): DefaultCustomTokenSelectorComponent + } +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ComponentModule.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ComponentModule.kt index f84b3c4c8e..9de5afa38c 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ComponentModule.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/di/ComponentModule.kt @@ -1,6 +1,12 @@ package com.tangem.features.managetokens.di +import com.tangem.features.managetokens.component.AddCustomTokenComponent +import com.tangem.features.managetokens.component.CustomTokenFormComponent +import com.tangem.features.managetokens.component.CustomTokenSelectorComponent import com.tangem.features.managetokens.component.ManageTokensComponent +import com.tangem.features.managetokens.component.impl.DefaultAddCustomTokenComponent +import com.tangem.features.managetokens.component.impl.DefaultCustomTokenFormComponent +import com.tangem.features.managetokens.component.impl.DefaultCustomTokenSelectorComponent import com.tangem.features.managetokens.component.impl.DefaultManageTokensComponent import dagger.Binds import dagger.Module @@ -15,4 +21,22 @@ internal interface ComponentModule { @Binds @Singleton fun bindManageTokensComponentFactory(factory: DefaultManageTokensComponent.Factory): ManageTokensComponent.Factory + + @Binds + @Singleton + fun bindAddCustomTokenComponentFactory( + factory: DefaultAddCustomTokenComponent.Factory, + ): AddCustomTokenComponent.Factory + + @Binds + @Singleton + fun bindCustomTokenSelectorComponentFactory( + factory: DefaultCustomTokenSelectorComponent.Factory, + ): CustomTokenSelectorComponent.Factory + + @Binds + @Singleton + fun bindCustomTokenFormComponentFactory( + factory: DefaultCustomTokenFormComponent.Factory, + ): CustomTokenFormComponent.Factory } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt index 49367133b5..417cd15585 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt @@ -13,6 +13,7 @@ internal data class AddCustomTokenConfig( val userWalletId: UserWalletId, val selectedNetwork: SelectedNetwork? = null, val selectedDerivationPath: SelectedDerivationPath? = null, + val formValues: CustomTokenFormValues = CustomTokenFormValues(), ) : TangemBottomSheetConfigContent { enum class Step { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenFormValues.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenFormValues.kt new file mode 100644 index 0000000000..1551b4bc30 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenFormValues.kt @@ -0,0 +1,31 @@ +package com.tangem.features.managetokens.entity.customtoken + +import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormUM.TokenFormUM +import kotlinx.serialization.Serializable + +@JvmInline +@Serializable +internal value class CustomTokenFormValues private constructor(private val values: List) { + + constructor() : this(values = emptyList()) + + constructor(form: TokenFormUM?) : this( + values = if (form == null) { + emptyList() + } else { + listOf( + form.contractAddress.value, + form.name.value, + form.symbol.value, + form.decimals.value, + ) + }, + ) + + fun fillValues(to: TokenFormUM): TokenFormUM = to.copy( + contractAddress = to.contractAddress.copy(value = values.getOrElse(index = 0) { "" }), + name = to.name.copy(value = values.getOrElse(index = 1) { "" }), + symbol = to.symbol.copy(value = values.getOrElse(index = 2) { "" }), + decimals = to.decimals.copy(value = values.getOrElse(index = 3) { "" }), + ) +} \ No newline at end of file From 5dbe06c8c2ee3bec14c51864e5d41e3d3c54b054 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Aug 2024 17:31:21 +0400 Subject: [PATCH 2/2] Updated on 2026-08-14 --- .../impl/DefaultManageTokensComponent.kt | 34 +++++++++++++++++++ .../managetokens/model/ManageTokensModel.kt | 12 +++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt index 7fc4940bea..9d90bf8789 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultManageTokensComponent.kt @@ -5,9 +5,17 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState +import com.arkivanov.decompose.router.slot.childSlot +import com.arkivanov.decompose.router.slot.dismiss 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.features.managetokens.component.AddCustomTokenComponent import com.tangem.features.managetokens.component.ManageTokensComponent +import com.tangem.features.managetokens.entity.managetokens.BottomSheetConfig import com.tangem.features.managetokens.model.ManageTokensModel import com.tangem.features.managetokens.ui.ManageTokensScreen import dagger.assisted.Assisted @@ -17,13 +25,22 @@ import dagger.assisted.AssistedInject internal class DefaultManageTokensComponent @AssistedInject constructor( @Assisted context: AppComponentContext, @Assisted params: ManageTokensComponent.Params, + private val addCustomTokenComponentFactory: AddCustomTokenComponent.Factory, ) : ManageTokensComponent, AppComponentContext by context { private val model: ManageTokensModel = getOrCreateModel(params) + private val bottomSheetSlot = childSlot( + source = model.bottomSheetNavigation, + serializer = BottomSheetConfig.serializer(), + handleBackButton = false, + childFactory = ::bottomSheetChild, + ) + @Composable override fun Content(modifier: Modifier) { val state by model.state.collectAsStateWithLifecycle() + val bottomSheet by bottomSheetSlot.subscribeAsState() BackHandler(onBack = state.popBack) @@ -31,6 +48,23 @@ internal class DefaultManageTokensComponent @AssistedInject constructor( modifier = modifier, state = state, ) + + bottomSheet.child?.instance?.BottomSheet() + } + + private fun bottomSheetChild( + config: BottomSheetConfig, + componentContext: ComponentContext, + ): ComposableBottomSheetComponent = when (config) { + is BottomSheetConfig.AddCustomToken -> { + addCustomTokenComponentFactory.create( + context = childByContext(componentContext), + params = AddCustomTokenComponent.Params( + userWalletId = config.userWalletId, + onDismiss = model.bottomSheetNavigation::dismiss, + ), + ) + } } @AssistedFactory diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt index 557b3fc508..941fdad919 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/ManageTokensModel.kt @@ -1,5 +1,7 @@ package com.tangem.features.managetokens.model +import com.arkivanov.decompose.router.slot.SlotNavigation +import com.arkivanov.decompose.router.slot.activate import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -13,6 +15,7 @@ import com.tangem.core.ui.message.SnackbarMessage import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.managetokens.component.ManageTokensComponent import com.tangem.features.managetokens.entity.item.CurrencyItemUM +import com.tangem.features.managetokens.entity.managetokens.BottomSheetConfig import com.tangem.features.managetokens.entity.managetokens.ManageTokensTopBarUM import com.tangem.features.managetokens.entity.managetokens.ManageTokensUM import com.tangem.features.managetokens.impl.R @@ -38,6 +41,7 @@ internal class ManageTokensModel @Inject constructor( private val params: ManageTokensComponent.Params = paramsContainer.require() val state: MutableStateFlow = MutableStateFlow(getInitialState(params.userWalletId)) + val bottomSheetNavigation: SlotNavigation = SlotNavigation() init { manageTokensListManager.uiItems @@ -99,7 +103,7 @@ internal class ManageTokensModel @Inject constructor( onBackButtonClick = router::pop, endButton = TopAppBarButtonUM( iconRes = R.drawable.ic_plus_24, - onIconClicked = ::onAddCustomToken, + onIconClicked = ::navigateToAddCustomToken, ), ), search = SearchBarUM( @@ -189,8 +193,10 @@ internal class ManageTokensModel @Inject constructor( return persistentListOf() } - private fun onAddCustomToken() { - // TODO: [REDACTED_JIRA] + private fun navigateToAddCustomToken() { + params.userWalletId?.let { + bottomSheetNavigation.activate(BottomSheetConfig.AddCustomToken(it)) + } } private fun saveChanges() {