Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-01 12:05:57 +05:00
parent 459672ba51
commit 1166f7e8bf
5 changed files with 162 additions and 31 deletions

View file

@ -15,6 +15,7 @@ import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.decompose.ComposableDialogComponent
import com.tangem.domain.tokens.model.details.TokenAction
import com.tangem.feature.wallet.child.wallet.model.WalletModel
import com.tangem.feature.wallet.navigation.WalletRoute
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
@ -25,6 +26,7 @@ import com.tangem.features.markets.entry.MarketsEntryComponent
import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent
import com.tangem.features.pushnotifications.api.PushNotificationsParams
import com.tangem.features.tokenreceive.TokenReceiveComponent
import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -39,6 +41,7 @@ internal class WalletComponent @AssistedInject constructor(
private val askBiometryComponentFactory: AskBiometryComponent.Factory,
private val pushNotificationsBottomSheetComponent: PushNotificationsBottomSheetComponent.Factory,
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
private val yieldSupplyDepositedWarningComponent: YieldSupplyDepositedWarningComponent.Factory,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
private val model: WalletModel = getOrCreateModel()
@ -90,6 +93,21 @@ internal class WalletComponent @AssistedInject constructor(
),
)
}
is WalletDialogConfig.YieldSupplyWarning -> {
yieldSupplyDepositedWarningComponent.create(
context = childByContext(componentContext),
params = YieldSupplyDepositedWarningComponent.Params(
cryptoCurrency = dialogConfig.cryptoCurrency,
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
tokenAction = dialogConfig.tokenAction,
modelCallback = object : YieldSupplyDepositedWarningComponent.ModelCallback {
override fun onYieldSupplyWarningAcknowledged(tokenAction: TokenAction) {
dialogConfig.onWarningAcknowledged(tokenAction)
}
},
),
)
}
}
},
)

View file

@ -45,6 +45,10 @@ import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
import com.tangem.domain.tokens.NeedShowYieldSupplyDepositedWarningUseCase
import com.tangem.domain.tokens.SaveViewedTokenReceiveWarningUseCase
import com.tangem.domain.tokens.SaveViewedYieldSupplyWarningUseCase
import com.tangem.domain.tokens.model.details.TokenAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
@ -68,6 +72,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBot
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
import com.tangem.feature.wallet.presentation.wallet.utils.WalletFeatureUseCasesFacade
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
@ -148,7 +153,11 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val rampStateManager: RampStateManager,
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
private val saveViewedTokenReceiveWarningUseCase: SaveViewedTokenReceiveWarningUseCase,
private val getEnsNameUseCase: GetEnsNameUseCase,
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
private val needShowYieldSupplyDepositedWarningUseCase: NeedShowYieldSupplyDepositedWarningUseCase,
private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase,
) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents {
override fun onSendClick(
@ -166,13 +175,24 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
if (handleUnavailabilityReason(unavailabilityReason)) return
stateHolder.update(CloseBottomSheetTransformer(userWalletId = portfolioId.userWalletId))
val route = AppRoute.Send(
currency = cryptoCurrencyStatus.currency,
portfolioId = portfolioId,
)
appRouter.push(route)
modelScope.launch(dispatchers.main) {
if (needShowYieldSupplyWarning(cryptoCurrencyStatus)) {
stateHolder.hideBottomSheet()
router.openYieldSupplyBottomSheet(
cryptoCurrency = cryptoCurrencyStatus.currency,
tokenAction = TokenAction.Send,
onWarningAcknowledged = { tokenAction ->
modelScope.launch {
saveViewedYieldSupplyWarningUseCase(cryptoCurrencyStatus.currency.name)
stateHolder.hideBottomSheet()
navigateToSend(cryptoCurrencyStatus, portfolioId)
}
},
)
} else {
navigateToSend(cryptoCurrencyStatus, portfolioId)
}
}
}
override fun onReceiveClick(
@ -196,24 +216,24 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
event?.let { analyticsEventHandler.send(it) }
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
stateHolder.hideBottomSheet()
modelScope.launch {
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)?.let {
router.openTokenReceiveBottomSheet(it)
}
modelScope.launch(dispatchers.main) {
if (needShowYieldSupplyWarning(cryptoCurrencyStatus)) {
stateHolder.hideBottomSheet()
router.openYieldSupplyBottomSheet(
cryptoCurrency = cryptoCurrencyStatus.currency,
tokenAction = TokenAction.Receive,
onWarningAcknowledged = { tokenAction ->
modelScope.launch {
saveViewedTokenReceiveWarningUseCase(cryptoCurrencyStatus.currency.name)
saveViewedYieldSupplyWarningUseCase(cryptoCurrencyStatus.currency.name)
stateHolder.hideBottomSheet()
navigateToReceive(cryptoCurrencyStatus)
}
},
)
} else {
navigateToReceive(cryptoCurrencyStatus)
}
} else {
analyticsEventHandler.send(
event = TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrencyStatus.currency.symbol),
)
stateHolder.showBottomSheet(
createReceiveBottomSheetContent(
currency = cryptoCurrencyStatus.currency,
addresses = cryptoCurrencyStatus.value.networkAddress ?: return,
),
userWalletId,
)
}
}
@ -417,13 +437,24 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
if (handleUnavailabilityReason(unavailabilityReason)) return
appRouter.push(
AppRoute.Swap(
currencyFrom = cryptoCurrencyStatus.currency,
portfolioId = portfolioId,
screenSource = AnalyticsParam.ScreensSources.LongTap.value,
),
)
modelScope.launch(dispatchers.main) {
if (needShowYieldSupplyWarning(cryptoCurrencyStatus)) {
stateHolder.hideBottomSheet()
router.openYieldSupplyBottomSheet(
cryptoCurrency = cryptoCurrencyStatus.currency,
tokenAction = TokenAction.Swap,
onWarningAcknowledged = { tokenAction ->
modelScope.launch {
saveViewedYieldSupplyWarningUseCase(cryptoCurrencyStatus.currency.name)
stateHolder.hideBottomSheet()
navigateToSwap(cryptoCurrencyStatus, portfolioId)
}
},
)
} else {
navigateToSwap(cryptoCurrencyStatus, portfolioId)
}
}
}
override fun onExploreClick() {
@ -729,4 +760,52 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
receiveAddress = receiveAddresses,
)
}
private suspend fun needShowYieldSupplyWarning(cryptoCurrencyStatus: CryptoCurrencyStatus): Boolean {
return yieldSupplyFeatureToggles.isYieldSupplyFeatureEnabled &&
needShowYieldSupplyDepositedWarningUseCase(cryptoCurrencyStatus)
}
private fun navigateToSend(cryptoCurrencyStatus: CryptoCurrencyStatus, portfolioId: PortfolioId) {
stateHolder.update(CloseBottomSheetTransformer(userWalletId = portfolioId.userWalletId))
val route = AppRoute.Send(
currency = cryptoCurrencyStatus.currency,
portfolioId = portfolioId,
)
appRouter.push(route)
}
private fun navigateToSwap(cryptoCurrencyStatus: CryptoCurrencyStatus, portfolioId: PortfolioId) {
appRouter.push(
AppRoute.Swap(
currencyFrom = cryptoCurrencyStatus.currency,
portfolioId = portfolioId,
screenSource = AnalyticsParam.ScreensSources.LongTap.value,
),
)
}
private fun navigateToReceive(cryptoCurrencyStatus: CryptoCurrencyStatus) {
val userWalletId = stateHolder.getSelectedWalletId()
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
stateHolder.hideBottomSheet()
modelScope.launch {
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)?.let {
router.openTokenReceiveBottomSheet(it)
}
}
} else {
analyticsEventHandler.send(
event = TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrencyStatus.currency.symbol),
)
stateHolder.showBottomSheet(
createReceiveBottomSheetContent(
currency = cryptoCurrencyStatus.currency,
addresses = cryptoCurrencyStatus.value.networkAddress ?: return,
),
userWalletId,
)
}
}
}

