From d42cb2a79e071b2f37b6f9a6b50b121061c6c5c1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 18 May 2026 17:45:13 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/tap/routing/utils/ChildFactory.kt | 9 ++ .../com/tangem/common/routing/AppRoute.kt | 5 + .../configs/feature_toggles_config.json | 4 + .../api/addfunds/AddFundsComponent.kt | 14 +++ .../api/choosetoken/ChooseTokenBridge.kt | 5 + .../impl/addfunds/DefaultAddFundsComponent.kt | 108 ++++++++++++++++++ .../addfunds/di/AddFundsComponentModule.kt | 16 +++ .../impl/addfunds/di/AddFundsModelModule.kt | 20 ++++ .../impl/addfunds/model/AddFundsModel.kt | 103 +++++++++++++++++ .../addtoportfolio/TokenActionsComponent.kt | 8 +- .../model/AddToPortfolioModel.kt | 8 +- .../model/TokenActionsUiBuilder.kt | 22 +++- .../addtoportfolio/ui/TokenActionsContent.kt | 8 +- .../ui/TokenActionsContentV2.kt | 7 +- .../addtoportfolio/ui/state/TokenActionsUM.kt | 3 +- .../featuretoggles/WalletFeatureToggles.kt | 2 + .../wallet/child/wallet/model/WalletModel.kt | 7 ++ .../model/intents/WalletClickIntents.kt | 5 + .../DefaultWalletFeatureToggles.kt | 3 + .../router/DefaultWalletRouter.kt | 4 + .../presentation/router/InnerWalletRouter.kt | 3 + .../wallet/state/model/WalletManageButton.kt | 14 +++ .../transformers/AddWalletTransformer.kt | 2 + .../InitializeWalletsTransformer.kt | 14 ++- .../ReinitializeNewWalletTransformer.kt | 2 + .../ReinitializeWalletTransformer.kt | 2 + .../SetRefreshStateTransformer.kt | 5 +- .../transformers/UnlockWalletTransformer.kt | 2 + .../state/utils/MultiWalletActionsExt.kt | 1 + .../state/utils/WalletLoadingStateFactory.kt | 15 ++- 30 files changed, 397 insertions(+), 24 deletions(-) create mode 100644 features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/addfunds/AddFundsComponent.kt create mode 100644 features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/DefaultAddFundsComponent.kt create mode 100644 features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsComponentModule.kt create mode 100644 features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsModelModule.kt create mode 100644 features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/model/AddFundsModel.kt diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index d9fc9e5fec..07f41386e5 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -9,6 +9,7 @@ import com.tangem.feature.stories.api.StoriesComponent import com.tangem.feature.usedesk.api.UsedeskComponent import com.tangem.feature.walletsettings.component.WalletSettingsComponent import com.tangem.features.account.AccountCreateEditComponent +import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent import com.tangem.features.account.AccountDetailsComponent import com.tangem.features.account.ArchivedAccountListComponent import com.tangem.features.createwalletselection.CreateWalletSelectionComponent @@ -111,6 +112,7 @@ internal class ChildFactory @Inject constructor( private val kycComponentFactory: KycComponent.Factory, private val yieldSupplyEntryComponentFactory: YieldSupplyEntryComponent.Factory, private val feedEntryComponentFactory: FeedEntryComponent.Factory, + private val addFundsComponentFactory: AddFundsComponent.Factory, ) { @Suppress("LongMethod", "CyclomaticComplexMethod") @@ -227,6 +229,13 @@ internal class ChildFactory @Inject constructor( componentFactory = buyCryptoComponentFactory, ) } + is AppRoute.AddFunds -> { + createComponentChild( + context = context, + params = AddFundsComponent.Params(userWalletId = route.userWalletId), + componentFactory = addFundsComponentFactory, + ) + } is AppRoute.SellCrypto -> { createComponentChild( context = context, diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index acb5a42b6b..d62597e6a8 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -58,6 +58,11 @@ sealed class AppRoute(val path: String) : Route { @Serializable data object Wallet : AppRoute(path = "/wallet") + @Serializable + data class AddFunds( + val userWalletId: UserWalletId, + ) : AppRoute(path = "/add_funds/${userWalletId.stringValue}") + @Serializable data class CurrencyDetails( val userWalletId: UserWalletId, diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index 13eea8afdb..485f0eab26 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -74,5 +74,9 @@ { "name": "TWI_1403_PUSH_NOTIFICATION_SETTINGS_ENABLED", "version": "undefined" + }, + { + "name": "AND_15310_ADD_FUNDS_STAGE1", + "version": "undefined" } ] diff --git a/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/addfunds/AddFundsComponent.kt b/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/addfunds/AddFundsComponent.kt new file mode 100644 index 0000000000..c8481039a9 --- /dev/null +++ b/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/addfunds/AddFundsComponent.kt @@ -0,0 +1,14 @@ +package com.tangem.features.commonfeatures.api.addfunds + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.models.wallet.UserWalletId + +interface AddFundsComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/choosetoken/ChooseTokenBridge.kt b/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/choosetoken/ChooseTokenBridge.kt index b581a64908..cc89e84d25 100644 --- a/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/choosetoken/ChooseTokenBridge.kt +++ b/features/common-features/api/src/main/java/com/tangem/features/commonfeatures/api/choosetoken/ChooseTokenBridge.kt @@ -41,6 +41,11 @@ interface ChooseTokenBridge : ChooseTokenBridgeInternal { isShowMarketBlock = true, isShowPaymentAccount = true, ) + val AddFunds = Settings( + title = resourceReference(R.string.swapping_to_title), + isShowMarketBlock = true, + isShowPaymentAccount = false, + ) } } diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/DefaultAddFundsComponent.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/DefaultAddFundsComponent.kt new file mode 100644 index 0000000000..b2a141752b --- /dev/null +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/DefaultAddFundsComponent.kt @@ -0,0 +1,108 @@ +package com.tangem.features.commonfeatures.impl.addfunds + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +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.decompose.context.child +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent +import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet +import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemeRedesign +import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent +import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent +import com.tangem.features.commonfeatures.impl.R +import com.tangem.features.commonfeatures.impl.addfunds.model.AddFundsModel +import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent +import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultAddFundsComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted private val params: AddFundsComponent.Params, + chooseTokenComponentFactory: ChooseTokenComponent.Factory, + tokenActionsComponentFactory: TokenActionsComponent.Factory, +) : AppComponentContext by appComponentContext, AddFundsComponent { + + private val model: AddFundsModel = getOrCreateModel(params) + + private val chooseTokenComponent: ChooseTokenComponent = chooseTokenComponentFactory.create( + context = child(key = "addFundsChooseToken"), + params = ChooseTokenComponent.Params(bridge = model.chooseTokenBridge), + ) + + private val tokenActionsComponent: TokenActionsComponent = tokenActionsComponentFactory.create( + context = child(key = "addFundsTokenActions"), + params = TokenActionsComponent.Params( + eventBuilder = PortfolioAnalyticsEvent.EventBuilder( + tokenSymbol = "", + source = ANALYTICS_SOURCE, + category = ANALYTICS_CATEGORY, + ), + data = model.tokenActionsData, + callbacks = model, + bottomAction = TokenActionsComponent.BottomAction.GoToToken, + isRedesignForced = true, + ), + ) + + @Composable + override fun Content(modifier: Modifier) { + chooseTokenComponent.Content(modifier) + val isTokenActionsShown by model.isTokenActionsShown.collectAsStateWithLifecycle() + if (isTokenActionsShown) { + // force use redesign theme here according to the task requirements, will be reworked in the next release + TangemThemeRedesign { + TangemModalBottomSheet( + config = TangemBottomSheetConfig( + isShown = true, + onDismissRequest = model::onTokenActionsDismiss, + content = TangemBottomSheetConfigContent.Empty, + ), + containerColor = TangemTheme.colors2.surface.level2, + scrollableContent = true, + title = { + TangemModalBottomSheetTitle( + modifier = Modifier.fillMaxWidth(), + title = resourceReference(R.string.common_get_token), + endIconRes = R.drawable.ic_close_24, + onEndClick = model::onTokenActionsDismiss, + ) + }, + content = { _ -> + Column( + modifier = Modifier.padding( + start = TangemTheme.dimens2.x4, + top = TangemTheme.dimens2.x2, + end = TangemTheme.dimens2.x4, + bottom = TangemTheme.dimens2.x4, + ), + ) { + tokenActionsComponent.Content(Modifier) + } + }, + ) + } + } + } + + @AssistedFactory + interface Factory : AddFundsComponent.Factory { + override fun create(context: AppComponentContext, params: AddFundsComponent.Params): DefaultAddFundsComponent + } + + private companion object { + const val ANALYTICS_SOURCE = "AddFunds" + const val ANALYTICS_CATEGORY = "Add Funds" + } +} \ No newline at end of file diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsComponentModule.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsComponentModule.kt new file mode 100644 index 0000000000..7ebd2f3ddf --- /dev/null +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsComponentModule.kt @@ -0,0 +1,16 @@ +package com.tangem.features.commonfeatures.impl.addfunds.di + +import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent +import com.tangem.features.commonfeatures.impl.addfunds.DefaultAddFundsComponent +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +internal interface AddFundsComponentModule { + + @Binds + fun bindAddFundsComponentFactory(factory: DefaultAddFundsComponent.Factory): AddFundsComponent.Factory +} \ No newline at end of file diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsModelModule.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsModelModule.kt new file mode 100644 index 0000000000..efc483ebf2 --- /dev/null +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/di/AddFundsModelModule.kt @@ -0,0 +1,20 @@ +package com.tangem.features.commonfeatures.impl.addfunds.di + +import com.tangem.core.decompose.di.ModelComponent +import com.tangem.core.decompose.model.Model +import com.tangem.features.commonfeatures.impl.addfunds.model.AddFundsModel +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +@InstallIn(ModelComponent::class) +internal interface AddFundsModelModule { + + @Binds + @IntoMap + @ClassKey(AddFundsModel::class) + fun addFundsModel(model: AddFundsModel): Model +} \ No newline at end of file diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/model/AddFundsModel.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/model/AddFundsModel.kt new file mode 100644 index 0000000000..a7bc37b8fa --- /dev/null +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addfunds/model/AddFundsModel.kt @@ -0,0 +1,103 @@ +package com.tangem.features.commonfeatures.impl.addfunds.model + +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter +import com.tangem.common.ui.markets.action.CryptoCurrencyData +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2 +import com.tangem.domain.models.account.AccountStatus +import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent +import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload +import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge +import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult +import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject + +@ModelScoped +internal class AddFundsModel @Inject constructor( + paramsContainer: ParamsContainer, + chooseTokenBridgeFactory: ChooseTokenBridge.Factory, + private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2, + private val appRouter: AppRouter, + override val dispatchers: CoroutineDispatcherProvider, +) : Model(), TokenActionsComponent.Callbacks { + + private val params = paramsContainer.require() + + val chooseTokenBridge: ChooseTokenBridge = chooseTokenBridgeFactory.create( + modelScope = modelScope, + settings = ChooseTokenBridge.Settings.AddFunds, + analyticsPayload = setOf( + ChooseTokenAnalyticsPayload.ScreensSources(SCREEN_SOURCE), + ), + ) + + private val selectedToken = MutableStateFlow(null) + + val isTokenActionsShown: StateFlow = selectedToken + .map { it != null } + .stateIn(modelScope, SharingStarted.Eagerly, initialValue = false) + + @OptIn(ExperimentalCoroutinesApi::class) + val tokenActionsData: Flow = selectedToken + .filterNotNull() + .flatMapLatest { result -> + val cryptoPortfolio = result.account as? AccountStatus.CryptoPortfolio + ?: return@flatMapLatest emptyFlow() + getCryptoCurrencyActionsUseCase( + accountId = cryptoPortfolio.account.accountId, + currency = result.currency.currency, + ).map { actionsState -> + CryptoCurrencyData( + userWallet = result.wallet, + status = result.currency, + actions = actionsState.states, + isAccountMode = false, + account = cryptoPortfolio, + ) + } + } + + init { + chooseTokenBridge.selectWalletTab(params.userWalletId) + observeBridge() + } + + override fun onBottomActionClick() { + val result = selectedToken.value ?: return + selectedToken.value = null + appRouter.replaceCurrent( + AppRoute.CurrencyDetails( + userWalletId = result.wallet.walletId, + currency = result.currency.currency, + ), + ) + } + + fun onTokenActionsDismiss() { + selectedToken.value = null + } + + private fun observeBridge() { + modelScope.launch { + chooseTokenBridge.onCurrencyChosen.receiveAsFlow().collect { result -> + selectedToken.value = result + } + } + modelScope.launch { + chooseTokenBridge.onClose.receiveAsFlow().collect { + appRouter.pop() + } + } + } + + private companion object { + const val SCREEN_SOURCE = "AddFunds" + } +} \ No newline at end of file diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/TokenActionsComponent.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/TokenActionsComponent.kt index 30cd1227fc..51c2963a3b 100644 --- a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/TokenActionsComponent.kt +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/TokenActionsComponent.kt @@ -46,7 +46,7 @@ internal class TokenActionsComponent @AssistedInject constructor( val state = model.uiState.collectAsStateWithLifecycle() val bottomSheet by bottomSheetSlot.subscribeAsState() val tokenActionsUM = state.value ?: return - if (LocalRedesignEnabled.current) { + if (LocalRedesignEnabled.current || params.isRedesignForced) { TokenActionsContentV2( modifier = modifier, state = tokenActionsUM, @@ -75,10 +75,14 @@ internal class TokenActionsComponent @AssistedInject constructor( val eventBuilder: PortfolioAnalyticsEvent.EventBuilder, val data: Flow, val callbacks: Callbacks, + val bottomAction: BottomAction = BottomAction.Later, + val isRedesignForced: Boolean = false, ) + enum class BottomAction { Later, GoToToken } + interface Callbacks { - fun onLaterClick() + fun onBottomActionClick() } @AssistedFactory diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/AddToPortfolioModel.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/AddToPortfolioModel.kt index 70567aab54..a9aaa92cb8 100644 --- a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/AddToPortfolioModel.kt +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/AddToPortfolioModel.kt @@ -307,7 +307,7 @@ internal class AddToPortfolioModel @Inject constructor( .onEmpty { finishSuccessFlow(result) } .launchIn(this) - callbackDelegate.onLaterClick.receiveAsFlow().first() + callbackDelegate.onChooseTokenBottomActionClick.receiveAsFlow().first() analyticsEventHandler.send(eventBuilder.getTokenLater()) finishSuccessFlow(result) } @@ -524,7 +524,7 @@ internal class AddToPortfolioCallbackDelegate @Inject constructor() : UserPortfolioComponent.Callbacks { val onNetworkSelected = Channel() - val onLaterClick = Channel() + val onChooseTokenBottomActionClick = Channel() val onChangeNetworkClick = Channel() val onChangePortfolioClick = Channel() val onTokenAdded = Channel() @@ -534,8 +534,8 @@ internal class AddToPortfolioCallbackDelegate @Inject constructor() : onNetworkSelected.trySend(network) } - override fun onLaterClick() { - onLaterClick.trySend(Unit) + override fun onBottomActionClick() { + onChooseTokenBottomActionClick.trySend(Unit) } override fun onChangeNetworkClick() { diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/TokenActionsUiBuilder.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/TokenActionsUiBuilder.kt index 2d4edace7e..0c59500c53 100644 --- a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/TokenActionsUiBuilder.kt +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/model/TokenActionsUiBuilder.kt @@ -21,9 +21,12 @@ import com.tangem.core.ui.ds.badge.TangemBadgeShape import com.tangem.core.ui.ds.badge.TangemBadgeSize import com.tangem.core.ui.ds.badge.TangemBadgeUM import com.tangem.core.ui.ds.image.TangemIconUM +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.format.bigdecimal.* import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.commonfeatures.impl.R import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.wallets.usecase.GetWalletIconUseCase @@ -48,7 +51,7 @@ internal class TokenActionsUiBuilder @Inject constructor( appCurrency: AppCurrency, isBalanceHidden: Boolean, ): TokenActionsUM { - return if (designFeatureToggles.isRedesignEnabled) { + return if (designFeatureToggles.isRedesignEnabled || params.isRedesignForced) { buildV2( cryptoCurrencyData = cryptoCurrencyData, tokenActionsHandler = tokenActionsHandler, @@ -85,8 +88,9 @@ internal class TokenActionsUiBuilder @Inject constructor( tokenActionsHandler = tokenActionsHandler, isRedesignEnabled = false, ), - onLaterClick = { - params.callbacks.onLaterClick() + bottomActionText = bottomActionText(params.bottomAction), + onBottomActionClick = { + params.callbacks.onBottomActionClick() }, ) } @@ -115,14 +119,22 @@ internal class TokenActionsUiBuilder @Inject constructor( tokenActionsHandler = tokenActionsHandler, isRedesignEnabled = true, ), - onLaterClick = { - params.callbacks.onLaterClick() + bottomActionText = bottomActionText(params.bottomAction), + onBottomActionClick = { + params.callbacks.onBottomActionClick() }, isBalancesHidden = isBalanceHidden, portfolioBadge = createPortfolioBadge(cryptoCurrencyData = cryptoCurrencyData), ) } + private fun bottomActionText(action: TokenActionsComponent.BottomAction): TextReference { + return when (action) { + TokenActionsComponent.BottomAction.Later -> resourceReference(R.string.common_later) + TokenActionsComponent.BottomAction.GoToToken -> resourceReference(R.string.common_go_to_token) + } + } + private fun createPortfolioBadge(cryptoCurrencyData: CryptoCurrencyData): PortfolioBadgeUM { return if (cryptoCurrencyData.isAccountMode) { val icon = CryptoPortfolioIconConverter.convert(cryptoCurrencyData.account.account.icon) diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/ui/TokenActionsContent.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/ui/TokenActionsContent.kt index 1b7f686fb7..d8bb296eb7 100644 --- a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/ui/TokenActionsContent.kt +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/ui/TokenActionsContent.kt @@ -33,7 +33,6 @@ import com.tangem.core.ui.components.token.TokenItem import com.tangem.core.ui.components.token.state.TokenItemState import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference -import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.res.LocalHapticManager import com.tangem.core.ui.res.TangemColorPalette @@ -78,8 +77,8 @@ internal fun TokenActionsContent(state: TokenActionsUM, modifier: Modifier = Mod SecondaryButton( modifier = Modifier.fillMaxWidth(), - text = stringResourceSafe(R.string.common_later), - onClick = state.onLaterClick, + text = state.bottomActionText.resolveReference(), + onClick = state.onBottomActionClick, ) } } @@ -198,7 +197,8 @@ private class TokenActionsContentPreviewProvider : PreviewParameterProvider Unit, + val bottomActionText: TextReference, + val onBottomActionClick: () -> Unit, val isBalancesHidden: Boolean = false, val portfolioBadge: PortfolioBadgeUM = PortfolioBadgeUM.None, ) diff --git a/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/featuretoggles/WalletFeatureToggles.kt b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/featuretoggles/WalletFeatureToggles.kt index f4d741b7fe..7c72192ae5 100644 --- a/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/featuretoggles/WalletFeatureToggles.kt +++ b/features/wallet/api/src/main/kotlin/com/tangem/features/wallet/featuretoggles/WalletFeatureToggles.kt @@ -8,4 +8,6 @@ package com.tangem.features.wallet.featuretoggles interface WalletFeatureToggles { val isAddAndManageTokensEnabled: Boolean + + val isAddFundsStage1Enabled: Boolean } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 7ee1dd5b1d..f85b700a44 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -63,6 +63,7 @@ import com.tangem.features.biometry.AskBiometryComponent import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener +import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import com.tangem.utils.logging.TangemLogger @@ -120,6 +121,7 @@ internal class WalletModel @Inject constructor( private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher, private val uiMessageSender: UiMessageSender, private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val walletFeatureToggles: WalletFeatureToggles, private val startAssetsDiscoveryUseCase: StartAssetsDiscoveryUseCase, val screenLifecycleProvider: ScreenLifecycleProvider, val innerWalletRouter: InnerWalletRouter, @@ -544,6 +546,7 @@ internal class WalletModel @Inject constructor( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled, ), ) @@ -590,6 +593,7 @@ internal class WalletModel @Inject constructor( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled, ), ) } @@ -611,6 +615,7 @@ internal class WalletModel @Inject constructor( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled, ), ) } @@ -625,6 +630,7 @@ internal class WalletModel @Inject constructor( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled, ), ) @@ -686,6 +692,7 @@ internal class WalletModel @Inject constructor( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt index 47c3f6be8a..d47bd1d8d8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletClickIntents.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.child.wallet.model.intents import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.ui.DesignFeatureToggles import com.tangem.domain.exchange.RampStateManager +import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.onramp.FetchHotCryptoUseCase import com.tangem.domain.settings.NeverToShowWalletsScrollPreview @@ -114,6 +115,10 @@ internal class WalletClickIntents @Inject constructor( refreshSingleCurrencyContent(showRefreshState = true) } + fun onAddFundsClick(userWalletId: UserWalletId) { + router.openAddFunds(userWalletId) + } + private fun refreshMultiCurrencyContent(showRefreshState: Boolean) { val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/featuretoggles/DefaultWalletFeatureToggles.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/featuretoggles/DefaultWalletFeatureToggles.kt index a15503fa38..1695e2fe76 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/featuretoggles/DefaultWalletFeatureToggles.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/featuretoggles/DefaultWalletFeatureToggles.kt @@ -11,4 +11,7 @@ internal class DefaultWalletFeatureToggles @Inject constructor( override val isAddAndManageTokensEnabled: Boolean get() = featureToggles.isFeatureEnabled(FeatureToggles.ADD_AND_MANAGE_TOKENS_ENABLED) + + override val isAddFundsStage1Enabled: Boolean + get() = featureToggles.isFeatureEnabled(FeatureToggles.AND_15310_ADD_FUNDS_STAGE1) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 13ebe72dd2..ab1ae71b4a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -119,6 +119,10 @@ internal class DefaultWalletRouter @Inject constructor( router.push(AppRoute.Home()) } + override fun openAddFunds(userWalletId: UserWalletId) { + router.push(AppRoute.AddFunds(userWalletId = userWalletId)) + } + override fun isWalletLastScreen(): Boolean { return router.stack.lastOrNull() is AppRoute.Wallet } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt index 60dc1d47ef..456ee387ec 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt @@ -117,4 +117,7 @@ internal interface InnerWalletRouter { /** Open network selection bottom sheet for multiple QR matches */ fun openNetworkSelectionBottomSheet(target: QrSendTarget.Multiple) + + /** Open Add Funds screen */ + fun openAddFunds(userWalletId: UserWalletId) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletManageButton.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletManageButton.kt index f956593a15..f2ab77907e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletManageButton.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletManageButton.kt @@ -51,6 +51,20 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) { ), ) + data class AddFunds( + override val enabled: Boolean, + override val dimContent: Boolean, + override val onClick: () -> Unit, + ) : WalletManageButton( + config = ActionButtonConfig( + text = TextReference.Res(id = R.string.common_add_funds), + iconResId = R.drawable.ic_plus_24, + onClick = onClick, + isEnabled = enabled, + shouldDimContent = dimContent, + ), + ) + /** * Send * diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt index ec3d6943be..f41f1471ae 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/AddWalletTransformer.kt @@ -13,6 +13,7 @@ internal class AddWalletTransformer( private val clickIntents: WalletClickIntents, private val walletImageResolver: WalletImageResolver, private val getWalletIconUseCase: GetWalletIconUseCase, + private val isAddFundsStage1Enabled: Boolean, ) : WalletScreenStateTransformer { private val walletLoadingStateFactory by lazy { @@ -20,6 +21,7 @@ internal class AddWalletTransformer( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = isAddFundsStage1Enabled, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt index a9774d2e2d..8726a0a42f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/InitializeWalletsTransformer.kt @@ -27,6 +27,7 @@ internal class InitializeWalletsTransformer( private val clickIntents: WalletClickIntents, private val walletImageResolver: WalletImageResolver, private val getWalletIconUseCase: GetWalletIconUseCase, + private val isAddFundsStage1Enabled: Boolean, ) : WalletScreenStateTransformer { private val walletLoadingStateFactory by lazy { @@ -34,6 +35,7 @@ internal class InitializeWalletsTransformer( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = isAddFundsStage1Enabled, ) } @@ -147,8 +149,18 @@ internal class InitializeWalletsTransformer( userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken() if (isSingleWalletWithToken) return persistentListOf() + val firstButton = if (isAddFundsStage1Enabled) { + WalletManageButton.AddFunds( + enabled = false, + dimContent = false, + onClick = {}, + ) + } else { + WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {}) + } + return persistentListOf( - WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {}), + firstButton, WalletManageButton.Swap(enabled = false, dimContent = false, onClick = {}), WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {}), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeNewWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeNewWalletTransformer.kt index 0c1b198d0c..2a7f70ad83 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeNewWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeNewWalletTransformer.kt @@ -24,6 +24,7 @@ internal class ReinitializeNewWalletTransformer( private val clickIntents: WalletClickIntents, private val walletImageResolver: WalletImageResolver, private val getWalletIconUseCase: GetWalletIconUseCase, + private val isAddFundsStage1Enabled: Boolean, ) : WalletScreenStateTransformer { private val walletLoadingStateFactory by lazy { @@ -31,6 +32,7 @@ internal class ReinitializeNewWalletTransformer( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = isAddFundsStage1Enabled, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt index 6dab085776..1729b92b47 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt @@ -20,6 +20,7 @@ internal class ReinitializeWalletTransformer( private val clickIntents: WalletClickIntents, private val walletImageResolver: WalletImageResolver, private val getWalletIconUseCase: GetWalletIconUseCase, + private val isAddFundsStage1Enabled: Boolean, ) : WalletStateTransformer(userWalletId = userWallet.walletId) { private val walletLoadingStateFactory by lazy { @@ -27,6 +28,7 @@ internal class ReinitializeWalletTransformer( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = isAddFundsStage1Enabled, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt index 15ef1cb2e8..cbe63f3861 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetRefreshStateTransformer.kt @@ -72,10 +72,11 @@ internal class SetRefreshStateTransformer( private fun PersistentList.toUpdatedState(): PersistentList { val isButtonsEnabled = !isRefreshing - return mutate { - it.mapNotNull { button -> + return mutate { items -> + items.mapNotNull { button -> when (button) { is WalletManageButton.Buy -> button.copy(enabled = isButtonsEnabled) + is WalletManageButton.AddFunds -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled) is WalletManageButton.Receive -> button diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt index d80feaec8e..f74ded9240 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/UnlockWalletTransformer.kt @@ -18,6 +18,7 @@ internal class UnlockWalletTransformer( private val clickIntents: WalletClickIntents, private val walletImageResolver: WalletImageResolver, private val getWalletIconUseCase: GetWalletIconUseCase, + private val isAddFundsStage1Enabled: Boolean, ) : WalletScreenStateTransformer { private val walletLoadingStateFactory by lazy { @@ -25,6 +26,7 @@ internal class UnlockWalletTransformer( clickIntents = clickIntents, walletImageResolver = walletImageResolver, getWalletIconUseCase = getWalletIconUseCase, + isAddFundsStage1Enabled = isAddFundsStage1Enabled, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/MultiWalletActionsExt.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/MultiWalletActionsExt.kt index 56fd1ba0f3..095f5d5654 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/MultiWalletActionsExt.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/MultiWalletActionsExt.kt @@ -43,6 +43,7 @@ private fun WalletState.MultiCurrency.Content.changeAvailability(enabled: Boolea .map { action -> when (action) { is WalletManageButton.Buy -> action.copy(enabled = enabled) + is WalletManageButton.AddFunds -> action.copy(enabled = enabled) is WalletManageButton.Sell -> action.copy(enabled = enabled) is WalletManageButton.Swap -> action.copy(enabled = enabled) else -> action diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt index 1140b80dd0..de41aea15f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt @@ -34,6 +34,7 @@ internal class WalletLoadingStateFactory( private val clickIntents: WalletClickIntents, private val walletImageResolver: WalletImageResolver, private val getWalletIconUseCase: GetWalletIconUseCase, + private val isAddFundsStage1Enabled: Boolean, ) { fun create(userWallet: UserWallet): WalletState { @@ -149,7 +150,13 @@ internal class WalletLoadingStateFactory( userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken() if (isSingleWalletWithToken) return persistentListOf() - return persistentListOf( + val firstButton = if (isAddFundsStage1Enabled) { + WalletManageButton.AddFunds( + enabled = true, + dimContent = false, + onClick = { clickIntents.onAddFundsClick(userWallet.walletId) }, + ) + } else { WalletManageButton.Buy( enabled = true, dimContent = false, @@ -159,7 +166,11 @@ internal class WalletLoadingStateFactory( WALLET_TYPE, ) }, - ), + ) + } + + return persistentListOf( + firstButton, WalletManageButton.Swap( enabled = true, dimContent = false,