diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/AddCustomTokenComponent.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/AddCustomTokenComponent.kt index aad2b8562d..c45a8667f6 100644 --- a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/AddCustomTokenComponent.kt +++ b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/AddCustomTokenComponent.kt @@ -2,12 +2,11 @@ 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.wallet.UserWalletId interface AddCustomTokenComponent : ComposableBottomSheetComponent { data class Params( - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, val source: ManageTokensSource, val onDismiss: () -> Unit, val onCurrencyAdded: () -> Unit, diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt index a02c7125ff..e680fabf26 100644 --- a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt +++ b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt @@ -7,9 +7,16 @@ import com.tangem.domain.models.wallet.UserWalletId interface ManageTokensComponent : ComposableContentComponent { data class Params( - val userWalletId: UserWalletId?, + val mode: ManageTokensMode, val source: ManageTokensSource, - ) + ) { + constructor(userWalletId: UserWalletId?, source: ManageTokensSource) : this( + source = source, + mode = userWalletId + ?.let { ManageTokensMode.Wallet(userWalletId) } + ?: ManageTokensMode.None, + ) + } interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensSource.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensSource.kt index c1d317c3d8..3c34dd0f34 100644 --- a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensSource.kt +++ b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensSource.kt @@ -1,8 +1,22 @@ package com.tangem.features.managetokens.component +import com.tangem.domain.models.account.AccountId +import com.tangem.domain.models.wallet.UserWalletId + enum class ManageTokensSource(val analyticsName: String) { STORIES(analyticsName = "Stories"), ONBOARDING(analyticsName = "Onboarding"), SETTINGS(analyticsName = "Settings"), SEND_VIA_SWAP(analyticsName = "SendViaSwap"), +} + +sealed interface ManageTokensMode { + data class Wallet(val userWalletId: UserWalletId) : ManageTokensMode + data class Account(val accountId: AccountId) : ManageTokensMode + data object None : ManageTokensMode +} + +sealed interface AddCustomTokenMode { + data class Wallet(val userWalletId: UserWalletId) : AddCustomTokenMode + data class Account(val accountId: AccountId) : AddCustomTokenMode } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/model/ChooseManagedTokensModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/model/ChooseManagedTokensModel.kt index 3c239162b1..a9c9f03c8f 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/model/ChooseManagedTokensModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/model/ChooseManagedTokensModel.kt @@ -22,6 +22,7 @@ import com.tangem.features.managetokens.choosetoken.entity.ChooseManageTokensBot import com.tangem.features.managetokens.choosetoken.entity.ChooseManagedTokenUM import com.tangem.features.managetokens.component.ChooseManagedTokensComponent import com.tangem.features.managetokens.component.ChooseManagedTokensComponent.Source +import com.tangem.features.managetokens.component.ManageTokensMode import com.tangem.features.managetokens.component.ManageTokensSource import com.tangem.features.managetokens.component.analytics.CommonManageTokensAnalyticEvents import com.tangem.features.managetokens.entity.item.CurrencyItemUM @@ -29,6 +30,7 @@ import com.tangem.features.managetokens.entity.managetokens.ManageTokensTopBarUM import com.tangem.features.managetokens.entity.managetokens.ManageTokensUM import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.utils.list.ManageTokensListManager +import com.tangem.features.managetokens.utils.list.ManageTokensUseCasesFacade import com.tangem.features.managetokens.utils.list.getLoadingItems import com.tangem.pagination.BatchFetchResult import com.tangem.pagination.PaginationStatus @@ -51,12 +53,19 @@ internal class ChooseManagedTokensModel @Inject constructor( private val setShouldShowNotificationUseCase: SetShouldShowNotificationUseCase, private val analyticsEventHandler: AnalyticsEventHandler, paramsContainer: ParamsContainer, + manageTokensUseCasesFacadeFactory: ManageTokensUseCasesFacade.Factory, manageTokensListManagerFactory: ManageTokensListManager.Factory, ) : Model() { private val params: ChooseManagedTokensComponent.Params = paramsContainer.require() + private val useCasesFacade: ManageTokensUseCasesFacade = manageTokensUseCasesFacadeFactory + .create(mode = ManageTokensMode.None) private val manageTokensListManager = manageTokensListManagerFactory.create( + scope = modelScope, + source = ManageTokensSource.SEND_VIA_SWAP, + mode = ManageTokensMode.None, + useCasesFacade = useCasesFacade, onCurrencySelect = { token -> bottomSheetNavigation.activate( ChooseManageTokensBottomSheetConfig.SwapTokensBottomSheetConfig( @@ -86,7 +95,7 @@ internal class ChooseManagedTokensModel @Inject constructor( observeSearchQueryChanges() modelScope.launch { - manageTokensListManager.launchPagination(source = ManageTokensSource.SEND_VIA_SWAP, userWalletId = null) + manageTokensListManager.launchPagination() } } @@ -159,7 +168,7 @@ internal class ChooseManagedTokensModel @Inject constructor( } } .sample(periodMillis = 1_000) - .onEach { query -> manageTokensListManager.search(userWalletId = null, query = query) } + .onEach { query -> manageTokensListManager.search(query = query) } .launchIn(modelScope) } @@ -295,7 +304,7 @@ internal class ChooseManagedTokensModel @Inject constructor( if (state.readContent.isInitialBatchLoading || state.readContent.isNextBatchLoading) return false modelScope.launch { - manageTokensListManager.loadMore(userWalletId = null, query = state.readContent.search.query) + manageTokensListManager.loadMore(query = state.readContent.search.query) } return true diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenDerivationInputComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenDerivationInputComponent.kt index 7ec0cff9c9..56f2b08ca9 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenDerivationInputComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenDerivationInputComponent.kt @@ -2,13 +2,12 @@ package com.tangem.features.managetokens.component import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableDialogComponent -import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath internal interface CustomTokenDerivationInputComponent : ComposableDialogComponent { data class Params( - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, val onConfirm: (SelectedDerivationPath) -> Unit, val onDismiss: () -> Unit, ) 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 04a9e59d48..2baf3f982f 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 @@ -2,7 +2,6 @@ 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.wallet.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 @@ -10,7 +9,7 @@ import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork internal interface CustomTokenFormComponent : ComposableContentComponent { data class Params( - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, val network: SelectedNetwork, val derivationPath: SelectedDerivationPath?, val formValues: CustomTokenFormValues, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenSelectorComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenSelectorComponent.kt index 6e36ef8eb7..a4ec53c9d9 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenSelectorComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/CustomTokenSelectorComponent.kt @@ -2,7 +2,6 @@ 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.wallet.UserWalletId import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork @@ -11,13 +10,13 @@ internal interface CustomTokenSelectorComponent : ComposableContentComponent { sealed class Params { data class NetworkSelector( - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, val selectedNetwork: SelectedNetwork?, val onNetworkSelected: (SelectedNetwork) -> Unit, ) : Params() data class DerivationPathSelector( - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, val selectedNetwork: SelectedNetwork, val selectedDerivationPath: SelectedDerivationPath?, val onDerivationPathSelected: (SelectedDerivationPath) -> Unit, 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 index f4ecc9ceed..1951b3cd44 100644 --- 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 @@ -38,7 +38,7 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor( ) : AddCustomTokenComponent, AppComponentContext by context { private val initialConfiguration = AddCustomTokenConfig( - userWalletId = params.userWalletId, + mode = params.mode, step = AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR, ) @@ -105,7 +105,7 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor( selectorComponentFactory.create( context = childByContext(componentContext), params = CustomTokenSelectorComponent.Params.NetworkSelector( - userWalletId = config.userWalletId, + mode = config.mode, selectedNetwork = null, onNetworkSelected = ::changeSelectedNetwork, ), @@ -115,7 +115,7 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor( selectorComponentFactory.create( context = childByContext(componentContext), params = CustomTokenSelectorComponent.Params.NetworkSelector( - userWalletId = config.userWalletId, + mode = config.mode, selectedNetwork = config.selectedNetwork, onNetworkSelected = ::changeSelectedNetwork, ), @@ -125,7 +125,7 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor( selectorComponentFactory.create( context = childByContext(componentContext), params = CustomTokenSelectorComponent.Params.DerivationPathSelector( - userWalletId = config.userWalletId, + mode = config.mode, selectedNetwork = requireNotNull(config.selectedNetwork) { "Network is not selected" }, @@ -138,7 +138,7 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor( formComponentFactory.create( context = childByContext(componentContext), params = CustomTokenFormComponent.Params( - userWalletId = config.userWalletId, + mode = config.mode, network = requireNotNull(config.selectedNetwork) { "Network is not selected" }, 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 index edd8f52aa9..44c781e3cc 100644 --- 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 @@ -41,7 +41,7 @@ internal class DefaultCustomTokenSelectorComponent @AssistedInject constructor( is CustomTokenSelectorDialogConfig.CustomDerivationInput -> customTokenDerivationInputComponentFactory.create( context = childByContext(context), params = CustomTokenDerivationInputComponent.Params( - userWalletId = config.userWalletId, + mode = config.mode, onConfirm = model::selectCustomDerivationPath, onDismiss = model.dialogNavigation::dismiss, ), 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 76ae54a12d..9dc5539ae4 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 @@ -13,6 +13,7 @@ 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.AddCustomTokenMode import com.tangem.features.managetokens.component.ManageTokensComponent import com.tangem.features.managetokens.entity.managetokens.ManageTokensBottomSheetConfig import com.tangem.features.managetokens.model.ManageTokensModel @@ -52,18 +53,20 @@ internal class DefaultManageTokensComponent @AssistedInject constructor( private fun bottomSheetChild( config: ManageTokensBottomSheetConfig, componentContext: ComponentContext, - ): ComposableBottomSheetComponent = when (config) { - is ManageTokensBottomSheetConfig.AddCustomToken -> { - addCustomTokenComponentFactory.create( - context = childByContext(componentContext), - params = AddCustomTokenComponent.Params( - userWalletId = config.userWalletId, - source = params.source, - onDismiss = model.bottomSheetNavigation::dismiss, - onCurrencyAdded = model::reloadList, - ), - ) + ): ComposableBottomSheetComponent { + val mode = when (config) { + is ManageTokensBottomSheetConfig.AddWalletCustomToken -> AddCustomTokenMode.Wallet(config.userWalletId) + is ManageTokensBottomSheetConfig.AddAccountCustomToken -> AddCustomTokenMode.Account(config.accountId) } + return addCustomTokenComponentFactory.create( + context = childByContext(componentContext), + params = AddCustomTokenComponent.Params( + mode = mode, + source = params.source, + onDismiss = model.bottomSheetNavigation::dismiss, + onCurrencyAdded = model::reloadList, + ), + ) } @AssistedFactory diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewAddCustomTokenComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewAddCustomTokenComponent.kt index eb693e20b1..239866349d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewAddCustomTokenComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewAddCustomTokenComponent.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.managetokens.component.AddCustomTokenComponent +import com.tangem.features.managetokens.component.AddCustomTokenMode import com.tangem.features.managetokens.component.CustomTokenSelectorComponent import com.tangem.features.managetokens.entity.customtoken.AddCustomTokenConfig import com.tangem.features.managetokens.ui.AddCustomTokenBottomSheet @@ -14,7 +15,7 @@ import kotlinx.coroutines.flow.MutableStateFlow internal class PreviewAddCustomTokenComponent( initialState: AddCustomTokenConfig = AddCustomTokenConfig( - userWalletId = UserWalletId(stringValue = "321"), + mode = AddCustomTokenMode.Wallet(UserWalletId(stringValue = "321")), step = AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR, ), ) : AddCustomTokenComponent { @@ -41,7 +42,7 @@ internal class PreviewAddCustomTokenComponent( AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR -> { PreviewCustomTokenSelectorComponent( params = CustomTokenSelectorComponent.Params.NetworkSelector( - userWalletId = config.userWalletId, + mode = config.mode, selectedNetwork = null, onNetworkSelected = {}, ), @@ -50,7 +51,7 @@ internal class PreviewAddCustomTokenComponent( AddCustomTokenConfig.Step.NETWORK_SELECTOR -> { PreviewCustomTokenSelectorComponent( params = CustomTokenSelectorComponent.Params.NetworkSelector( - userWalletId = config.userWalletId, + mode = config.mode, selectedNetwork = config.selectedNetwork, onNetworkSelected = {}, ), @@ -59,7 +60,7 @@ internal class PreviewAddCustomTokenComponent( AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR -> { PreviewCustomTokenSelectorComponent( params = CustomTokenSelectorComponent.Params.DerivationPathSelector( - userWalletId = config.userWalletId, + mode = config.mode, selectedNetwork = config.selectedNetwork!!, selectedDerivationPath = config.selectedDerivationPath!!, onDerivationPathSelected = {}, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt index eca3ff5cc5..9d4485dee8 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt @@ -5,6 +5,7 @@ import androidx.compose.ui.Modifier import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.models.network.Network import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.component.AddCustomTokenMode import com.tangem.features.managetokens.component.CustomTokenSelectorComponent import com.tangem.features.managetokens.component.CustomTokenSelectorComponent.Params import com.tangem.features.managetokens.entity.customtoken.CustomTokenSelectorUM @@ -18,7 +19,7 @@ import kotlinx.collections.immutable.toImmutableList internal class PreviewCustomTokenSelectorComponent( private val params: Params = Params.NetworkSelector( - userWalletId = UserWalletId(stringValue = "321"), + mode = AddCustomTokenMode.Wallet(UserWalletId(stringValue = "321")), selectedNetwork = null, onNetworkSelected = {}, ), diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt index d7caaf672c..c14f0f1836 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt @@ -13,6 +13,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.models.network.Network import com.tangem.features.managetokens.component.ManageTokensComponent +import com.tangem.features.managetokens.component.ManageTokensMode import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM import com.tangem.features.managetokens.entity.managetokens.ManageTokensTopBarUM @@ -38,8 +39,10 @@ internal class PreviewManageTokensComponent( value = ManageTokensUM.ManageContent( popBack = {}, items = items, - topBar = if (params.userWalletId != null) { - ManageTokensTopBarUM.ManageContent( + topBar = when (params.mode) { + is ManageTokensMode.Account, + is ManageTokensMode.Wallet, + -> ManageTokensTopBarUM.ManageContent( title = resourceReference(id = R.string.main_manage_tokens), onBackButtonClick = {}, endButton = TopAppBarButtonUM.Icon( @@ -47,8 +50,7 @@ internal class PreviewManageTokensComponent( onClicked = {}, ), ) - } else { - ManageTokensTopBarUM.ReadContent( + ManageTokensMode.None -> ManageTokensTopBarUM.ReadContent( title = resourceReference(R.string.common_search_tokens), onBackButtonClick = {}, ) 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 767e87805c..e33d46321d 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 @@ -1,13 +1,13 @@ package com.tangem.features.managetokens.entity.customtoken import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.component.AddCustomTokenMode import kotlinx.serialization.Serializable @Serializable internal data class AddCustomTokenConfig( val step: Step, - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, val selectedNetwork: SelectedNetwork? = null, val selectedDerivationPath: SelectedDerivationPath? = null, val formValues: CustomTokenFormValues = CustomTokenFormValues(), diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenSelectorDialogConfig.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenSelectorDialogConfig.kt index 05a447f9d1..fc34e8cdda 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenSelectorDialogConfig.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/CustomTokenSelectorDialogConfig.kt @@ -1,6 +1,6 @@ package com.tangem.features.managetokens.entity.customtoken -import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.component.AddCustomTokenMode import kotlinx.serialization.Serializable @Serializable @@ -8,6 +8,6 @@ internal sealed class CustomTokenSelectorDialogConfig { @Serializable data class CustomDerivationInput( - val userWalletId: UserWalletId, + val mode: AddCustomTokenMode, ) : CustomTokenSelectorDialogConfig() } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/managetokens/ManageTokensBottomSheetConfig.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/managetokens/ManageTokensBottomSheetConfig.kt index 9e2153b6e5..91a4b7fba3 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/managetokens/ManageTokensBottomSheetConfig.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/managetokens/ManageTokensBottomSheetConfig.kt @@ -1,5 +1,6 @@ package com.tangem.features.managetokens.entity.managetokens +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.wallet.UserWalletId import kotlinx.serialization.Serializable @@ -7,7 +8,12 @@ import kotlinx.serialization.Serializable internal sealed class ManageTokensBottomSheetConfig { @Serializable - data class AddCustomToken( + data class AddWalletCustomToken( val userWalletId: UserWalletId, ) : ManageTokensBottomSheetConfig() + + @Serializable + data class AddAccountCustomToken( + val accountId: AccountId, + ) : ManageTokensBottomSheetConfig() } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt index 08d5f86574..6e5d19d000 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenFormModel.kt @@ -12,9 +12,6 @@ import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.network.Network -import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase -import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase -import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent import com.tangem.features.managetokens.component.CustomTokenFormComponent import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM @@ -25,6 +22,7 @@ import com.tangem.features.managetokens.entity.customtoken.TextInputFieldUM import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.utils.CustomCurrencyFormBuilder import com.tangem.features.managetokens.utils.CustomCurrencyValidator +import com.tangem.features.managetokens.utils.list.CustomTokenFormUseCasesFacade import com.tangem.features.managetokens.utils.mapper.mapToDomainModel import com.tangem.features.managetokens.utils.ui.* import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -40,18 +38,17 @@ import javax.inject.Inject @ModelScoped internal class CustomTokenFormModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, - private val customCurrencyValidator: CustomCurrencyValidator, - private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, - private val derivePublicKeysUseCase: DerivePublicKeysUseCase, - private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, private val messageSender: UiMessageSender, private val customTokenFormManager: CustomCurrencyFormBuilder, private val analyticsEventHandler: AnalyticsEventHandler, paramsContainer: ParamsContainer, + customTokenFormUseCasesFacadeFactory: CustomTokenFormUseCasesFacade.Factory, ) : Model() { private val params: CustomTokenFormComponent.Params = paramsContainer.require() private var createdCurrency: CryptoCurrency? = null + private var useCasesFacade: CustomTokenFormUseCasesFacade = customTokenFormUseCasesFacadeFactory.create(params.mode) + private val customCurrencyValidator = CustomCurrencyValidator(useCasesFacade) val state: MutableStateFlow = MutableStateFlow( value = getInitialState(), @@ -117,7 +114,6 @@ internal class CustomTokenFormModel @Inject constructor( .drop(count = 1) // Skip initial state .onEach { formValues -> customCurrencyValidator.validateForm( - userWalletId = params.userWalletId, networkId = params.network.id, derivationPath = getDerivationPath(), formValues = formValues, @@ -156,7 +152,6 @@ internal class CustomTokenFormModel @Inject constructor( private fun validatePrefilledForm() = modelScope.launch { customCurrencyValidator.validateForm( - userWalletId = params.userWalletId, networkId = params.network.id, derivationPath = getDerivationPath(), formValues = state.value.tokenForm.mapToDomainModel(), @@ -169,8 +164,7 @@ internal class CustomTokenFormModel @Inject constructor( isAlreadyAdded: Boolean, isCustom: Boolean, ) = modelScope.launch { - val needToAddDerivation = hasMissedDerivationsUseCase( - userWalletId = params.userWalletId, + val needToAddDerivation = useCasesFacade.hasMissedDerivationsUseCase( networksWithDerivationPath = mapOf(currency.network.backendId to getDerivationPath().value), ) @@ -343,13 +337,13 @@ internal class CustomTokenFormModel @Inject constructor( ) analyticsEventHandler.send(event) - derivePublicKeysUseCase(params.userWalletId, listOf(currency)).getOrElse { + useCasesFacade.derivePublicKeysUseCase(listOf(currency)).getOrElse { Timber.e(it, "Failed to derive public keys") showErrorDialog() return@resource } - addCryptoCurrenciesUseCase(params.userWalletId, currency).getOrElse { + useCasesFacade.addCryptoCurrenciesUseCase(currency).getOrElse { Timber.e(it, "Failed to add currency") showErrorDialog() return@resource diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt index a919429bd1..3bb119e580 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt @@ -11,7 +11,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.SnackbarMessage import com.tangem.domain.managetokens.GetSupportedNetworksUseCase import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.component.AddCustomTokenMode import com.tangem.features.managetokens.component.CustomTokenSelectorComponent import com.tangem.features.managetokens.component.CustomTokenSelectorComponent.Params.DerivationPathSelector import com.tangem.features.managetokens.component.CustomTokenSelectorComponent.Params.NetworkSelector @@ -83,7 +83,7 @@ internal class CustomTokenSelectorModel @Inject constructor( } private suspend fun loadNetworks(selector: NetworkSelector): List { - return getSupportedNetworks(selector.userWalletId).map { network -> + return getSupportedNetworks(selector.mode).map { network -> network.toCurrencyNetworkModel( isSelected = network.id == selector.selectedNetwork?.id, onSelectedStateChange = { @@ -122,7 +122,7 @@ internal class CustomTokenSelectorModel @Inject constructor( derivationPaths.add(defaultPath) } - getSupportedNetworks(selector.userWalletId) + getSupportedNetworks(selector.mode) .mapNotNullTo(derivationPaths) { network -> if (network.id == selector.selectedNetwork.id) { return@mapNotNullTo null // Skip default path @@ -146,8 +146,9 @@ internal class CustomTokenSelectorModel @Inject constructor( return derivationPaths } - private suspend fun getSupportedNetworks(userWalletId: UserWalletId): List { - return getSupportedNetworksUseCase(userWalletId).getOrElse { e -> + private suspend fun getSupportedNetworks(mode: AddCustomTokenMode): List = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> getSupportedNetworksUseCase(mode.userWalletId).getOrElse { e -> val message = SnackbarMessage(message = resourceReference(R.string.common_unknown_error)) messageSender.send(message) @@ -158,7 +159,7 @@ internal class CustomTokenSelectorModel @Inject constructor( private fun showCustomDerivationInput() { val config = when (params) { is NetworkSelector -> return - is DerivationPathSelector -> CustomTokenSelectorDialogConfig.CustomDerivationInput(params.userWalletId) + is DerivationPathSelector -> CustomTokenSelectorDialogConfig.CustomDerivationInput(params.mode) } dialogNavigation.activate(config) 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 91e1814599..afc1d11bc5 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 @@ -17,12 +17,10 @@ import com.tangem.core.ui.event.triggeredEvent import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.message.SnackbarMessage -import com.tangem.domain.managetokens.SaveManagedTokensUseCase -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent import com.tangem.features.managetokens.component.ManageTokensComponent +import com.tangem.features.managetokens.component.ManageTokensMode import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.features.managetokens.entity.managetokens.ManageTokensBottomSheetConfig import com.tangem.features.managetokens.entity.managetokens.ManageTokensTopBarUM @@ -30,6 +28,7 @@ import com.tangem.features.managetokens.entity.managetokens.ManageTokensUM import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.utils.list.ChangedCurrencies import com.tangem.features.managetokens.utils.list.ManageTokensListManager +import com.tangem.features.managetokens.utils.list.ManageTokensUseCasesFacade import com.tangem.pagination.BatchFetchResult import com.tangem.pagination.PaginationStatus import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -47,18 +46,24 @@ internal class ManageTokensModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, private val messageSender: UiMessageSender, - private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, - private val saveManagedTokensUseCase: SaveManagedTokensUseCase, private val analyticsEventHandler: AnalyticsEventHandler, manageTokensListManagerFactory: ManageTokensListManager.Factory, + manageTokensUseCasesFacadeFactory: ManageTokensUseCasesFacade.Factory, paramsContainer: ParamsContainer, ) : Model() { private val params: ManageTokensComponent.Params = paramsContainer.require() + private val useCasesFacade: ManageTokensUseCasesFacade = manageTokensUseCasesFacadeFactory + .create(mode = params.mode) - private val manageTokensListManager = manageTokensListManagerFactory.create() + private val manageTokensListManager = manageTokensListManagerFactory.create( + scope = modelScope, + source = params.source, + mode = params.mode, + useCasesFacade = useCasesFacade, + ) - val state: MutableStateFlow = MutableStateFlow(getInitialState(params.userWalletId)) + val state: MutableStateFlow = MutableStateFlow(getInitialState()) val bottomSheetNavigation: SlotNavigation = SlotNavigation() init { @@ -79,23 +84,24 @@ internal class ManageTokensModel @Inject constructor( observeSearchQueryChanges() modelScope.launch { - manageTokensListManager.launchPagination(source = params.source, userWalletId = params.userWalletId) + manageTokensListManager.launchPagination() } } fun reloadList() { modelScope.launch { - manageTokensListManager.reload(params.userWalletId) + manageTokensListManager.reload() } } - private fun getInitialState(userWalletId: UserWalletId?): ManageTokensUM { + private fun getInitialState(): ManageTokensUM { analyticsEventHandler.send(ManageTokensAnalyticEvent.ScreenOpened(params.source)) - return if (userWalletId == null) { - createReadContentModel() - } else { - createManageContentModel() + return when (params.mode) { + is ManageTokensMode.Wallet, + is ManageTokensMode.Account, + -> createManageContentModel() + ManageTokensMode.None -> createReadContentModel() } } @@ -164,7 +170,7 @@ internal class ManageTokensModel @Inject constructor( } } .sample(periodMillis = 1_000) - .onEach { query -> manageTokensListManager.search(userWalletId = params.userWalletId, query = query) } + .onEach { query -> manageTokensListManager.search(query = query) } .launchIn(modelScope) } @@ -261,19 +267,16 @@ internal class ManageTokensModel @Inject constructor( private fun updateChangedItems(currenciesToAdd: ChangedCurrencies, currenciesToRemove: ChangedCurrencies) { modelScope.launch { - val hasMissedDerivations = params.userWalletId?.let { walletId -> - val networks = currenciesToAdd.values - .flatten() - .toSet() - .associate { it.backendId to null } - - hasMissedDerivationsUseCase(walletId, networks) - } + val networks = currenciesToAdd.values + .flatten() + .toSet() + .associate { it.backendId to null } + val hasMissedDerivations = useCasesFacade.hasMissedDerivationsUseCase(networks) state.update { state -> state.copySealed( hasChanges = currenciesToAdd.isNotEmpty() || currenciesToRemove.isNotEmpty(), - needToAddDerivations = hasMissedDerivations ?: false, + needToAddDerivations = hasMissedDerivations, ) } } @@ -284,7 +287,7 @@ internal class ManageTokensModel @Inject constructor( if (state.isInitialBatchLoading || state.isNextBatchLoading) return false modelScope.launch { - manageTokensListManager.loadMore(userWalletId = params.userWalletId, query = state.search.query) + manageTokensListManager.loadMore(query = state.search.query) } return true @@ -292,9 +295,14 @@ internal class ManageTokensModel @Inject constructor( private fun navigateToAddCustomToken() { analyticsEventHandler.send(CustomTokenAnalyticsEvent.ButtonCustomToken(params.source)) - - params.userWalletId?.let { - bottomSheetNavigation.activate(ManageTokensBottomSheetConfig.AddCustomToken(it)) + when (val portfolio = params.mode) { + is ManageTokensMode.Wallet -> + bottomSheetNavigation + .activate(ManageTokensBottomSheetConfig.AddWalletCustomToken(portfolio.userWalletId)) + is ManageTokensMode.Account -> + bottomSheetNavigation + .activate(ManageTokensBottomSheetConfig.AddAccountCustomToken(portfolio.accountId)) + ManageTokensMode.None -> Unit } } @@ -308,8 +316,7 @@ internal class ManageTokensModel @Inject constructor( ) analyticsEventHandler.send(event) - saveManagedTokensUseCase( - userWalletId = requireNotNull(params.userWalletId), + useCasesFacade.saveManagedTokensUseCase( currenciesToAdd = manageTokensListManager.currenciesToAdd.value, currenciesToRemove = manageTokensListManager.currenciesToRemove.value, ).getOrElse { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt index 30f64dad46..101e04e78c 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/OnboardingManageTokensModel.kt @@ -13,11 +13,10 @@ import com.tangem.core.ui.event.triggeredEvent import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.message.SnackbarMessage -import com.tangem.domain.managetokens.SaveManagedTokensUseCase import com.tangem.domain.redux.OnboardingManageTokensAction import com.tangem.domain.redux.ReduxStateHolder -import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent +import com.tangem.features.managetokens.component.ManageTokensMode import com.tangem.features.managetokens.component.ManageTokensSource import com.tangem.features.managetokens.component.OnboardingManageTokensComponent import com.tangem.features.managetokens.entity.item.CurrencyItemUM @@ -25,6 +24,7 @@ import com.tangem.features.managetokens.entity.managetokens.OnboardingManageToke import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.utils.list.ChangedCurrencies import com.tangem.features.managetokens.utils.list.ManageTokensListManager +import com.tangem.features.managetokens.utils.list.ManageTokensUseCasesFacade import com.tangem.pagination.BatchFetchResult import com.tangem.pagination.PaginationStatus import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -42,15 +42,22 @@ internal class OnboardingManageTokensModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val messageSender: UiMessageSender, private val reduxStateHolder: ReduxStateHolder, - private val saveManagedTokensUseCase: SaveManagedTokensUseCase, - private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, private val analyticsEventHandler: AnalyticsEventHandler, manageTokensListManagerFactory: ManageTokensListManager.Factory, + manageTokensUseCasesFacadeFactory: ManageTokensUseCasesFacade.Factory, paramsContainer: ParamsContainer, ) : Model() { private val params: OnboardingManageTokensComponent.Params = paramsContainer.require() - private val manageTokensListManager = manageTokensListManagerFactory.create() + private val portfolio = ManageTokensMode.Wallet(params.userWalletId) + private val useCasesFacade: ManageTokensUseCasesFacade = manageTokensUseCasesFacadeFactory + .create(mode = portfolio) + private val manageTokensListManager = manageTokensListManagerFactory.create( + scope = modelScope, + source = ManageTokensSource.ONBOARDING, + useCasesFacade = useCasesFacade, + mode = portfolio, + ) val state: MutableStateFlow = MutableStateFlow(getInitialState()) val returnToParentComponentFlow = MutableSharedFlow() @@ -73,10 +80,7 @@ internal class OnboardingManageTokensModel @Inject constructor( observeSearchQueryChanges() modelScope.launch { - manageTokensListManager.launchPagination( - source = ManageTokensSource.ONBOARDING, - userWalletId = params.userWalletId, - ) + manageTokensListManager.launchPagination() } } @@ -119,7 +123,7 @@ internal class OnboardingManageTokensModel @Inject constructor( } } .sample(periodMillis = 1_000) - .onEach { query -> manageTokensListManager.search(userWalletId = params.userWalletId, query = query) } + .onEach { query -> manageTokensListManager.search(query = query) } .launchIn(modelScope) } @@ -208,13 +212,11 @@ internal class OnboardingManageTokensModel @Inject constructor( ) } } else { - val hasMissedDerivations = hasMissedDerivationsUseCase.invoke( - userWalletId = params.userWalletId, - networksWithDerivationPath = currenciesToAdd.values - .flatten() - .toSet() - .associate { it.backendId to null }, - ) + val network = currenciesToAdd.values + .flatten() + .toSet() + .associate { it.backendId to null } + val hasMissedDerivations = useCasesFacade.hasMissedDerivationsUseCase(network = network) state.update { state -> state.copy( actionButtonConfig = OnboardingManageTokensUM.ActionButtonConfig.Continue( @@ -231,7 +233,7 @@ internal class OnboardingManageTokensModel @Inject constructor( if (state.isInitialBatchLoading || state.isNextBatchLoading) return false modelScope.launch { - manageTokensListManager.loadMore(userWalletId = params.userWalletId, query = state.search.query) + manageTokensListManager.loadMore(query = state.search.query) } return true @@ -255,8 +257,7 @@ internal class OnboardingManageTokensModel @Inject constructor( ) analyticsEventHandler.send(event) - saveManagedTokensUseCase( - userWalletId = requireNotNull(params.userWalletId), + useCasesFacade.saveManagedTokensUseCase( currenciesToAdd = manageTokensListManager.currenciesToAdd.value, currenciesToRemove = manageTokensListManager.currenciesToRemove.value, ).getOrElse { @@ -281,8 +282,7 @@ internal class OnboardingManageTokensModel @Inject constructor( ) { analyticsEventHandler.send(ManageTokensAnalyticEvent.ButtonLater) - saveManagedTokensUseCase( - userWalletId = requireNotNull(params.userWalletId), + useCasesFacade.saveManagedTokensUseCase( currenciesToAdd = manageTokensListManager.currenciesToAdd.value, currenciesToRemove = manageTokensListManager.currenciesToRemove.value, ).getOrElse { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt index 8cd0a27d68..4699454540 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt @@ -19,6 +19,7 @@ import com.tangem.core.ui.res.TangemThemePreview import com.tangem.domain.models.network.Network import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.managetokens.component.AddCustomTokenComponent +import com.tangem.features.managetokens.component.AddCustomTokenMode import com.tangem.features.managetokens.component.preview.PreviewAddCustomTokenComponent import com.tangem.features.managetokens.entity.customtoken.AddCustomTokenConfig import com.tangem.features.managetokens.entity.customtoken.AddCustomTokenUM @@ -68,12 +69,13 @@ private fun Preview_AddCustomTokenBottomSheet( } private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider { + private val mode: AddCustomTokenMode get() = AddCustomTokenMode.Wallet(UserWalletId(stringValue = "321")) override val values: Sequence get() = sequenceOf( PreviewAddCustomTokenComponent(), PreviewAddCustomTokenComponent( initialState = AddCustomTokenConfig( - userWalletId = UserWalletId(stringValue = "321"), + mode = mode, step = AddCustomTokenConfig.Step.FORM, selectedNetwork = SelectedNetwork( id = Network.ID(value = "1", derivationPath = Network.DerivationPath.None), @@ -85,7 +87,7 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider< ), PreviewAddCustomTokenComponent( initialState = AddCustomTokenConfig( - userWalletId = UserWalletId(stringValue = "321"), + mode = mode, step = AddCustomTokenConfig.Step.NETWORK_SELECTOR, selectedNetwork = SelectedNetwork( id = Network.ID(value = "0", derivationPath = Network.DerivationPath.None), @@ -97,7 +99,7 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider< ), PreviewAddCustomTokenComponent( initialState = AddCustomTokenConfig( - userWalletId = UserWalletId(stringValue = "321"), + mode = mode, step = AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR, selectedDerivationPath = SelectedDerivationPath( id = Network.ID(value = "0", derivationPath = Network.DerivationPath.None), diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt index 6320fd6743..b7eae1ce2c 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt @@ -32,6 +32,7 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.domain.models.network.Network import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.component.AddCustomTokenMode import com.tangem.features.managetokens.component.CustomTokenSelectorComponent import com.tangem.features.managetokens.component.preview.PreviewCustomTokenSelectorComponent import com.tangem.features.managetokens.entity.customtoken.CustomTokenSelectorUM @@ -268,12 +269,13 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider : PreviewParameterProvider { private val derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/0") + private val mode: AddCustomTokenMode get() = AddCustomTokenMode.Wallet(UserWalletId(stringValue = "321")) override val values: Sequence get() = sequenceOf( PreviewCustomTokenSelectorComponent( params = CustomTokenSelectorComponent.Params.DerivationPathSelector( - userWalletId = UserWalletId(stringValue = "321"), + mode = mode, selectedNetwork = SelectedNetwork( id = Network.ID(value = "0", derivationPath = derivationPath), name = "Ethereum", @@ -291,7 +293,7 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider : ), PreviewCustomTokenSelectorComponent( params = CustomTokenSelectorComponent.Params.NetworkSelector( - userWalletId = UserWalletId(stringValue = "321"), + mode = mode, selectedNetwork = SelectedNetwork( id = Network.ID(value = "0", derivationPath = derivationPath), name = "Ethereum", diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt index bed3b20286..feabc9cb4d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CustomCurrencyValidator.kt @@ -1,31 +1,21 @@ package com.tangem.features.managetokens.utils import arrow.core.getOrElse -import com.tangem.core.decompose.di.ModelScoped -import com.tangem.domain.managetokens.CheckIsCurrencyNotAddedUseCase -import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase -import com.tangem.domain.managetokens.FindTokenUseCase -import com.tangem.domain.managetokens.ValidateTokenFormUseCase import com.tangem.domain.managetokens.model.AddCustomTokenForm import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException import com.tangem.domain.managetokens.model.exceptoin.FindTokenException import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.utils.list.CustomTokenFormUseCasesFacade import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveInAndJoin import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber -import javax.inject.Inject -@ModelScoped -internal class CustomCurrencyValidator @Inject constructor( - private val validateTokenFormUseCase: ValidateTokenFormUseCase, - private val createCryptoCurrencyUseCase: CreateCryptoCurrencyUseCase, - private val findTokenUseCase: FindTokenUseCase, - private val checkIsCurrencyNotAddedUseCase: CheckIsCurrencyNotAddedUseCase, +internal class CustomCurrencyValidator( + private val useCasesFacade: CustomTokenFormUseCasesFacade, ) { private val validateFormJobHolder = JobHolder() @@ -45,14 +35,13 @@ internal class CustomCurrencyValidator @Inject constructor( } suspend fun validateForm( - userWalletId: UserWalletId, networkId: Network.ID, derivationPath: Network.DerivationPath, formValues: AddCustomTokenForm.Raw, ) = coroutineScope { updateStatus(Status.Validating) - val result = validateTokenFormUseCase( + val result = useCasesFacade.validateTokenFormUseCase( networkId = networkId, formValues = formValues, ) @@ -73,20 +62,19 @@ internal class CustomCurrencyValidator @Inject constructor( launch { when (validatedForm) { is AddCustomTokenForm.Validated.All -> { - findOrCreateCurrency(userWalletId, networkId, derivationPath, validatedForm) + findOrCreateCurrency(networkId, derivationPath, validatedForm) } is AddCustomTokenForm.Validated.ContractAddressOnly -> { - findToken(userWalletId, networkId, derivationPath, validatedForm) + findToken(networkId, derivationPath, validatedForm) } is AddCustomTokenForm.Validated.Empty -> { - createCurrency(userWalletId, networkId, derivationPath, validatedForm = null) + createCurrency(networkId, derivationPath, validatedForm = null) } } }.saveInAndJoin(validateFormJobHolder) } private suspend fun findOrCreateCurrency( - userWalletId: UserWalletId, networkId: Network.ID, derivationPath: Network.DerivationPath, validatedForm: AddCustomTokenForm.Validated.All, @@ -96,14 +84,13 @@ internal class CustomCurrencyValidator @Inject constructor( currentState.prevFoundOrCreatedCurrency.contractAddress == validatedForm.contractAddress ) { // No need to search for token again if contract address is not changed - createCurrency(userWalletId, networkId, derivationPath, validatedForm) + createCurrency(networkId, derivationPath, validatedForm) return } updateStatus(Status.SearchingToken) - val foundToken = findTokenUseCase( - userWalletId = userWalletId, + val foundToken = useCasesFacade.findTokenUseCase( contractAddress = validatedForm.contractAddress, networkId = networkId, derivationPath = derivationPath, @@ -121,22 +108,20 @@ internal class CustomCurrencyValidator @Inject constructor( } if (foundToken != null) { - updateStateToValidated(userWalletId, foundToken, fillForm = true, isCustom = false) + updateStateToValidated(foundToken, fillForm = true, isCustom = false) } else { - createCurrency(userWalletId, networkId, derivationPath, validatedForm) + createCurrency(networkId, derivationPath, validatedForm) } } private suspend fun findToken( - userWalletId: UserWalletId, networkId: Network.ID, derivationPath: Network.DerivationPath, validatedForm: AddCustomTokenForm.Validated.ContractAddressOnly, ) { updateStatus(Status.SearchingToken) - val token = findTokenUseCase( - userWalletId = userWalletId, + val token = useCasesFacade.findTokenUseCase( contractAddress = validatedForm.contractAddress, networkId = networkId, derivationPath = derivationPath, @@ -155,17 +140,15 @@ internal class CustomCurrencyValidator @Inject constructor( return } - updateStateToValidated(userWalletId, token, fillForm = true, isCustom = false) + updateStateToValidated(token, fillForm = true, isCustom = false) } private suspend fun createCurrency( - userWalletId: UserWalletId, networkId: Network.ID, derivationPath: Network.DerivationPath, validatedForm: AddCustomTokenForm.Validated.All?, ) { - val currency = createCryptoCurrencyUseCase( - userWalletId = userWalletId, + val currency = useCasesFacade.createCryptoCurrencyUseCase( networkId = networkId, derivationPath = derivationPath, formValues = validatedForm, @@ -175,20 +158,14 @@ internal class CustomCurrencyValidator @Inject constructor( return } - updateStateToValidated(userWalletId, currency, fillForm = false, isCustom = validatedForm != null) + updateStateToValidated(currency, fillForm = false, isCustom = validatedForm != null) } - private suspend fun updateStateToValidated( - userWalletId: UserWalletId, - currency: CryptoCurrency, - fillForm: Boolean, - isCustom: Boolean, - ) { + private suspend fun updateStateToValidated(currency: CryptoCurrency, fillForm: Boolean, isCustom: Boolean) { val currentStatus = state.value.status if (currentStatus is Status.Validated && currentStatus.currency == currency) return - val isNotAdded = checkIsCurrencyNotAddedUseCase( - userWalletId = userWalletId, + val isNotAdded = useCasesFacade.checkIsCurrencyNotAddedUseCase( networkId = currency.network.id, derivationPath = currency.network.derivationPath, contractAddress = when (currency) { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/CustomTokenFormUseCasesFacade.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/CustomTokenFormUseCasesFacade.kt new file mode 100644 index 0000000000..6582d27d32 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/CustomTokenFormUseCasesFacade.kt @@ -0,0 +1,117 @@ +package com.tangem.features.managetokens.utils.list + +import arrow.core.Either +import arrow.core.NonEmptyList +import com.tangem.domain.managetokens.CheckIsCurrencyNotAddedUseCase +import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase +import com.tangem.domain.managetokens.FindTokenUseCase +import com.tangem.domain.managetokens.ValidateTokenFormUseCase +import com.tangem.domain.managetokens.model.AddCustomTokenForm +import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException +import com.tangem.domain.managetokens.model.exceptoin.FindTokenException +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.network.Network +import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase +import com.tangem.domain.wallets.usecase.BackendId +import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase +import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase +import com.tangem.features.managetokens.component.AddCustomTokenMode +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +@Suppress("LongParameterList") +internal class CustomTokenFormUseCasesFacade @AssistedInject constructor( + private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, + private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, + private val derivePublicKeysUseCase: DerivePublicKeysUseCase, + private val validateTokenFormUseCase: ValidateTokenFormUseCase, + private val createCryptoCurrencyUseCase: CreateCryptoCurrencyUseCase, + private val findTokenUseCase: FindTokenUseCase, + private val checkIsCurrencyNotAddedUseCase: CheckIsCurrencyNotAddedUseCase, + @Assisted private val mode: AddCustomTokenMode, +) { + + suspend fun hasMissedDerivationsUseCase(networksWithDerivationPath: Map): Boolean = + when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> hasMissedDerivationsUseCase.invoke( + userWalletId = mode.userWalletId, + networksWithDerivationPath = networksWithDerivationPath, + ) + } + + suspend fun addCryptoCurrenciesUseCase(currency: CryptoCurrency): Either = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> addCryptoCurrenciesUseCase.invoke( + userWalletId = mode.userWalletId, + currency = currency, + ) + } + + suspend fun derivePublicKeysUseCase(currencies: List): Either = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> derivePublicKeysUseCase.invoke( + userWalletId = mode.userWalletId, + currencies = currencies, + ) + } + + suspend fun checkIsCurrencyNotAddedUseCase( + networkId: Network.ID, + derivationPath: Network.DerivationPath, + contractAddress: String?, + ): Either = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> checkIsCurrencyNotAddedUseCase.invoke( + userWalletId = mode.userWalletId, + networkId = networkId, + derivationPath = derivationPath, + contractAddress = contractAddress, + ) + } + + suspend fun createCryptoCurrencyUseCase( + networkId: Network.ID, + derivationPath: Network.DerivationPath, + formValues: AddCustomTokenForm.Validated.All?, + ): Either = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> createCryptoCurrencyUseCase.invoke( + userWalletId = mode.userWalletId, + networkId = networkId, + derivationPath = derivationPath, + formValues = formValues, + ) + } + + suspend fun findTokenUseCase( + contractAddress: String, + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): Either = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> findTokenUseCase.invoke( + userWalletId = mode.userWalletId, + contractAddress = contractAddress, + networkId = networkId, + derivationPath = derivationPath, + ) + } + + suspend fun validateTokenFormUseCase( + networkId: Network.ID, + formValues: AddCustomTokenForm.Raw, + ): Either, AddCustomTokenForm.Validated> = when (mode) { + is AddCustomTokenMode.Account -> TODO("Account") + is AddCustomTokenMode.Wallet -> validateTokenFormUseCase.invoke( + networkId = networkId, + formValues = formValues, + ) + } + + @AssistedFactory + interface Factory { + fun create(mode: AddCustomTokenMode): CustomTokenFormUseCasesFacade + } +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt index 7664a6ce6e..0964dbe793 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt @@ -9,13 +9,14 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.message.DialogMessage -import com.tangem.core.ui.message.EventMessageAction import com.tangem.core.ui.message.SnackbarMessage -import com.tangem.domain.managetokens.* -import com.tangem.domain.managetokens.model.* +import com.tangem.domain.managetokens.model.CurrencyUnsupportedState +import com.tangem.domain.managetokens.model.ManageTokensListBatchingContext +import com.tangem.domain.managetokens.model.ManageTokensUpdateAction +import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent +import com.tangem.features.managetokens.component.ManageTokensMode import com.tangem.features.managetokens.component.ManageTokensSource import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.features.managetokens.impl.R @@ -24,7 +25,6 @@ import com.tangem.pagination.Batch import com.tangem.pagination.BatchAction import com.tangem.pagination.BatchListState import com.tangem.pagination.PaginationStatus -import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn @@ -42,37 +42,36 @@ import timber.log.Timber @Suppress("LongParameterList", "LargeClass") internal class ManageTokensListManager @AssistedInject constructor( - private val getManagedTokensUseCase: GetManagedTokensUseCase, - private val getDistinctManagedTokensUseCase: GetDistinctManagedCurrenciesUseCase, - private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase, - private val removeCustomCurrencyUseCase: RemoveCustomManagedCryptoCurrencyUseCase, - private val checkCurrencyUnsupportedUseCase: CheckCurrencyUnsupportedUseCase, private val messageSender: UiMessageSender, private val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, private val clipboardManager: ClipboardManager, + manageTokensWarningDelegateFactory: ManageTokensWarningDelegate.Factory, + @Assisted private val useCasesFacade: ManageTokensUseCasesFacade, + @Assisted private val source: ManageTokensSource, + @Assisted private val mode: ManageTokensMode, + @Assisted private val scope: CoroutineScope, @Assisted private val onCurrencySelect: (ManagedCryptoCurrency.Token) -> Unit = {}, ) : ManageTokensUiActions { - private lateinit var scope: CoroutineScope - private lateinit var source: ManageTokensSource - private val jobHolder = JobHolder() private val actionsFlow: MutableSharedFlow = MutableSharedFlow( replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) - private val state: MutableStateFlow = MutableStateFlow(ManageTokensListState()) + private val state: MutableStateFlow = + MutableStateFlow(ManageTokensListState(mode = mode)) + private val manageTokensWarningDelegate: ManageTokensWarningDelegate = manageTokensWarningDelegateFactory + .create(mode, source, this) private val changedCurrenciesManager = ChangedCurrenciesManager() private val uiManager = ManageTokensUiManager( state = state, - messageSender = messageSender, + manageTokensWarningDelegate = manageTokensWarningDelegate, dispatchers = dispatchers, actions = this, - scopeProvider = Provider { scope }, - sourceProvider = Provider { source }, + scope = scope, ) val currenciesToAdd: StateFlow = changedCurrenciesManager.currenciesToAdd.asStateFlow() @@ -84,62 +83,61 @@ internal class ManageTokensListManager @AssistedInject constructor( .distinctUntilChanged() val uiItems: Flow> = uiManager.items - suspend fun launchPagination(source: ManageTokensSource, userWalletId: UserWalletId?) = coroutineScope { - scope = this - this@ManageTokensListManager.source = source - - val batchFlow = getManagedTokensUseCase( + suspend fun launchPagination() = coroutineScope { + val loadUserTokensFromRemote = when (mode) { + is ManageTokensMode.Wallet -> source == ManageTokensSource.ONBOARDING + is ManageTokensMode.Account, + ManageTokensMode.None, + -> false + } + val batchFlow = useCasesFacade.getManagedTokensUseCase( context = ManageTokensListBatchingContext( actionsFlow = actionsFlow, coroutineScope = this, ), // only for onboarding case, change carefully and check repository implementation - loadUserTokensFromRemote = userWalletId != null && source == ManageTokensSource.ONBOARDING, + loadUserTokensFromRemote = loadUserTokensFromRemote, ) batchFlow.state - .onEach { state -> updateState(state, userWalletId) } + .onEach { state -> updateState(state) } .flowOn(dispatchers.default) .launchIn(scope = this) .saveIn(jobHolder) // Initial load - reload(userWalletId) + reload() } - suspend fun reload(userWalletId: UserWalletId?) { - state.value = ManageTokensListState() + suspend fun reload() { + state.value = ManageTokensListState(mode = mode) actionsFlow.emit( BatchAction.Reload( - requestParams = ManageTokensListConfig(userWalletId, searchText = null), + requestParams = useCasesFacade.manageTokensListConfig(searchText = null), ), ) } - suspend fun loadMore(userWalletId: UserWalletId?, query: String) { + suspend fun loadMore(query: String) { actionsFlow.emit( BatchAction.LoadMore( - requestParams = ManageTokensListConfig(userWalletId, query), + requestParams = useCasesFacade.manageTokensListConfig(query), ), ) } - suspend fun search(userWalletId: UserWalletId?, query: String) { - state.value = ManageTokensListState(searchQuery = query) + suspend fun search(query: String) { + state.value = ManageTokensListState(mode = mode, searchQuery = query) actionsFlow.emit( BatchAction.Reload( - requestParams = ManageTokensListConfig( - userWalletId = userWalletId, + requestParams = useCasesFacade.manageTokensListConfig( searchText = query, ), ), ) } - private fun updateState( - batchListState: BatchListState>, - userWalletId: UserWalletId?, - ) { + private fun updateState(batchListState: BatchListState>) { state.update { state -> state.copy( status = batchListState.status, @@ -154,7 +152,6 @@ internal class ManageTokensListManager @AssistedInject constructor( ) { state.update { state -> state.copy( - userWalletId = userWalletId, currencyBatches = emptyList(), uiBatches = listOf( Batch( @@ -170,7 +167,7 @@ internal class ManageTokensListManager @AssistedInject constructor( scope.launch { state.update { state -> - val newBatches = getDistinctManagedTokensUseCase(batchListState.data) + val newBatches = useCasesFacade.getDistinctManagedTokensUseCase(batchListState.data) val currentBatches = state.currencyBatches // Distinct until changed @@ -181,9 +178,13 @@ internal class ManageTokensListManager @AssistedInject constructor( return@launch } - val canEditItems = userWalletId != null + val canEditItems = when (state.mode) { + is ManageTokensMode.Account, + is ManageTokensMode.Wallet, + -> true + ManageTokensMode.None -> false + } state.copy( - userWalletId = userWalletId, currencyBatches = newBatches, uiBatches = uiManager.createOrUpdateUiBatches(newBatches, canEditItems), canEditItems = canEditItems, @@ -216,10 +217,10 @@ internal class ManageTokensListManager @AssistedInject constructor( sendSelectCurrencyAnalyticsEvent(currency, isSelected = false) } - override fun removeCustomCurrency(userWalletId: UserWalletId, currency: ManagedCryptoCurrency.Custom) { + override fun removeCustomCurrency(currency: ManagedCryptoCurrency.Custom) { scope.launch { - removeCustomCurrencyUseCase.invoke(userWalletId, currency) - .onRight { reload(userWalletId) } + useCasesFacade.removeCustomCurrencyUseCase(currency) + .onRight { reload() } .onLeft { Timber.e(it) } } } @@ -258,9 +259,8 @@ internal class ManageTokensListManager @AssistedInject constructor( actionsFlow.tryEmit(action) } - override suspend fun checkHasLinkedTokens(userWalletId: UserWalletId, network: Network): Boolean { - return checkHasLinkedTokensUseCase( - userWalletId = userWalletId, + override suspend fun checkHasLinkedTokens(network: Network): Boolean { + return useCasesFacade.checkHasLinkedTokensUseCase( network = network, tempAddedTokens = changedCurrenciesManager.currenciesToAdd.value, tempRemovedTokens = changedCurrenciesManager.currenciesToRemove.value, @@ -269,7 +269,7 @@ internal class ManageTokensListManager @AssistedInject constructor( it, """ Failed to check linked tokens - |- User wallet ID: $userWalletId + |- Mode: $mode |- Network ID: ${network.id} """.trimIndent(), ) @@ -286,18 +286,16 @@ internal class ManageTokensListManager @AssistedInject constructor( } override suspend fun checkCurrencyUnsupportedState( - userWalletId: UserWalletId, sourceNetwork: ManagedCryptoCurrency.SourceNetwork, ): CurrencyUnsupportedState? { - return checkCurrencyUnsupportedUseCase( - userWalletId = userWalletId, + return useCasesFacade.checkCurrencyUnsupportedUseCase( sourceNetwork = sourceNetwork, ).getOrElse { Timber.e( it, """ Failed to check currency unsupported state - |- User wallet ID: $userWalletId + |- Mode: $mode |- Source Network: $sourceNetwork """.trimIndent(), ) @@ -359,8 +357,7 @@ internal class ManageTokensListManager @AssistedInject constructor( if (currency !is ManagedCryptoCurrency.Token) return@launch if (isSelected) { - val userWalletId = state.value.userWalletId - val unsupportedState = userWalletId?.let { checkCurrencyUnsupportedState(it, source) } + val unsupportedState = checkCurrencyUnsupportedState(source) if (unsupportedState != null) { showUnsupportedWarning(unsupportedState) } else { @@ -368,7 +365,7 @@ internal class ManageTokensListManager @AssistedInject constructor( } } else { if (checkNeedToShowRemoveNetworkWarning(currency, source.network)) { - showRemoveNetworkWarning( + manageTokensWarningDelegate.showRemoveNetworkWarning( currency = currency, network = source.network, isCoin = source is ManagedCryptoCurrency.SourceNetwork.Main, @@ -404,67 +401,6 @@ internal class ManageTokensListManager @AssistedInject constructor( messageSender.send(message) } - private suspend fun showRemoveNetworkWarning( - currency: ManagedCryptoCurrency, - network: Network, - isCoin: Boolean, - onConfirm: () -> Unit, - ) { - val userWalletId = state.value.userWalletId - val hasLinkedTokens = if (userWalletId == null || !isCoin) { - false - } else { - checkHasLinkedTokens(userWalletId, network) - } - val canHideWithoutConfirming = source == ManageTokensSource.ONBOARDING - - if (hasLinkedTokens) { - showLinkedTokensWarning(currency, network) - } else if (canHideWithoutConfirming) { - onConfirm() - } else { - showHideTokenWarning(currency, onConfirm) - } - } - - private fun showLinkedTokensWarning(currency: ManagedCryptoCurrency, network: Network) { - val message = DialogMessage( - title = resourceReference( - id = R.string.token_details_unable_hide_alert_title, - formatArgs = wrappedList(currency.name), - ), - message = resourceReference( - id = R.string.token_details_unable_hide_alert_message, - formatArgs = wrappedList( - currency.name, - currency.symbol, - network.name, - ), - ), - ) - messageSender.send(message) - } - - private fun showHideTokenWarning(currency: ManagedCryptoCurrency, onConfirm: () -> Unit) { - val message = DialogMessage( - title = resourceReference( - id = R.string.token_details_hide_alert_title, - formatArgs = wrappedList(currency.name), - ), - message = resourceReference(R.string.token_details_hide_alert_message), - firstActionBuilder = { - EventMessageAction( - title = resourceReference(R.string.token_details_hide_alert_hide), - warning = true, - onClick = onConfirm, - ) - }, - secondActionBuilder = { cancelAction() }, - ) - - messageSender.send(message) - } - private fun Batch>.currencyIndexById(id: ManagedCryptoCurrency.ID): Int { return data .indexOfFirst { it.id == id } @@ -474,6 +410,12 @@ internal class ManageTokensListManager @AssistedInject constructor( @AssistedFactory interface Factory { - fun create(onCurrencySelect: (ManagedCryptoCurrency.Token) -> Unit = {}): ManageTokensListManager + fun create( + scope: CoroutineScope, + mode: ManageTokensMode, + source: ManageTokensSource, + useCasesFacade: ManageTokensUseCasesFacade, + onCurrencySelect: (ManagedCryptoCurrency.Token) -> Unit = {}, + ): ManageTokensListManager } } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListState.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListState.kt index 42fa36da37..b559a93ae7 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListState.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListState.kt @@ -3,7 +3,7 @@ package com.tangem.features.managetokens.utils.list import com.tangem.domain.managetokens.model.ManageTokensListConfig import com.tangem.domain.managetokens.model.ManageTokensUpdateAction import com.tangem.domain.managetokens.model.ManagedCryptoCurrency -import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.features.managetokens.component.ManageTokensMode import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.pagination.Batch import com.tangem.pagination.BatchAction @@ -13,7 +13,7 @@ internal typealias ManageTokensBatchAction = BatchAction = PaginationStatus.None, - val userWalletId: UserWalletId? = null, + val mode: ManageTokensMode, val uiBatches: List>> = mutableListOf(), val currencyBatches: List>> = mutableListOf(), val canEditItems: Boolean = true, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt index 8c1873e7da..13a4a44cbd 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt @@ -3,7 +3,6 @@ package com.tangem.features.managetokens.utils.list import com.tangem.domain.managetokens.model.CurrencyUnsupportedState import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWalletId internal interface ManageTokensUiActions { @@ -13,14 +12,13 @@ internal interface ManageTokensUiActions { fun removeCurrency(batchKey: Int, currency: ManagedCryptoCurrency.Token, network: Network) - fun removeCustomCurrency(userWalletId: UserWalletId, currency: ManagedCryptoCurrency.Custom) + fun removeCustomCurrency(currency: ManagedCryptoCurrency.Custom) fun checkNeedToShowRemoveNetworkWarning(currency: ManagedCryptoCurrency.Token, network: Network): Boolean - suspend fun checkHasLinkedTokens(userWalletId: UserWalletId, network: Network): Boolean + suspend fun checkHasLinkedTokens(network: Network): Boolean suspend fun checkCurrencyUnsupportedState( - userWalletId: UserWalletId, sourceNetwork: ManagedCryptoCurrency.SourceNetwork, ): CurrencyUnsupportedState? } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt index 8c038934c5..23bb3ba720 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt @@ -1,19 +1,10 @@ package com.tangem.features.managetokens.utils.list -import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.wrappedList -import com.tangem.core.ui.message.DialogMessage -import com.tangem.core.ui.message.EventMessageAction import com.tangem.domain.managetokens.model.ManagedCryptoCurrency -import com.tangem.domain.models.network.Network -import com.tangem.features.managetokens.component.ManageTokensSource import com.tangem.features.managetokens.entity.item.CurrencyItemUM -import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.utils.mapper.toUiModel import com.tangem.features.managetokens.utils.ui.update import com.tangem.pagination.Batch -import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.addOrReplace import kotlinx.collections.immutable.ImmutableList @@ -29,19 +20,12 @@ import kotlinx.coroutines.launch @Suppress("LongParameterList") internal class ManageTokensUiManager( private val state: MutableStateFlow, - private val messageSender: UiMessageSender, private val dispatchers: CoroutineDispatcherProvider, - private val scopeProvider: Provider, - private val sourceProvider: Provider, + private val scope: CoroutineScope, private val actions: ManageTokensUiActions, + private val manageTokensWarningDelegate: ManageTokensWarningDelegate, ) { - private val scope: CoroutineScope - get() = scopeProvider() - - private val source: ManageTokensSource - get() = sourceProvider() - @OptIn(ExperimentalCoroutinesApi::class) val items: Flow> = state .mapLatest { state -> @@ -109,75 +93,11 @@ internal class ManageTokensUiManager( } private fun removeCustomCurrency(currency: ManagedCryptoCurrency.Custom) = scope.launch(dispatchers.default) { - showRemoveNetworkWarning( + manageTokensWarningDelegate.showRemoveNetworkWarning( currency = currency, network = currency.network, isCoin = currency is ManagedCryptoCurrency.Custom.Coin, - onConfirm = { - val userWalletId = requireNotNull(state.value.userWalletId) { "UserWalletId is null. Can not remove" } - actions.removeCustomCurrency(userWalletId = userWalletId, currency = currency) - }, + onConfirm = { actions.removeCustomCurrency(currency = currency) }, ) } - - private suspend fun showRemoveNetworkWarning( - currency: ManagedCryptoCurrency, - network: Network, - isCoin: Boolean, - onConfirm: () -> Unit, - ) { - val userWalletId = state.value.userWalletId - val hasLinkedTokens = if (userWalletId == null || !isCoin) { - false - } else { - actions.checkHasLinkedTokens(userWalletId, network) - } - val canHideWithoutConfirming = source == ManageTokensSource.ONBOARDING - - if (hasLinkedTokens) { - showLinkedTokensWarning(currency, network) - } else if (canHideWithoutConfirming) { - onConfirm() - } else { - showHideTokenWarning(currency, onConfirm) - } - } - - private fun showLinkedTokensWarning(currency: ManagedCryptoCurrency, network: Network) { - val message = DialogMessage( - title = resourceReference( - id = R.string.token_details_unable_hide_alert_title, - formatArgs = wrappedList(currency.name), - ), - message = resourceReference( - id = R.string.token_details_unable_hide_alert_message, - formatArgs = wrappedList( - currency.name, - currency.symbol, - network.name, - ), - ), - ) - messageSender.send(message) - } - - private fun showHideTokenWarning(currency: ManagedCryptoCurrency, onConfirm: () -> Unit) { - val message = DialogMessage( - title = resourceReference( - id = R.string.token_details_hide_alert_title, - formatArgs = wrappedList(currency.name), - ), - message = resourceReference(R.string.token_details_hide_alert_message), - firstActionBuilder = { - EventMessageAction( - title = resourceReference(R.string.token_details_hide_alert_hide), - warning = true, - onClick = onConfirm, - ) - }, - secondActionBuilder = { cancelAction() }, - ) - - messageSender.send(message) - } } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUseCasesFacade.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUseCasesFacade.kt new file mode 100644 index 0000000000..6d246fd5e0 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUseCasesFacade.kt @@ -0,0 +1,108 @@ +package com.tangem.features.managetokens.utils.list + +import arrow.core.Either +import arrow.core.left +import com.tangem.domain.managetokens.* +import com.tangem.domain.managetokens.model.CurrencyUnsupportedState +import com.tangem.domain.managetokens.model.ManageTokensListConfig +import com.tangem.domain.managetokens.model.ManagedCryptoCurrency +import com.tangem.domain.models.network.Network +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase +import com.tangem.features.managetokens.component.ManageTokensMode +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +@Suppress("LongParameterList") +internal class ManageTokensUseCasesFacade @AssistedInject constructor( + val getManagedTokensUseCase: GetManagedTokensUseCase, + val getDistinctManagedTokensUseCase: GetDistinctManagedCurrenciesUseCase, + private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase, + private val removeCustomCurrencyUseCase: RemoveCustomManagedCryptoCurrencyUseCase, + private val checkCurrencyUnsupportedUseCase: CheckCurrencyUnsupportedUseCase, + private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, + private val saveManagedTokensUseCase: SaveManagedTokensUseCase, + @Assisted private val mode: ManageTokensMode, +) { + + private val nonePortfolioError: IllegalStateException + get() = IllegalStateException("Unsupported") + + fun manageTokensListConfig(searchText: String?): ManageTokensListConfig { + val userWalletId: UserWalletId? = when (mode) { + is ManageTokensMode.Account -> TODO("Account") + ManageTokensMode.None -> null + is ManageTokensMode.Wallet -> mode.userWalletId + } + return ManageTokensListConfig(userWalletId, searchText) + } + + suspend fun removeCustomCurrencyUseCase(customCurrency: ManagedCryptoCurrency.Custom): Either { + return when (mode) { + is ManageTokensMode.Account -> TODO("Account") + is ManageTokensMode.Wallet -> removeCustomCurrencyUseCase.invoke( + userWalletId = mode.userWalletId, + customCurrency = customCurrency, + ) + ManageTokensMode.None -> nonePortfolioError.left() + } + } + + suspend fun checkHasLinkedTokensUseCase( + network: Network, + tempAddedTokens: Map>, + tempRemovedTokens: Map>, + ): Either { + return when (mode) { + is ManageTokensMode.Account -> TODO("Account") + is ManageTokensMode.Wallet -> checkHasLinkedTokensUseCase.invoke( + userWalletId = mode.userWalletId, + network = network, + tempAddedTokens = tempAddedTokens, + tempRemovedTokens = tempRemovedTokens, + ) + ManageTokensMode.None -> nonePortfolioError.left() + } + } + + suspend fun checkCurrencyUnsupportedUseCase( + sourceNetwork: ManagedCryptoCurrency.SourceNetwork, + ): Either { + return when (mode) { + is ManageTokensMode.Account -> TODO("Account") + is ManageTokensMode.Wallet -> checkCurrencyUnsupportedUseCase.invoke( + userWalletId = mode.userWalletId, + sourceNetwork = sourceNetwork, + ) + ManageTokensMode.None -> nonePortfolioError.left() + } + } + + suspend fun hasMissedDerivationsUseCase(network: Map): Boolean = when (mode) { + is ManageTokensMode.Account -> TODO("Account") + is ManageTokensMode.Wallet -> hasMissedDerivationsUseCase.invoke( + userWalletId = mode.userWalletId, + networksWithDerivationPath = network, + ) + ManageTokensMode.None -> false + } + + suspend fun saveManagedTokensUseCase( + currenciesToAdd: Map>, + currenciesToRemove: Map>, + ): Either = when (mode) { + is ManageTokensMode.Account -> TODO("Account") + is ManageTokensMode.Wallet -> saveManagedTokensUseCase.invoke( + userWalletId = mode.userWalletId, + currenciesToAdd = currenciesToAdd, + currenciesToRemove = currenciesToRemove, + ) + ManageTokensMode.None -> nonePortfolioError.left() + } + + @AssistedFactory + interface Factory { + fun create(mode: ManageTokensMode): ManageTokensUseCasesFacade + } +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensWarningDelegate.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensWarningDelegate.kt new file mode 100644 index 0000000000..037e69b449 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensWarningDelegate.kt @@ -0,0 +1,98 @@ +package com.tangem.features.managetokens.utils.list + +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.message.DialogMessage +import com.tangem.core.ui.message.EventMessageAction +import com.tangem.domain.managetokens.model.ManagedCryptoCurrency +import com.tangem.domain.models.network.Network +import com.tangem.features.managetokens.component.ManageTokensMode +import com.tangem.features.managetokens.component.ManageTokensSource +import com.tangem.features.managetokens.impl.R +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class ManageTokensWarningDelegate @AssistedInject constructor( + private val messageSender: UiMessageSender, + @Assisted private val mode: ManageTokensMode, + @Assisted private val source: ManageTokensSource, + @Assisted private val uiActions: ManageTokensUiActions, +) { + + suspend fun showRemoveNetworkWarning( + currency: ManagedCryptoCurrency, + network: Network, + isCoin: Boolean, + onConfirm: () -> Unit, + ) { + val isNonePortfolio = when (mode) { + ManageTokensMode.None -> true + is ManageTokensMode.Account, + is ManageTokensMode.Wallet, + -> false + } + val hasLinkedTokens = if (isNonePortfolio || !isCoin) { + false + } else { + uiActions.checkHasLinkedTokens(network) + } + val canHideWithoutConfirming = source == ManageTokensSource.ONBOARDING + + if (hasLinkedTokens) { + showLinkedTokensWarning(currency, network) + } else if (canHideWithoutConfirming) { + onConfirm() + } else { + showHideTokenWarning(currency, onConfirm) + } + } + + private fun showLinkedTokensWarning(currency: ManagedCryptoCurrency, network: Network) { + val message = DialogMessage( + title = resourceReference( + id = R.string.token_details_unable_hide_alert_title, + formatArgs = wrappedList(currency.name), + ), + message = resourceReference( + id = R.string.token_details_unable_hide_alert_message, + formatArgs = wrappedList( + currency.name, + currency.symbol, + network.name, + ), + ), + ) + messageSender.send(message) + } + + private fun showHideTokenWarning(currency: ManagedCryptoCurrency, onConfirm: () -> Unit) { + val message = DialogMessage( + title = resourceReference( + id = R.string.token_details_hide_alert_title, + formatArgs = wrappedList(currency.name), + ), + message = resourceReference(R.string.token_details_hide_alert_message), + firstActionBuilder = { + EventMessageAction( + title = resourceReference(R.string.token_details_hide_alert_hide), + warning = true, + onClick = onConfirm, + ) + }, + secondActionBuilder = { cancelAction() }, + ) + + messageSender.send(message) + } + + @AssistedFactory + interface Factory { + fun create( + mode: ManageTokensMode, + source: ManageTokensSource, + uiActions: ManageTokensUiActions, + ): ManageTokensWarningDelegate + } +} \ No newline at end of file