Updated on 2026-08-14

This commit is contained in:
Tangem 2025-02-10 11:08:23 +05:00
parent 0cbf7b74e2
commit 8565d74638
10 changed files with 127 additions and 5 deletions

View file

@ -105,6 +105,7 @@ dependencies {
implementation(projects.features.markets.api)
implementation(projects.features.onramp.api)
implementation(projects.features.onboardingV2.api)
implementation(projects.features.swap.api)
/** Common modules */
implementation(projects.common)

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
@ -12,10 +13,12 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionButtonsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletTokenListSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.swap.SwapFeatureToggles
@Suppress("LongParameterList")
internal class MultiWalletContentLoader(
@ -31,6 +34,8 @@ internal class MultiWalletContentLoader(
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase,
private val swapFeatureToggles: SwapFeatureToggles,
private val deepLinksRegistry: DeepLinksRegistry,
) : WalletContentLoader(id = userWallet.walletId) {
@ -56,6 +61,12 @@ internal class MultiWalletContentLoader(
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
),
MultiWalletActionButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase,
swapFeatureToggles = swapFeatureToggles,
),
)
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
@ -13,6 +14,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenList
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.swap.SwapFeatureToggles
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@ -29,6 +31,8 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase,
private val swapFeatureToggles: SwapFeatureToggles,
private val deepLinksRegistry: DeepLinksRegistry,
) {
@ -46,6 +50,8 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase,
swapFeatureToggles = swapFeatureToggles,
deepLinksRegistry = deepLinksRegistry,
)
}

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
@ -11,10 +12,12 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionButtonsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenListSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.swap.SwapFeatureToggles
@Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoader(
@ -29,6 +32,8 @@ internal class SingleWalletWithTokenContentLoader(
private val tokenListStore: MultiWalletTokenListStore,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase,
private val swapFeatureToggles: SwapFeatureToggles,
private val deepLinksRegistry: DeepLinksRegistry,
) : WalletContentLoader(id = userWallet.walletId) {
@ -53,6 +58,12 @@ internal class SingleWalletWithTokenContentLoader(
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
),
MultiWalletActionButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase,
swapFeatureToggles = swapFeatureToggles,
),
)
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
@ -12,6 +13,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenList
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.swap.SwapFeatureToggles
import javax.inject.Inject
// TODO: Refactor
@ -26,6 +28,8 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase,
private val swapFeatureToggles: SwapFeatureToggles,
private val deepLinksRegistry: DeepLinksRegistry,
) {
@ -42,6 +46,8 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase,
swapFeatureToggles = swapFeatureToggles,
deepLinksRegistry = deepLinksRegistry,
)
}

View file

@ -143,6 +143,7 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
override val dimContent: Boolean,
override val onClick: () -> Unit,
val isInProgress: Boolean = false,
val showBadge: Boolean = false,
) : WalletManageButton(
config = ActionButtonConfig(
text = TextReference.Res(id = R.string.swapping_swap_action),
@ -151,6 +152,7 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
enabled = enabled,
dimContent = dimContent,
isInProgress = isInProgress,
showBadge = showBadge,
),
)
}

View file

@ -0,0 +1,19 @@
package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.utils.showSwapBadge
internal class UpdateMultiWalletActionButtonBadgeTransformer(
private val showSwapBadge: Boolean,
userWalletId: UserWalletId,
) : WalletStateTransformer(userWalletId) {
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.MultiCurrency.Content -> {
prevState.copy(buttons = prevState.showSwapBadge(showBadge = showSwapBadge))
}
else -> prevState
}
}
}

View file

@ -24,4 +24,15 @@ private fun WalletState.MultiCurrency.Content.changeAvailability(enabled: Boolea
}
}
.toPersistentList()
}
internal fun WalletState.MultiCurrency.Content.showSwapBadge(showBadge: Boolean): PersistentList<WalletManageButton> {
return buttons
.map { action ->
when (action) {
is WalletManageButton.Swap -> action.copy(showBadge = showBadge)
else -> action
}
}
.toPersistentList()
}

View file

@ -0,0 +1,30 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.UpdateMultiWalletActionButtonBadgeTransformer
import com.tangem.features.swap.SwapFeatureToggles
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
internal class MultiWalletActionButtonsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase,
private val swapFeatureToggles: SwapFeatureToggles,
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> = shouldShowSwapStoriesUseCase()
.distinctUntilChanged()
.map { showSwapBadge ->
val showBadge = swapFeatureToggles.isPromoStoriesEnabled && showSwapBadge
stateHolder.update(
UpdateMultiWalletActionButtonBadgeTransformer(
userWalletId = userWallet.walletId,
showSwapBadge = showBadge,
),
)
}
}

View file

@ -28,6 +28,8 @@ import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.domain.onramp.model.OnrampSource
import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
@ -51,6 +53,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensLis
import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
import com.tangem.features.onramp.OnrampFeatureToggles
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.collections.immutable.toImmutableList
@ -110,6 +113,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val removeCurrencyUseCase: RemoveCurrencyUseCase,
private val getExploreUrlUseCase: GetExploreUrlUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val dispatchers: CoroutineDispatcherProvider,
private val reduxStateHolder: ReduxStateHolder,
@ -119,6 +123,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val appRouter: AppRouter,
private val rampStateManager: RampStateManager,
private val onrampFeatureToggles: OnrampFeatureToggles,
private val swapFeatureToggles: SwapFeatureToggles,
) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents {
override fun onSendClick(
@ -430,11 +435,16 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
return
}
onMultiWalletActionClick(
statusFlow = rampStateManager.getExpressInitializationStatus(userWalletId),
route = AppRoute.SwapCrypto(userWalletId = userWalletId),
eventCreator = MainScreenAnalyticsEvent::ButtonSwap,
)
viewModelScope.launch {
val swapRoute = getSwapRoute(
AppRoute.SwapCrypto(userWalletId = userWalletId),
)
onMultiWalletActionClick(
statusFlow = rampStateManager.getExpressInitializationStatus(userWalletId),
route = swapRoute,
eventCreator = MainScreenAnalyticsEvent::ButtonSwap,
)
}
}
override fun onMultiWalletBuyClick(userWalletId: UserWalletId) {
@ -597,4 +607,19 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
event = WalletEvent.ShowAlert(state = WalletAlertState.ProvidersStillLoading),
)
}
private suspend fun getSwapRoute(targetRoute: AppRoute): AppRoute {
val isSwapStoriesEnabled = swapFeatureToggles.isPromoStoriesEnabled
val shouldShowSwapStories = shouldShowSwapStoriesUseCase.invokeSync()
val showSwapStories = shouldShowSwapStories && isSwapStoriesEnabled
return if (showSwapStories) {
AppRoute.Stories(
storyId = StoryContentIds.STORY_FIRST_TIME_SWAP.id,
nextScreen = targetRoute,
)
} else {
targetRoute
}
}
}