View file

@ -9,12 +9,14 @@ import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.redux.StateDialog
import com.tangem.domain.tokens.model.details.TokenAction
import com.tangem.feature.wallet.navigation.WalletRoute
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
import kotlinx.coroutines.channels.BufferOverflow
@ -115,4 +117,18 @@ internal class DefaultWalletRouter @Inject constructor(
override fun openTangemPayDetails(custoemrWalletAddress: String) {
router.push(AppRoute.TangemPayDetails(custoemrWalletAddress))
}
override fun openYieldSupplyBottomSheet(
cryptoCurrency: CryptoCurrency,
tokenAction: TokenAction,
onWarningAcknowledged: (TokenAction) -> Unit,
) {
dialogNavigation.activate(
configuration = WalletDialogConfig.YieldSupplyWarning(
cryptoCurrency = cryptoCurrency,
tokenAction = tokenAction,
onWarningAcknowledged = onWarningAcknowledged,
),
)
}
}

View file

@ -4,10 +4,12 @@ import androidx.compose.runtime.Stable
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.model.details.TokenAction
import com.tangem.feature.wallet.navigation.WalletRoute
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
import kotlinx.coroutines.flow.SharedFlow
@ -62,4 +64,11 @@ internal interface InnerWalletRouter {
fun openTangemPayOnboarding()
fun openTangemPayDetails(custoemrWalletAddress: String)
/** Open BS abput yield supply active and all money deposited in AAVE */
fun openYieldSupplyBottomSheet(
cryptoCurrency: CryptoCurrency,
tokenAction: TokenAction,
onWarningAcknowledged: (TokenAction) -> Unit,
)
}

View file

@ -1,7 +1,9 @@
package com.tangem.feature.wallet.presentation.wallet.state.model
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.model.details.TokenAction
import kotlinx.serialization.Serializable
/**
@ -23,4 +25,11 @@ internal sealed interface WalletDialogConfig {
@Serializable
data class TokenReceive(val tokenReceiveConfig: TokenReceiveConfig) : WalletDialogConfig
@Serializable
data class YieldSupplyWarning(
val cryptoCurrency: CryptoCurrency,
val tokenAction: TokenAction,
val onWarningAcknowledged: (TokenAction) -> Unit,
) : WalletDialogConfig
}