Updated on 2026-08-14
This commit is contained in:
parent
4d75db3cdd
commit
22dc2eb3e9
57 changed files with 931 additions and 258 deletions
|
|
@ -628,6 +628,7 @@ internal class ChildFactory @Inject constructor(
|
||||||
params = SendEntryPointComponent.Params(
|
params = SendEntryPointComponent.Params(
|
||||||
userWalletId = route.userWalletId,
|
userWalletId = route.userWalletId,
|
||||||
cryptoCurrency = route.currency,
|
cryptoCurrency = route.currency,
|
||||||
|
shouldStartWithSwap = route.shouldStartWithSwap,
|
||||||
),
|
),
|
||||||
componentFactory = sendEntryPointComponentFactory,
|
componentFactory = sendEntryPointComponentFactory,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,7 @@ sealed class AppRoute(val path: String) : Route {
|
||||||
data class SendEntryPoint(
|
data class SendEntryPoint(
|
||||||
val userWalletId: UserWalletId,
|
val userWalletId: UserWalletId,
|
||||||
val currency: CryptoCurrency,
|
val currency: CryptoCurrency,
|
||||||
|
val shouldStartWithSwap: Boolean = false,
|
||||||
) : AppRoute(
|
) : AppRoute(
|
||||||
path = "/send_entry_point/${userWalletId.stringValue}/${currency.id.value}?",
|
path = "/send_entry_point/${userWalletId.stringValue}/${currency.id.value}?",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -44,4 +44,8 @@ dependencies {
|
||||||
/** DI */
|
/** DI */
|
||||||
implementation(deps.hilt.android)
|
implementation(deps.hilt.android)
|
||||||
kapt(deps.hilt.kapt)
|
kapt(deps.hilt.kapt)
|
||||||
|
|
||||||
|
/** Test */
|
||||||
|
testImplementation(projects.test.core)
|
||||||
|
testImplementation(projects.common.test)
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +60,24 @@ sealed class QuickActionUM(
|
||||||
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
||||||
icon = R.drawable.ic_analytics_up_mini_24,
|
icon = R.drawable.ic_analytics_up_mini_24,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data object Send : V1(
|
||||||
|
title = resourceReference(R.string.common_send),
|
||||||
|
description = resourceReference(R.string.quick_action_send_description),
|
||||||
|
icon = R.drawable.ic_arrow_up_24,
|
||||||
|
)
|
||||||
|
|
||||||
|
data object Sell : V1(
|
||||||
|
title = resourceReference(R.string.common_sell),
|
||||||
|
description = resourceReference(R.string.quick_action_sell_description),
|
||||||
|
icon = R.drawable.ic_currency_24,
|
||||||
|
)
|
||||||
|
|
||||||
|
data object SwapAndSend : V1(
|
||||||
|
title = resourceReference(R.string.common_send_with_swap),
|
||||||
|
description = resourceReference(R.string.quick_action_send_and_swap_description),
|
||||||
|
icon = R.drawable.ic_exchange_mini_24,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class V2(
|
sealed class V2(
|
||||||
|
|
@ -107,5 +125,23 @@ sealed class QuickActionUM(
|
||||||
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
||||||
icon = R.drawable.ic_analytics_up_mini_24,
|
icon = R.drawable.ic_analytics_up_mini_24,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data object Send : V2(
|
||||||
|
title = resourceReference(R.string.common_send),
|
||||||
|
description = resourceReference(R.string.quick_action_send_description),
|
||||||
|
icon = R.drawable.ic_arrow_up_24,
|
||||||
|
)
|
||||||
|
|
||||||
|
data object Sell : V2(
|
||||||
|
title = resourceReference(R.string.common_sell),
|
||||||
|
description = resourceReference(R.string.quick_action_sell_description),
|
||||||
|
icon = R.drawable.ic_currency_24,
|
||||||
|
)
|
||||||
|
|
||||||
|
data object SwapAndSend : V2(
|
||||||
|
title = resourceReference(R.string.common_send_with_swap),
|
||||||
|
description = resourceReference(R.string.quick_action_send_and_swap_description),
|
||||||
|
icon = R.drawable.ic_exchange_mini_24,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,52 +11,16 @@ object QuickActionsConverter {
|
||||||
cryptoData: CryptoCurrencyData,
|
cryptoData: CryptoCurrencyData,
|
||||||
tokenActionsHandler: TokenActionsHandler,
|
tokenActionsHandler: TokenActionsHandler,
|
||||||
isRedesignEnabled: Boolean,
|
isRedesignEnabled: Boolean,
|
||||||
|
context: TokenActionsContext = TokenActionsContext.Markets,
|
||||||
): QuickActions {
|
): QuickActions {
|
||||||
return QuickActions(
|
return QuickActions(
|
||||||
actions = toQuickActions(cryptoData.actions, isRedesignEnabled),
|
actions = toQuickActions(cryptoData.actions, isRedesignEnabled, context),
|
||||||
onQuickActionClick = { quickActionUM ->
|
onQuickActionClick = { quickActionUM ->
|
||||||
when (quickActionUM) {
|
tokenActionsHandler.handle(
|
||||||
QuickActionUM.V1.Buy -> tokenActionsHandler.handle(
|
action = quickActionUM.toHandledAction(),
|
||||||
action = TokenActionsBSContentUM.Action.Buy,
|
cryptoCurrencyData = cryptoData,
|
||||||
cryptoCurrencyData = cryptoData,
|
context = context,
|
||||||
)
|
)
|
||||||
is QuickActionUM.V1.Exchange -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Exchange,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
QuickActionUM.V1.Receive -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Receive,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
QuickActionUM.V1.Stake -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Stake,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
is QuickActionUM.V1.YieldMode -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.YieldMode,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
QuickActionUM.V2.Buy -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Buy,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
is QuickActionUM.V2.Exchange -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Exchange,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
QuickActionUM.V2.Receive -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Receive,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
QuickActionUM.V2.Stake -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.Stake,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
is QuickActionUM.V2.YieldMode -> tokenActionsHandler.handle(
|
|
||||||
action = TokenActionsBSContentUM.Action.YieldMode,
|
|
||||||
cryptoCurrencyData = cryptoData,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onQuickActionLongClick = { actionUM ->
|
onQuickActionLongClick = { actionUM ->
|
||||||
if (actionUM == QuickActionUM.V1.Receive || actionUM == QuickActionUM.V2.Receive) {
|
if (actionUM == QuickActionUM.V1.Receive || actionUM == QuickActionUM.V2.Receive) {
|
||||||
|
|
@ -69,44 +33,78 @@ object QuickActionsConverter {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toQuickActions(actions: List<TokenActionsState.ActionState>, isRedesignEnabled: Boolean) =
|
private fun QuickActionUM.toHandledAction(): TokenActionsBSContentUM.Action = when (this) {
|
||||||
if (isRedesignEnabled) {
|
QuickActionUM.V1.Buy, QuickActionUM.V2.Buy -> TokenActionsBSContentUM.Action.Buy
|
||||||
redesignedQuickActions(actions)
|
is QuickActionUM.V1.Exchange, is QuickActionUM.V2.Exchange -> TokenActionsBSContentUM.Action.Exchange
|
||||||
} else {
|
QuickActionUM.V1.Receive, QuickActionUM.V2.Receive -> TokenActionsBSContentUM.Action.Receive
|
||||||
legacyQuickActions(actions)
|
QuickActionUM.V1.Stake, QuickActionUM.V2.Stake -> TokenActionsBSContentUM.Action.Stake
|
||||||
}
|
is QuickActionUM.V1.YieldMode, is QuickActionUM.V2.YieldMode -> TokenActionsBSContentUM.Action.YieldMode
|
||||||
|
QuickActionUM.V1.Send, QuickActionUM.V2.Send -> TokenActionsBSContentUM.Action.Send
|
||||||
|
QuickActionUM.V1.Sell, QuickActionUM.V2.Sell -> TokenActionsBSContentUM.Action.Sell
|
||||||
|
QuickActionUM.V1.SwapAndSend, QuickActionUM.V2.SwapAndSend -> TokenActionsBSContentUM.Action.SendWithSwap
|
||||||
|
}
|
||||||
|
|
||||||
private fun redesignedQuickActions(actions: List<TokenActionsState.ActionState>): ImmutableList<QuickActionUM> {
|
/**
|
||||||
return buildList {
|
* Returns available actions filtered to [context]'s allow-list and ordered by it.
|
||||||
actions.forEach { action ->
|
* Omitting [context] (default [TokenActionsContext.Markets]) yields all available actions in source order;
|
||||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
* a context with a non-null [TokenActionsContext.allowedActionsInOrder] filters to and orders by that list.
|
||||||
when (action) {
|
*/
|
||||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.V2.Buy
|
fun toQuickActions(
|
||||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.V2.Exchange(action.shouldShowBadge)
|
actions: List<TokenActionsState.ActionState>,
|
||||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.V2.Receive
|
isRedesignEnabled: Boolean,
|
||||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.V2.Stake
|
context: TokenActionsContext = TokenActionsContext.Markets,
|
||||||
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.V2.YieldMode(action.apy)
|
): ImmutableList<QuickActionUM> {
|
||||||
else -> null
|
val available = actions.filter { it.unavailabilityReason == ScenarioUnavailabilityReason.None }
|
||||||
}?.let(::add)
|
val allowed = context.allowedActionsInOrder
|
||||||
}
|
?: return available.mapNotNull { it.toQuickActionUM(isRedesignEnabled) }.toImmutableList()
|
||||||
|
|
||||||
|
val byBsAction = available.associateBy { it.toBsAction() }
|
||||||
|
val hasExchange = byBsAction.containsKey(TokenActionsBSContentUM.Action.Exchange)
|
||||||
|
return allowed.mapNotNull { action ->
|
||||||
|
when (action) {
|
||||||
|
TokenActionsBSContentUM.Action.SendWithSwap ->
|
||||||
|
if (hasExchange) swapAndSendUM(isRedesignEnabled) else null
|
||||||
|
else -> byBsAction[action]?.toQuickActionUM(isRedesignEnabled)
|
||||||
}
|
}
|
||||||
}.toImmutableList()
|
}.toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun legacyQuickActions(actions: List<TokenActionsState.ActionState>): ImmutableList<QuickActionUM> {
|
private fun swapAndSendUM(isRedesignEnabled: Boolean): QuickActionUM =
|
||||||
return buildList {
|
if (isRedesignEnabled) QuickActionUM.V2.SwapAndSend else QuickActionUM.V1.SwapAndSend
|
||||||
actions.forEach { action ->
|
|
||||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
private fun TokenActionsState.ActionState.toQuickActionUM(isRedesignEnabled: Boolean): QuickActionUM? =
|
||||||
when (action) {
|
if (isRedesignEnabled) toV2() else toV1()
|
||||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.V1.Buy
|
|
||||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.V1.Exchange(action.shouldShowBadge)
|
private fun TokenActionsState.ActionState.toV2(): QuickActionUM? = when (this) {
|
||||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.V1.Receive
|
is TokenActionsState.ActionState.Buy -> QuickActionUM.V2.Buy
|
||||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.V1.Stake
|
is TokenActionsState.ActionState.Swap -> QuickActionUM.V2.Exchange(shouldShowBadge)
|
||||||
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.V1.YieldMode(action.apy)
|
is TokenActionsState.ActionState.Receive -> QuickActionUM.V2.Receive
|
||||||
else -> null
|
is TokenActionsState.ActionState.Send -> QuickActionUM.V2.Send
|
||||||
}?.let(::add)
|
is TokenActionsState.ActionState.Sell -> QuickActionUM.V2.Sell
|
||||||
}
|
is TokenActionsState.ActionState.Stake -> QuickActionUM.V2.Stake
|
||||||
}
|
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.V2.YieldMode(apy)
|
||||||
}.toImmutableList()
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TokenActionsState.ActionState.toV1(): QuickActionUM? = when (this) {
|
||||||
|
is TokenActionsState.ActionState.Buy -> QuickActionUM.V1.Buy
|
||||||
|
is TokenActionsState.ActionState.Swap -> QuickActionUM.V1.Exchange(shouldShowBadge)
|
||||||
|
is TokenActionsState.ActionState.Receive -> QuickActionUM.V1.Receive
|
||||||
|
is TokenActionsState.ActionState.Send -> QuickActionUM.V1.Send
|
||||||
|
is TokenActionsState.ActionState.Sell -> QuickActionUM.V1.Sell
|
||||||
|
is TokenActionsState.ActionState.Stake -> QuickActionUM.V1.Stake
|
||||||
|
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.V1.YieldMode(apy)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TokenActionsState.ActionState.toBsAction(): TokenActionsBSContentUM.Action? = when (this) {
|
||||||
|
is TokenActionsState.ActionState.Buy -> TokenActionsBSContentUM.Action.Buy
|
||||||
|
is TokenActionsState.ActionState.Swap -> TokenActionsBSContentUM.Action.Exchange
|
||||||
|
is TokenActionsState.ActionState.Receive -> TokenActionsBSContentUM.Action.Receive
|
||||||
|
is TokenActionsState.ActionState.Send -> TokenActionsBSContentUM.Action.Send
|
||||||
|
is TokenActionsState.ActionState.Sell -> TokenActionsBSContentUM.Action.Sell
|
||||||
|
is TokenActionsState.ActionState.Stake -> TokenActionsBSContentUM.Action.Stake
|
||||||
|
is TokenActionsState.ActionState.YieldMode -> TokenActionsBSContentUM.Action.YieldMode
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +43,10 @@ data class TokenActionsBSContentUM(
|
||||||
text = resourceReference(R.string.common_exchange),
|
text = resourceReference(R.string.common_exchange),
|
||||||
iconRes = R.drawable.ic_exchange_horizontal_24,
|
iconRes = R.drawable.ic_exchange_horizontal_24,
|
||||||
),
|
),
|
||||||
|
SendWithSwap(
|
||||||
|
text = resourceReference(R.string.common_send_with_swap),
|
||||||
|
iconRes = R.drawable.ic_exchange_horizontal_24,
|
||||||
|
),
|
||||||
Stake(
|
Stake(
|
||||||
text = resourceReference(R.string.common_stake),
|
text = resourceReference(R.string.common_stake),
|
||||||
iconRes = R.drawable.ic_staking_24,
|
iconRes = R.drawable.ic_staking_24,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.tangem.common.ui.markets.action
|
||||||
|
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
|
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM.Action
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drives how the shared token-actions bottom sheet behaves per entry point.
|
||||||
|
*
|
||||||
|
* @property allowedActionsInOrder explicit allow-list + display order; `null` means "all actions
|
||||||
|
* in source order" (legacy Markets behaviour).
|
||||||
|
* @property swapPosition the [AppRoute.Swap.CurrencyPosition] used when the Swap/Exchange action is
|
||||||
|
* launched from this context.
|
||||||
|
*/
|
||||||
|
enum class TokenActionsContext(
|
||||||
|
val allowedActionsInOrder: List<Action>?,
|
||||||
|
val swapPosition: AppRoute.Swap.CurrencyPosition,
|
||||||
|
) {
|
||||||
|
Markets(
|
||||||
|
allowedActionsInOrder = null,
|
||||||
|
swapPosition = AppRoute.Swap.CurrencyPosition.ANY,
|
||||||
|
),
|
||||||
|
AddFunds(
|
||||||
|
allowedActionsInOrder = listOf(Action.Buy, Action.Exchange, Action.Receive),
|
||||||
|
swapPosition = AppRoute.Swap.CurrencyPosition.TO,
|
||||||
|
),
|
||||||
|
Transfer(
|
||||||
|
// Action.SendWithSwap has no TokenActionsState.ActionState counterpart and is never produced from the
|
||||||
|
// domain action list; it is injected as a synthetic row by the converter when Swap is available.
|
||||||
|
allowedActionsInOrder = listOf(Action.Send, Action.Exchange, Action.SendWithSwap, Action.Sell),
|
||||||
|
swapPosition = AppRoute.Swap.CurrencyPosition.FROM,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -51,7 +51,11 @@ class TokenActionsHandler @AssistedInject constructor(
|
||||||
add(TokenActionsBSContentUM.Action.Sell)
|
add(TokenActionsBSContentUM.Action.Sell)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handle(action: TokenActionsBSContentUM.Action, cryptoCurrencyData: CryptoCurrencyData) {
|
fun handle(
|
||||||
|
action: TokenActionsBSContentUM.Action,
|
||||||
|
cryptoCurrencyData: CryptoCurrencyData,
|
||||||
|
context: TokenActionsContext = TokenActionsContext.Markets,
|
||||||
|
) {
|
||||||
if (isTopUpBlockedByBackupError(action, cryptoCurrencyData.userWallet)) return
|
if (isTopUpBlockedByBackupError(action, cryptoCurrencyData.userWallet)) return
|
||||||
|
|
||||||
onHandleQuickAction(
|
onHandleQuickAction(
|
||||||
|
|
@ -59,25 +63,37 @@ class TokenActionsHandler @AssistedInject constructor(
|
||||||
action = action,
|
action = action,
|
||||||
cryptoCurrencyData = cryptoCurrencyData,
|
cryptoCurrencyData = cryptoCurrencyData,
|
||||||
),
|
),
|
||||||
when (action) {
|
action.shouldDismissBottomSheet(),
|
||||||
TokenActionsBSContentUM.Action.Receive,
|
|
||||||
TokenActionsBSContentUM.Action.CopyAddress,
|
|
||||||
TokenActionsBSContentUM.Action.Sell,
|
|
||||||
-> false
|
|
||||||
TokenActionsBSContentUM.Action.Send,
|
|
||||||
TokenActionsBSContentUM.Action.Stake,
|
|
||||||
TokenActionsBSContentUM.Action.YieldMode,
|
|
||||||
TokenActionsBSContentUM.Action.Buy,
|
|
||||||
TokenActionsBSContentUM.Action.Exchange,
|
|
||||||
-> true
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
val userWallet = cryptoCurrencyData.userWallet
|
val userWallet = cryptoCurrencyData.userWallet
|
||||||
if (userWallet is UserWallet.Cold && handleDemoMode(action, userWallet)) return
|
if (userWallet is UserWallet.Cold && handleDemoMode(action, userWallet)) return
|
||||||
|
|
||||||
|
dispatchAction(action, cryptoCurrencyData, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TokenActionsBSContentUM.Action.shouldDismissBottomSheet(): Boolean = when (this) {
|
||||||
|
TokenActionsBSContentUM.Action.Receive,
|
||||||
|
TokenActionsBSContentUM.Action.CopyAddress,
|
||||||
|
TokenActionsBSContentUM.Action.Sell,
|
||||||
|
-> false
|
||||||
|
TokenActionsBSContentUM.Action.Send,
|
||||||
|
TokenActionsBSContentUM.Action.Stake,
|
||||||
|
TokenActionsBSContentUM.Action.YieldMode,
|
||||||
|
TokenActionsBSContentUM.Action.Buy,
|
||||||
|
TokenActionsBSContentUM.Action.Exchange,
|
||||||
|
TokenActionsBSContentUM.Action.SendWithSwap,
|
||||||
|
-> true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dispatchAction(
|
||||||
|
action: TokenActionsBSContentUM.Action,
|
||||||
|
cryptoCurrencyData: CryptoCurrencyData,
|
||||||
|
context: TokenActionsContext,
|
||||||
|
) {
|
||||||
when (action) {
|
when (action) {
|
||||||
TokenActionsBSContentUM.Action.Buy -> onBuyClick(cryptoCurrencyData)
|
TokenActionsBSContentUM.Action.Buy -> onBuyClick(cryptoCurrencyData)
|
||||||
TokenActionsBSContentUM.Action.Exchange -> onExchangeClick(cryptoCurrencyData)
|
TokenActionsBSContentUM.Action.Exchange -> onExchangeClick(cryptoCurrencyData, context)
|
||||||
|
TokenActionsBSContentUM.Action.SendWithSwap -> onSwapAndSendClick(cryptoCurrencyData)
|
||||||
TokenActionsBSContentUM.Action.Receive -> Unit
|
TokenActionsBSContentUM.Action.Receive -> Unit
|
||||||
TokenActionsBSContentUM.Action.CopyAddress -> onCopyAddress(cryptoCurrencyData)
|
TokenActionsBSContentUM.Action.CopyAddress -> onCopyAddress(cryptoCurrencyData)
|
||||||
TokenActionsBSContentUM.Action.Sell -> onSellClick(cryptoCurrencyData)
|
TokenActionsBSContentUM.Action.Sell -> onSellClick(cryptoCurrencyData)
|
||||||
|
|
@ -155,12 +171,13 @@ class TokenActionsHandler @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onExchangeClick(cryptoCurrencyData: CryptoCurrencyData) {
|
private fun onExchangeClick(cryptoCurrencyData: CryptoCurrencyData, context: TokenActionsContext) {
|
||||||
router.push(
|
router.push(
|
||||||
AppRoute.Swap(
|
AppRoute.Swap(
|
||||||
fromCryptoCurrency = cryptoCurrencyData.status.currency,
|
fromCryptoCurrency = cryptoCurrencyData.status.currency,
|
||||||
userWalletId = cryptoCurrencyData.userWallet.walletId,
|
userWalletId = cryptoCurrencyData.userWallet.walletId,
|
||||||
screenSource = AnalyticsParam.ScreensSources.Markets.value,
|
screenSource = AnalyticsParam.ScreensSources.Markets.value,
|
||||||
|
fromCurrencyPosition = context.swapPosition,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -173,6 +190,16 @@ class TokenActionsHandler @AssistedInject constructor(
|
||||||
router.push(route)
|
router.push(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onSwapAndSendClick(cryptoCurrencyData: CryptoCurrencyData) {
|
||||||
|
router.push(
|
||||||
|
AppRoute.SendEntryPoint(
|
||||||
|
userWalletId = cryptoCurrencyData.userWallet.walletId,
|
||||||
|
currency = cryptoCurrencyData.status.currency,
|
||||||
|
shouldStartWithSwap = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun onStakeClick(cryptoCurrencyData: CryptoCurrencyData) {
|
private fun onStakeClick(cryptoCurrencyData: CryptoCurrencyData) {
|
||||||
val option = cryptoCurrencyData.actions.firstOrNull { it is TokenActionsState.ActionState.Stake }
|
val option = cryptoCurrencyData.actions.firstOrNull { it is TokenActionsState.ActionState.Stake }
|
||||||
?.let { it as TokenActionsState.ActionState.Stake }
|
?.let { it as TokenActionsState.ActionState.Stake }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
package com.tangem.common.ui.markets.action
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||||
|
import com.tangem.domain.tokens.model.TokenActionsState
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class QuickActionsConverterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN actions in source order WHEN context is AddFunds THEN buy exchange receive in order with no stake`() {
|
||||||
|
// Arrange
|
||||||
|
val actions = listOf(
|
||||||
|
TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None),
|
||||||
|
TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.None, option = null),
|
||||||
|
TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, shouldShowBadge = false),
|
||||||
|
TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = QuickActionsConverter.toQuickActions(
|
||||||
|
actions = actions,
|
||||||
|
isRedesignEnabled = true,
|
||||||
|
context = TokenActionsContext.AddFunds,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result).containsExactly(
|
||||||
|
QuickActionUM.V2.Buy,
|
||||||
|
QuickActionUM.V2.Exchange(shouldShowBadge = false),
|
||||||
|
QuickActionUM.V2.Receive,
|
||||||
|
).inOrder()
|
||||||
|
assertThat(result).doesNotContain(QuickActionUM.V2.Stake)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN receive and stake WHEN context is Markets THEN preserves source order and keeps stake`() {
|
||||||
|
// Arrange
|
||||||
|
val actions = listOf(
|
||||||
|
TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None),
|
||||||
|
TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.None, option = null),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = QuickActionsConverter.toQuickActions(
|
||||||
|
actions = actions,
|
||||||
|
isRedesignEnabled = true,
|
||||||
|
context = TokenActionsContext.Markets,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result).containsExactly(
|
||||||
|
QuickActionUM.V2.Receive,
|
||||||
|
QuickActionUM.V2.Stake,
|
||||||
|
).inOrder()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN buy with unavailability reason mixed with available actions WHEN toQuickActions THEN unavailable action is excluded`() {
|
||||||
|
// Arrange
|
||||||
|
val actions = listOf(
|
||||||
|
TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.BuyUnavailable(cryptoCurrencyName = "BTC")),
|
||||||
|
TokenActionsState.ActionState.Receive(ScenarioUnavailabilityReason.None),
|
||||||
|
TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, shouldShowBadge = false),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = QuickActionsConverter.toQuickActions(
|
||||||
|
actions = actions,
|
||||||
|
isRedesignEnabled = true,
|
||||||
|
context = TokenActionsContext.Markets,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result).containsExactly(
|
||||||
|
QuickActionUM.V2.Receive,
|
||||||
|
QuickActionUM.V2.Exchange(shouldShowBadge = false),
|
||||||
|
).inOrder()
|
||||||
|
assertThat(result).doesNotContain(QuickActionUM.V2.Buy)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN send swap sell available WHEN context is Transfer THEN send exchange swapAndSend sell in order`() {
|
||||||
|
// Arrange
|
||||||
|
val actions = listOf(
|
||||||
|
TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.None),
|
||||||
|
TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, shouldShowBadge = false),
|
||||||
|
TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.None),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = QuickActionsConverter.toQuickActions(
|
||||||
|
actions = actions,
|
||||||
|
isRedesignEnabled = true,
|
||||||
|
context = TokenActionsContext.Transfer,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result).containsExactly(
|
||||||
|
QuickActionUM.V2.Send,
|
||||||
|
QuickActionUM.V2.Exchange(shouldShowBadge = false),
|
||||||
|
QuickActionUM.V2.SwapAndSend,
|
||||||
|
QuickActionUM.V2.Sell,
|
||||||
|
).inOrder()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN send and sell but no swap WHEN context is Transfer THEN only send and sell with no swapAndSend`() {
|
||||||
|
// Arrange
|
||||||
|
val actions = listOf(
|
||||||
|
TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.None),
|
||||||
|
TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.None),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = QuickActionsConverter.toQuickActions(
|
||||||
|
actions = actions,
|
||||||
|
isRedesignEnabled = true,
|
||||||
|
context = TokenActionsContext.Transfer,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result).containsExactly(
|
||||||
|
QuickActionUM.V2.Send,
|
||||||
|
QuickActionUM.V2.Sell,
|
||||||
|
).inOrder()
|
||||||
|
assertThat(result).doesNotContain(QuickActionUM.V2.SwapAndSend)
|
||||||
|
assertThat(result).doesNotContain(QuickActionUM.V2.Exchange(shouldShowBadge = false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.tangem.common.ui.markets.action
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
|
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM.Action
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class TokenActionsContextTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN AddFunds context WHEN allowedActionsInOrder THEN Buy Swap Receive`() {
|
||||||
|
// Act
|
||||||
|
val actual = TokenActionsContext.AddFunds.allowedActionsInOrder
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(actual).containsExactly(Action.Buy, Action.Exchange, Action.Receive).inOrder()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN AddFunds context WHEN swapPosition THEN TO`() {
|
||||||
|
assertThat(TokenActionsContext.AddFunds.swapPosition)
|
||||||
|
.isEqualTo(AppRoute.Swap.CurrencyPosition.TO)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN Transfer context WHEN swapPosition THEN FROM`() {
|
||||||
|
assertThat(TokenActionsContext.Transfer.swapPosition)
|
||||||
|
.isEqualTo(AppRoute.Swap.CurrencyPosition.FROM)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN Markets context WHEN allowedActionsInOrder THEN null meaning all`() {
|
||||||
|
assertThat(TokenActionsContext.Markets.allowedActionsInOrder).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.tangem.common.ui.markets.action
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
|
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||||
|
import com.tangem.core.decompose.navigation.Route
|
||||||
|
import com.tangem.core.decompose.navigation.Router
|
||||||
|
import com.tangem.domain.models.account.AccountStatus
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.utils.Provider
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
internal class TokenActionsHandlerSwapTest {
|
||||||
|
|
||||||
|
private val router: Router = mockk(relaxed = true)
|
||||||
|
|
||||||
|
private val handler = TokenActionsHandler(
|
||||||
|
router = router,
|
||||||
|
clipboardManager = mockk(relaxed = true),
|
||||||
|
uiMessageSender = mockk(relaxed = true),
|
||||||
|
getOfframpUrlUseCase = mockk(relaxed = true),
|
||||||
|
urlOpener = mockk(relaxed = true),
|
||||||
|
analyticsEventHandler = mockk(relaxed = true),
|
||||||
|
currentAppCurrency = Provider { mockk(relaxed = true) },
|
||||||
|
onHandleQuickAction = { _, _ -> },
|
||||||
|
coroutineScope = CoroutineScope(UnconfinedTestDispatcher()),
|
||||||
|
isDemoCardUseCase = mockk(relaxed = true),
|
||||||
|
isWalletBackupProblematicUseCase = mockk(relaxed = true),
|
||||||
|
sendBackupProblemEmailUseCase = mockk(relaxed = true),
|
||||||
|
messageSender = mockk(relaxed = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val userWallet: UserWallet = mockk(relaxed = true)
|
||||||
|
private val currency: CryptoCurrency = MockCryptoCurrencyFactory().ethereum
|
||||||
|
private val data = CryptoCurrencyData(
|
||||||
|
userWallet = userWallet,
|
||||||
|
status = CryptoCurrencyStatus(currency = currency, value = CryptoCurrencyStatus.Loading),
|
||||||
|
actions = emptyList(),
|
||||||
|
isAccountMode = false,
|
||||||
|
account = mockk<AccountStatus.CryptoPortfolio>(relaxed = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN AddFunds context WHEN handle Exchange THEN swap pushed with TO position`() {
|
||||||
|
// Arrange
|
||||||
|
val slot = slot<Route>()
|
||||||
|
every { router.push(capture(slot), any()) } returns Unit
|
||||||
|
|
||||||
|
// Act
|
||||||
|
handler.handle(
|
||||||
|
action = TokenActionsBSContentUM.Action.Exchange,
|
||||||
|
cryptoCurrencyData = data,
|
||||||
|
context = TokenActionsContext.AddFunds,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val pushed = slot.captured as AppRoute.Swap
|
||||||
|
assertThat(pushed.fromCurrencyPosition).isEqualTo(AppRoute.Swap.CurrencyPosition.TO)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN Transfer context WHEN handle Exchange THEN swap pushed with FROM position`() {
|
||||||
|
// Arrange
|
||||||
|
val slot = slot<Route>()
|
||||||
|
every { router.push(capture(slot), any()) } returns Unit
|
||||||
|
|
||||||
|
// Act
|
||||||
|
handler.handle(
|
||||||
|
action = TokenActionsBSContentUM.Action.Exchange,
|
||||||
|
cryptoCurrencyData = data,
|
||||||
|
context = TokenActionsContext.Transfer,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val pushed = slot.captured as AppRoute.Swap
|
||||||
|
assertThat(pushed.fromCurrencyPosition).isEqualTo(AppRoute.Swap.CurrencyPosition.FROM)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN default context WHEN handle Exchange THEN swap pushed with ANY position`() {
|
||||||
|
// Arrange
|
||||||
|
val slot = slot<Route>()
|
||||||
|
every { router.push(capture(slot), any()) } returns Unit
|
||||||
|
|
||||||
|
// Act
|
||||||
|
handler.handle(
|
||||||
|
action = TokenActionsBSContentUM.Action.Exchange,
|
||||||
|
cryptoCurrencyData = data,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val pushed = slot.captured as AppRoute.Swap
|
||||||
|
assertThat(pushed.fromCurrencyPosition).isEqualTo(AppRoute.Swap.CurrencyPosition.ANY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -87,6 +87,10 @@
|
||||||
"name": "AND_15310_ADD_FUNDS_STAGE1",
|
"name": "AND_15310_ADD_FUNDS_STAGE1",
|
||||||
"version": "5.39"
|
"version": "5.39"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TWI_1377_MANAGE_FUNDS",
|
||||||
|
"version": "5.40"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "AND_15009_SWAP_PROVIDER_FILTER_ENABLED",
|
"name": "AND_15009_SWAP_PROVIDER_FILTER_ENABLED",
|
||||||
"version": "5.39"
|
"version": "5.39"
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,7 @@
|
||||||
<string name="common_error">Error</string>
|
<string name="common_error">Error</string>
|
||||||
<string name="common_estimated_fee">Top-up network fee</string>
|
<string name="common_estimated_fee">Top-up network fee</string>
|
||||||
<string name="common_exchange">Swap</string>
|
<string name="common_exchange">Swap</string>
|
||||||
|
<string name="common_send_with_swap">Send&Swap</string>
|
||||||
<string name="common_explore">Explore</string>
|
<string name="common_explore">Explore</string>
|
||||||
<string name="common_explore_transaction_history">Explore transaction history</string>
|
<string name="common_explore_transaction_history">Explore transaction history</string>
|
||||||
<string name="common_explorer">Explorer</string>
|
<string name="common_explorer">Explorer</string>
|
||||||
|
|
@ -1294,6 +1295,7 @@
|
||||||
<string name="quick_action_sell_description">Sell crypto securely</string>
|
<string name="quick_action_sell_description">Sell crypto securely</string>
|
||||||
<string name="quick_action_send_description">Send to another wallet</string>
|
<string name="quick_action_send_description">Send to another wallet</string>
|
||||||
<string name="quick_action_swap_description">Between your portfolios</string>
|
<string name="quick_action_swap_description">Between your portfolios</string>
|
||||||
|
<string name="quick_action_send_and_swap_description">Send with swap to another token</string>
|
||||||
<string name="quick_top_up_chip_other">Other</string>
|
<string name="quick_top_up_chip_other">Other</string>
|
||||||
<string name="quick_top_up_title">Quick top up</string>
|
<string name="quick_top_up_title">Quick top up</string>
|
||||||
<string name="receive_bottom_sheet_no_memo_required_message">No memo required</string>
|
<string name="receive_bottom_sheet_no_memo_required_message">No memo required</string>
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,13 @@ interface ChooseTokenBridge : ChooseTokenBridgeInternal {
|
||||||
isAppBarShown = false,
|
isAppBarShown = false,
|
||||||
isShowSingleCurrencyWallets = true,
|
isShowSingleCurrencyWallets = true,
|
||||||
)
|
)
|
||||||
|
val Transfer = Settings(
|
||||||
|
title = resourceReference(R.string.common_transfer),
|
||||||
|
isShowMarketBlock = false,
|
||||||
|
isShowPaymentAccount = false,
|
||||||
|
isAppBarShown = false,
|
||||||
|
isShowSingleCurrencyWallets = true,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
package com.tangem.features.commonfeatures.api.addfunds
|
package com.tangem.features.commonfeatures.api.managefunds
|
||||||
|
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
interface AddFundsComponent : ComposableBottomSheetComponent {
|
interface ManageFundsComponent : ComposableBottomSheetComponent {
|
||||||
|
|
||||||
data class Params(
|
data class Params(
|
||||||
val launchMode: LaunchMode,
|
val launchMode: LaunchMode,
|
||||||
val onDismiss: () -> Unit,
|
val onDismiss: () -> Unit,
|
||||||
|
val flowType: FlowType = FlowType.AddFunds,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class FlowType { AddFunds, Transfer }
|
||||||
|
|
||||||
sealed interface LaunchMode {
|
sealed interface LaunchMode {
|
||||||
data class ChooseToken(val userWalletId: UserWalletId) : LaunchMode
|
data class ChooseToken(val userWalletId: UserWalletId) : LaunchMode
|
||||||
|
|
||||||
|
|
@ -25,5 +28,5 @@ interface AddFundsComponent : ComposableBottomSheetComponent {
|
||||||
) : LaunchMode
|
) : LaunchMode
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Factory : ComponentFactory<Params, AddFundsComponent>
|
interface Factory : ComponentFactory<Params, ManageFundsComponent>
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package com.tangem.features.commonfeatures.impl.addfunds.model
|
|
||||||
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
import com.tangem.features.commonfeatures.impl.R
|
|
||||||
import com.tangem.core.ui.R as CoreR
|
|
||||||
|
|
||||||
internal data class AddFundsRouteUiSpec(
|
|
||||||
val title: TextReference,
|
|
||||||
val shouldApplyHorizontalPadding: Boolean,
|
|
||||||
val shouldFillHeight: Boolean,
|
|
||||||
)
|
|
||||||
|
|
||||||
internal fun AddFundsModel.UiRoute.uiSpec(): AddFundsRouteUiSpec = when (this) {
|
|
||||||
AddFundsModel.UiRoute.Loading -> AddFundsRouteUiSpec(
|
|
||||||
title = resourceReference(R.string.common_add_funds),
|
|
||||||
shouldApplyHorizontalPadding = false,
|
|
||||||
shouldFillHeight = false,
|
|
||||||
)
|
|
||||||
AddFundsModel.UiRoute.ChooseToken -> AddFundsRouteUiSpec(
|
|
||||||
title = resourceReference(R.string.common_add_funds),
|
|
||||||
shouldApplyHorizontalPadding = false,
|
|
||||||
shouldFillHeight = true,
|
|
||||||
)
|
|
||||||
AddFundsModel.UiRoute.UserPortfolio -> AddFundsRouteUiSpec(
|
|
||||||
title = resourceReference(R.string.common_add_funds),
|
|
||||||
shouldApplyHorizontalPadding = false,
|
|
||||||
shouldFillHeight = false,
|
|
||||||
)
|
|
||||||
AddFundsModel.UiRoute.TokenActions -> AddFundsRouteUiSpec(
|
|
||||||
title = resourceReference(CoreR.string.common_get_token),
|
|
||||||
shouldApplyHorizontalPadding = true,
|
|
||||||
shouldFillHeight = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.features.commonfeatures.impl.addfunds
|
package com.tangem.features.commonfeatures.impl.managefunds
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
|
@ -22,51 +22,56 @@ import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemeRedesign
|
import com.tangem.core.ui.res.TangemThemeRedesign
|
||||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||||
import com.tangem.features.commonfeatures.impl.addfunds.model.AddFundsModel
|
import com.tangem.features.commonfeatures.impl.managefunds.model.ManageFundsModel
|
||||||
import com.tangem.features.commonfeatures.impl.addfunds.model.uiSpec
|
import com.tangem.features.commonfeatures.impl.managefunds.model.uiSpec
|
||||||
|
import com.tangem.common.ui.markets.action.TokenActionsContext
|
||||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||||
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
|
||||||
|
import com.tangem.features.commonfeatures.impl.R
|
||||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import com.tangem.core.ui.R as CoreR
|
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
internal class DefaultAddFundsComponent @AssistedInject constructor(
|
internal class DefaultManageFundsComponent @AssistedInject constructor(
|
||||||
@Assisted appComponentContext: AppComponentContext,
|
@Assisted appComponentContext: AppComponentContext,
|
||||||
@Assisted private val params: AddFundsComponent.Params,
|
@Assisted private val params: ManageFundsComponent.Params,
|
||||||
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
||||||
tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||||
userPortfolioComponentFactory: UserPortfolioComponent.Factory,
|
userPortfolioComponentFactory: UserPortfolioComponent.Factory,
|
||||||
walletFeatureToggles: WalletFeatureToggles,
|
walletFeatureToggles: WalletFeatureToggles,
|
||||||
) : AppComponentContext by appComponentContext, AddFundsComponent {
|
) : AppComponentContext by appComponentContext, ManageFundsComponent {
|
||||||
|
|
||||||
private val model: AddFundsModel = getOrCreateModel(params)
|
private val model: ManageFundsModel = getOrCreateModel(params)
|
||||||
|
|
||||||
private val isCompactTokenActions: Boolean = params.launchMode is AddFundsComponent.LaunchMode.TokenActionsOnly
|
private val isCompactTokenActions: Boolean = params.launchMode is ManageFundsComponent.LaunchMode.TokenActionsOnly
|
||||||
|
|
||||||
private val isAddFundsStage1Enabled: Boolean = walletFeatureToggles.isAddFundsStage1Enabled
|
private val isAddFundsStage1Enabled: Boolean = walletFeatureToggles.isAddFundsStage1Enabled
|
||||||
|
|
||||||
private val tokenActionsComponent: TokenActionsComponent by lazy {
|
private val tokenActionsComponent: TokenActionsComponent by lazy {
|
||||||
tokenActionsComponentFactory.create(
|
tokenActionsComponentFactory.create(
|
||||||
context = child(key = "addFundsTokenActions"),
|
context = child(key = "manageFundsTokenActions"),
|
||||||
params = TokenActionsComponent.Params(
|
params = TokenActionsComponent.Params(
|
||||||
data = model.tokenActionsData,
|
data = model.tokenActionsData,
|
||||||
callbacks = model,
|
callbacks = model,
|
||||||
bottomAction = model.currentBottomAction,
|
bottomAction = model.currentBottomAction,
|
||||||
isRedesignForced = true,
|
isRedesignForced = true,
|
||||||
isCompact = isCompactTokenActions,
|
isCompact = isCompactTokenActions,
|
||||||
|
context = when (model.flowType) {
|
||||||
|
ManageFundsComponent.FlowType.AddFunds -> TokenActionsContext.AddFunds
|
||||||
|
ManageFundsComponent.FlowType.Transfer -> TokenActionsContext.Transfer
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val chooseTokenComponent: ChooseTokenComponent? by lazy {
|
private val chooseTokenComponent: ChooseTokenComponent? by lazy {
|
||||||
(params.launchMode as? AddFundsComponent.LaunchMode.ChooseToken)?.let {
|
(params.launchMode as? ManageFundsComponent.LaunchMode.ChooseToken)?.let {
|
||||||
chooseTokenComponentFactory.create(
|
chooseTokenComponentFactory.create(
|
||||||
context = child(key = "addFundsChooseToken"),
|
context = child(key = "manageFundsChooseToken"),
|
||||||
params = ChooseTokenComponent.Params(
|
params = ChooseTokenComponent.Params(
|
||||||
bridge = model.chooseTokenBridge,
|
bridge = model.chooseTokenBridge,
|
||||||
),
|
),
|
||||||
|
|
@ -76,7 +81,7 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
|
|
||||||
private val userPortfolioComponent: UserPortfolioComponent by lazy {
|
private val userPortfolioComponent: UserPortfolioComponent by lazy {
|
||||||
userPortfolioComponentFactory.create(
|
userPortfolioComponentFactory.create(
|
||||||
context = child(key = "addFundsUserPortfolio"),
|
context = child(key = "manageFundsUserPortfolio"),
|
||||||
params = UserPortfolioComponent.Params(
|
params = UserPortfolioComponent.Params(
|
||||||
uiState = model.userPortfolioStateController.uiState,
|
uiState = model.userPortfolioStateController.uiState,
|
||||||
callbacks = object : UserPortfolioComponent.Callbacks {
|
callbacks = object : UserPortfolioComponent.Callbacks {
|
||||||
|
|
@ -94,8 +99,8 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
val canGoBack by model.canGoBack.collectAsStateWithLifecycle()
|
val canGoBack by model.canGoBack.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
LaunchedEffect(route) {
|
LaunchedEffect(route) {
|
||||||
if (route != AddFundsModel.UiRoute.UserPortfolio) return@LaunchedEffect
|
if (route != ManageFundsModel.UiRoute.UserPortfolio) return@LaunchedEffect
|
||||||
val mode = params.launchMode as? AddFundsComponent.LaunchMode.FilteredByRawId ?: return@LaunchedEffect
|
val mode = params.launchMode as? ManageFundsComponent.LaunchMode.FilteredByRawId ?: return@LaunchedEffect
|
||||||
model.userPortfolioStateController.updateAndWaitNotNullState(
|
model.userPortfolioStateController.updateAndWaitNotNullState(
|
||||||
allAvailableData = model.buildAvailableToAddDataForChooser(),
|
allAvailableData = model.buildAvailableToAddDataForChooser(),
|
||||||
rawCurrencyId = mode.rawCurrencyId,
|
rawCurrencyId = mode.rawCurrencyId,
|
||||||
|
|
@ -111,10 +116,10 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
content = TangemBottomSheetConfigContent.Empty,
|
content = TangemBottomSheetConfigContent.Empty,
|
||||||
),
|
),
|
||||||
type = when (params.launchMode) {
|
type = when (params.launchMode) {
|
||||||
is AddFundsComponent.LaunchMode.TokenActionsOnly -> TangemBottomSheetType.Modal
|
is ManageFundsComponent.LaunchMode.TokenActionsOnly -> TangemBottomSheetType.Modal
|
||||||
is AddFundsComponent.LaunchMode.ChooseToken -> TangemBottomSheetType.Default
|
is ManageFundsComponent.LaunchMode.ChooseToken -> TangemBottomSheetType.Default
|
||||||
is AddFundsComponent.LaunchMode.FilteredByRawId ->
|
is ManageFundsComponent.LaunchMode.FilteredByRawId ->
|
||||||
if (route is AddFundsModel.UiRoute.TokenActions) {
|
if (route is ManageFundsModel.UiRoute.TokenActions) {
|
||||||
TangemBottomSheetType.Default
|
TangemBottomSheetType.Default
|
||||||
} else {
|
} else {
|
||||||
TangemBottomSheetType.Modal
|
TangemBottomSheetType.Modal
|
||||||
|
|
@ -122,7 +127,7 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
},
|
},
|
||||||
containerColor = TangemTheme.colors2.surface.level2,
|
containerColor = TangemTheme.colors2.surface.level2,
|
||||||
title = {
|
title = {
|
||||||
AddFundsBottomSheetTitle(
|
ManageFundsBottomSheetTitle(
|
||||||
route = route,
|
route = route,
|
||||||
canGoBack = canGoBack,
|
canGoBack = canGoBack,
|
||||||
onBackClick = model::onBack,
|
onBackClick = model::onBack,
|
||||||
|
|
@ -131,7 +136,7 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
val animatedContentModifier =
|
val animatedContentModifier =
|
||||||
if (params.launchMode is AddFundsComponent.LaunchMode.ChooseToken) {
|
if (params.launchMode is ManageFundsComponent.LaunchMode.ChooseToken) {
|
||||||
Modifier.fillMaxSize()
|
Modifier.fillMaxSize()
|
||||||
} else {
|
} else {
|
||||||
Modifier
|
Modifier
|
||||||
|
|
@ -139,11 +144,12 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = route,
|
targetState = route,
|
||||||
modifier = animatedContentModifier,
|
modifier = animatedContentModifier,
|
||||||
label = "AddFundsContentAnimation",
|
label = "ManageFundsContentAnimation",
|
||||||
) { animatedRoute ->
|
) { animatedRoute ->
|
||||||
AddFundsRouteContent(
|
ManageFundsRouteContent(
|
||||||
route = animatedRoute,
|
route = animatedRoute,
|
||||||
shouldFillHeight = !isCompactTokenActions && animatedRoute.uiSpec().shouldFillHeight,
|
shouldFillHeight = !isCompactTokenActions &&
|
||||||
|
animatedRoute.uiSpec(model.flowType).shouldFillHeight,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -152,8 +158,8 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AddFundsRouteContent(route: AddFundsModel.UiRoute, shouldFillHeight: Boolean) {
|
private fun ManageFundsRouteContent(route: ManageFundsModel.UiRoute, shouldFillHeight: Boolean) {
|
||||||
val spec = route.uiSpec()
|
val spec = route.uiSpec(model.flowType)
|
||||||
val horizontalPadding = if (spec.shouldApplyHorizontalPadding) {
|
val horizontalPadding = if (spec.shouldApplyHorizontalPadding) {
|
||||||
Modifier.padding(horizontal = TangemTheme.dimens2.x4)
|
Modifier.padding(horizontal = TangemTheme.dimens2.x4)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -164,33 +170,33 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RenderRoute(route: AddFundsModel.UiRoute, modifier: Modifier = Modifier) {
|
private fun RenderRoute(route: ManageFundsModel.UiRoute, modifier: Modifier = Modifier) {
|
||||||
when (route) {
|
when (route) {
|
||||||
AddFundsModel.UiRoute.Loading -> Unit
|
ManageFundsModel.UiRoute.Loading -> Unit
|
||||||
AddFundsModel.UiRoute.ChooseToken -> chooseTokenComponent?.Content(modifier)
|
ManageFundsModel.UiRoute.ChooseToken -> chooseTokenComponent?.Content(modifier)
|
||||||
AddFundsModel.UiRoute.UserPortfolio -> CompositionLocalProvider(
|
ManageFundsModel.UiRoute.UserPortfolio -> CompositionLocalProvider(
|
||||||
LocalTangemBottomSheetContentBottomInset provides TangemTheme.dimens2.x4,
|
LocalTangemBottomSheetContentBottomInset provides TangemTheme.dimens2.x4,
|
||||||
) {
|
) {
|
||||||
userPortfolioComponent.Content(modifier)
|
userPortfolioComponent.Content(modifier)
|
||||||
}
|
}
|
||||||
AddFundsModel.UiRoute.TokenActions -> tokenActionsComponent.Content(modifier)
|
ManageFundsModel.UiRoute.TokenActions -> tokenActionsComponent.Content(modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AddFundsBottomSheetTitle(
|
private fun ManageFundsBottomSheetTitle(
|
||||||
route: AddFundsModel.UiRoute,
|
route: ManageFundsModel.UiRoute,
|
||||||
canGoBack: Boolean,
|
canGoBack: Boolean,
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
onCloseClick: () -> Unit,
|
onCloseClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
TangemTopBar(
|
TangemTopBar(
|
||||||
title = route.uiSpec().title,
|
title = route.uiSpec(model.flowType).title,
|
||||||
type = TangemTopBarType.BottomSheet,
|
type = TangemTopBarType.BottomSheet,
|
||||||
startContent = if (canGoBack) {
|
startContent = if (canGoBack) {
|
||||||
{
|
{
|
||||||
TangemButton(
|
TangemButton(
|
||||||
iconStart = TangemIconUM.Icon(iconRes = CoreR.drawable.ic_arrow_back_28),
|
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_arrow_back_28),
|
||||||
onClick = onBackClick,
|
onClick = onBackClick,
|
||||||
size = TangemButton.Size.X11,
|
size = TangemButton.Size.X11,
|
||||||
variant = TangemButton.Variant.Material,
|
variant = TangemButton.Variant.Material,
|
||||||
|
|
@ -202,7 +208,7 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
endContent = {
|
endContent = {
|
||||||
TangemButton(
|
TangemButton(
|
||||||
modifier = Modifier.testTag(BaseBottomSheetTestTags.CLOSE_BUTTON),
|
modifier = Modifier.testTag(BaseBottomSheetTestTags.CLOSE_BUTTON),
|
||||||
iconStart = TangemIconUM.Icon(iconRes = CoreR.drawable.ic_close_24),
|
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_close_24),
|
||||||
onClick = onCloseClick,
|
onClick = onCloseClick,
|
||||||
size = TangemButton.Size.X11,
|
size = TangemButton.Size.X11,
|
||||||
variant = TangemButton.Variant.Material,
|
variant = TangemButton.Variant.Material,
|
||||||
|
|
@ -221,7 +227,10 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory : AddFundsComponent.Factory {
|
interface Factory : ManageFundsComponent.Factory {
|
||||||
override fun create(context: AppComponentContext, params: AddFundsComponent.Params): DefaultAddFundsComponent
|
override fun create(
|
||||||
|
context: AppComponentContext,
|
||||||
|
params: ManageFundsComponent.Params,
|
||||||
|
): DefaultManageFundsComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
package com.tangem.features.commonfeatures.impl.addfunds.analytics
|
package com.tangem.features.commonfeatures.impl.managefunds.analytics
|
||||||
|
|
||||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
|
|
||||||
internal sealed class AddFundsAnalyticsEvent(
|
internal sealed class ManageFundsAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = emptyMap(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent(category = CATEGORY, event = event, params = params) {
|
) : AnalyticsEvent(category = CATEGORY, event = event, params = params) {
|
||||||
|
|
||||||
class MethodScreenOpened(source: String) : AddFundsAnalyticsEvent(
|
class MethodScreenOpened(source: String) : ManageFundsAnalyticsEvent(
|
||||||
event = "Method Screen Opened",
|
event = "Method Screen Opened",
|
||||||
params = mapOf(AnalyticsParam.SOURCE to source),
|
params = mapOf(AnalyticsParam.SOURCE to source),
|
||||||
)
|
)
|
||||||
|
|
||||||
class ButtonBuy : AddFundsAnalyticsEvent(event = "Button - Buy")
|
class ButtonBuy : ManageFundsAnalyticsEvent(event = "Button - Buy")
|
||||||
|
|
||||||
class ButtonSwap : AddFundsAnalyticsEvent(event = "Button - Swap")
|
class ButtonSwap : ManageFundsAnalyticsEvent(event = "Button - Swap")
|
||||||
|
|
||||||
class ButtonReceive : AddFundsAnalyticsEvent(event = "Button - Receive")
|
class ButtonReceive : ManageFundsAnalyticsEvent(event = "Button - Receive")
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val CATEGORY = "Add Funds"
|
private const val CATEGORY = "Add Funds"
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.tangem.features.commonfeatures.impl.managefunds.di
|
||||||
|
|
||||||
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
|
import com.tangem.features.commonfeatures.impl.managefunds.DefaultManageFundsComponent
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
internal interface ManageFundsComponentModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
fun bindManageFundsComponentFactory(factory: DefaultManageFundsComponent.Factory): ManageFundsComponent.Factory
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.features.commonfeatures.impl.addfunds.di
|
package com.tangem.features.commonfeatures.impl.managefunds.di
|
||||||
|
|
||||||
import com.tangem.core.decompose.di.ModelComponent
|
import com.tangem.core.decompose.di.ModelComponent
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.features.commonfeatures.impl.addfunds.model.AddFundsModel
|
import com.tangem.features.commonfeatures.impl.managefunds.model.ManageFundsModel
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
|
@ -11,10 +11,10 @@ import dagger.multibindings.IntoMap
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(ModelComponent::class)
|
@InstallIn(ModelComponent::class)
|
||||||
internal interface AddFundsModelModule {
|
internal interface ManageFundsModelModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ClassKey(AddFundsModel::class)
|
@ClassKey(ManageFundsModel::class)
|
||||||
fun addFundsModel(model: AddFundsModel): Model
|
fun manageFundsModel(model: ManageFundsModel): Model
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.features.commonfeatures.impl.addfunds.model
|
package com.tangem.features.commonfeatures.impl.managefunds.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||||
|
|
@ -19,14 +19,14 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddData
|
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddData
|
||||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddWallet
|
import com.tangem.features.commonfeatures.api.addtoportfolio.AvailableToAddWallet
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||||
import com.tangem.features.commonfeatures.impl.addfunds.analytics.AddFundsAnalyticsEvent
|
import com.tangem.features.commonfeatures.impl.managefunds.analytics.ManageFundsAnalyticsEvent
|
||||||
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
|
||||||
import com.tangem.features.commonfeatures.impl.userportfolio.state.UserPortfolioStateController
|
import com.tangem.features.commonfeatures.impl.userportfolio.state.UserPortfolioStateController
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
|
@ -37,7 +37,7 @@ import javax.inject.Inject
|
||||||
|
|
||||||
@ModelScoped
|
@ModelScoped
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
internal class AddFundsModel @Inject constructor(
|
internal class ManageFundsModel @Inject constructor(
|
||||||
paramsContainer: ParamsContainer,
|
paramsContainer: ParamsContainer,
|
||||||
chooseTokenBridgeFactory: ChooseTokenBridge.Factory,
|
chooseTokenBridgeFactory: ChooseTokenBridge.Factory,
|
||||||
userPortfolioStateControllerFactory: UserPortfolioStateController.Factory,
|
userPortfolioStateControllerFactory: UserPortfolioStateController.Factory,
|
||||||
|
|
@ -50,8 +50,9 @@ internal class AddFundsModel @Inject constructor(
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
) : Model(), TokenActionsComponent.Callbacks {
|
) : Model(), TokenActionsComponent.Callbacks {
|
||||||
|
|
||||||
private val params = paramsContainer.require<AddFundsComponent.Params>()
|
private val params = paramsContainer.require<ManageFundsComponent.Params>()
|
||||||
val launchMode: AddFundsComponent.LaunchMode = params.launchMode
|
val launchMode: ManageFundsComponent.LaunchMode = params.launchMode
|
||||||
|
val flowType: ManageFundsComponent.FlowType = params.flowType
|
||||||
|
|
||||||
private val routeStack = MutableStateFlow(listOf<UiRoute>(UiRoute.Loading))
|
private val routeStack = MutableStateFlow(listOf<UiRoute>(UiRoute.Loading))
|
||||||
|
|
||||||
|
|
@ -95,7 +96,10 @@ internal class AddFundsModel @Inject constructor(
|
||||||
val chooseTokenBridge: ChooseTokenBridge by lazy {
|
val chooseTokenBridge: ChooseTokenBridge by lazy {
|
||||||
chooseTokenBridgeFactory.create(
|
chooseTokenBridgeFactory.create(
|
||||||
modelScope = modelScope,
|
modelScope = modelScope,
|
||||||
settings = ChooseTokenBridge.Settings.AddFunds,
|
settings = when (flowType) {
|
||||||
|
ManageFundsComponent.FlowType.AddFunds -> ChooseTokenBridge.Settings.AddFunds
|
||||||
|
ManageFundsComponent.FlowType.Transfer -> ChooseTokenBridge.Settings.Transfer
|
||||||
|
},
|
||||||
analyticsPayload = setOf(ChooseTokenAnalyticsPayload.ScreensSources(SCREEN_SOURCE)),
|
analyticsPayload = setOf(ChooseTokenAnalyticsPayload.ScreensSources(SCREEN_SOURCE)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -116,9 +120,9 @@ internal class AddFundsModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
when (val mode = launchMode) {
|
when (val mode = launchMode) {
|
||||||
is AddFundsComponent.LaunchMode.ChooseToken -> initChooseToken(mode)
|
is ManageFundsComponent.LaunchMode.ChooseToken -> initChooseToken(mode)
|
||||||
is AddFundsComponent.LaunchMode.TokenActionsOnly -> initTokenActionsOnly(mode)
|
is ManageFundsComponent.LaunchMode.TokenActionsOnly -> initTokenActionsOnly(mode)
|
||||||
is AddFundsComponent.LaunchMode.FilteredByRawId -> initFilteredByRawId(mode)
|
is ManageFundsComponent.LaunchMode.FilteredByRawId -> initFilteredByRawId(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,9 +147,9 @@ internal class AddFundsModel @Inject constructor(
|
||||||
|
|
||||||
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action, shouldDismiss: Boolean) {
|
override fun onQuickActionClick(action: TokenActionsBSContentUM.Action, shouldDismiss: Boolean) {
|
||||||
val event = when (action) {
|
val event = when (action) {
|
||||||
TokenActionsBSContentUM.Action.Buy -> AddFundsAnalyticsEvent.ButtonBuy()
|
TokenActionsBSContentUM.Action.Buy -> ManageFundsAnalyticsEvent.ButtonBuy()
|
||||||
TokenActionsBSContentUM.Action.Exchange -> AddFundsAnalyticsEvent.ButtonSwap()
|
TokenActionsBSContentUM.Action.Exchange -> ManageFundsAnalyticsEvent.ButtonSwap()
|
||||||
TokenActionsBSContentUM.Action.Receive -> AddFundsAnalyticsEvent.ButtonReceive()
|
TokenActionsBSContentUM.Action.Receive -> ManageFundsAnalyticsEvent.ButtonReceive()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
event?.let { analyticsEventHandler.send(it) }
|
event?.let { analyticsEventHandler.send(it) }
|
||||||
|
|
@ -168,10 +172,10 @@ internal class AddFundsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initChooseToken(mode: AddFundsComponent.LaunchMode.ChooseToken) {
|
private fun initChooseToken(mode: ManageFundsComponent.LaunchMode.ChooseToken) {
|
||||||
chooseTokenBridge.selectWalletTab(mode.userWalletId)
|
chooseTokenBridge.selectWalletTab(mode.userWalletId)
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
AddFundsAnalyticsEvent.MethodScreenOpened(source = AddFundsAnalyticsEvent.SOURCE_MAIN_SCREEN),
|
ManageFundsAnalyticsEvent.MethodScreenOpened(source = ManageFundsAnalyticsEvent.SOURCE_MAIN_SCREEN),
|
||||||
)
|
)
|
||||||
replaceRoot(UiRoute.ChooseToken)
|
replaceRoot(UiRoute.ChooseToken)
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
|
|
@ -182,7 +186,7 @@ internal class AddFundsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initTokenActionsOnly(mode: AddFundsComponent.LaunchMode.TokenActionsOnly) {
|
private fun initTokenActionsOnly(mode: ManageFundsComponent.LaunchMode.TokenActionsOnly) {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
val wallet = getUserWalletUseCase.invokeFlow(mode.userWalletId)
|
val wallet = getUserWalletUseCase.invokeFlow(mode.userWalletId)
|
||||||
.mapNotNull { it.getOrNull() }
|
.mapNotNull { it.getOrNull() }
|
||||||
|
|
@ -206,7 +210,7 @@ internal class AddFundsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initFilteredByRawId(mode: AddFundsComponent.LaunchMode.FilteredByRawId) {
|
private fun initFilteredByRawId(mode: ManageFundsComponent.LaunchMode.FilteredByRawId) {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
val entries = collectFilteredEntries(mode.rawCurrencyId)
|
val entries = collectFilteredEntries(mode.rawCurrencyId)
|
||||||
when (entries.size) {
|
when (entries.size) {
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.tangem.features.commonfeatures.impl.managefunds.model
|
||||||
|
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
|
import com.tangem.features.commonfeatures.impl.R
|
||||||
|
|
||||||
|
internal data class ManageFundsRouteUiSpec(
|
||||||
|
val title: TextReference,
|
||||||
|
val shouldApplyHorizontalPadding: Boolean,
|
||||||
|
val shouldFillHeight: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun ManageFundsModel.UiRoute.uiSpec(flowType: ManageFundsComponent.FlowType): ManageFundsRouteUiSpec {
|
||||||
|
val isTransfer = flowType == ManageFundsComponent.FlowType.Transfer
|
||||||
|
return when (this) {
|
||||||
|
ManageFundsModel.UiRoute.Loading -> ManageFundsRouteUiSpec(
|
||||||
|
title = resourceReference(if (isTransfer) R.string.common_choose_token else R.string.common_add_funds),
|
||||||
|
shouldApplyHorizontalPadding = false,
|
||||||
|
shouldFillHeight = false,
|
||||||
|
)
|
||||||
|
ManageFundsModel.UiRoute.ChooseToken -> ManageFundsRouteUiSpec(
|
||||||
|
title = resourceReference(R.string.common_choose_token),
|
||||||
|
shouldApplyHorizontalPadding = false,
|
||||||
|
shouldFillHeight = true,
|
||||||
|
)
|
||||||
|
ManageFundsModel.UiRoute.UserPortfolio -> ManageFundsRouteUiSpec(
|
||||||
|
title = resourceReference(R.string.common_add_funds),
|
||||||
|
shouldApplyHorizontalPadding = false,
|
||||||
|
shouldFillHeight = false,
|
||||||
|
)
|
||||||
|
ManageFundsModel.UiRoute.TokenActions -> ManageFundsRouteUiSpec(
|
||||||
|
title = resourceReference(if (isTransfer) R.string.common_transfer else R.string.common_get_token),
|
||||||
|
shouldApplyHorizontalPadding = true,
|
||||||
|
shouldFillHeight = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import com.arkivanov.decompose.router.slot.childSlot
|
||||||
import com.arkivanov.decompose.router.slot.dismiss
|
import com.arkivanov.decompose.router.slot.dismiss
|
||||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||||
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
import com.tangem.common.ui.markets.action.TokenActionsBSContentUM
|
||||||
|
import com.tangem.common.ui.markets.action.TokenActionsContext
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.childByContext
|
import com.tangem.core.decompose.context.childByContext
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
|
|
@ -79,6 +80,7 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
||||||
val bottomAction: Flow<BottomAction> = flowOf(BottomAction.None),
|
val bottomAction: Flow<BottomAction> = flowOf(BottomAction.None),
|
||||||
val isRedesignForced: Boolean = false,
|
val isRedesignForced: Boolean = false,
|
||||||
val isCompact: Boolean = false,
|
val isCompact: Boolean = false,
|
||||||
|
val context: TokenActionsContext = TokenActionsContext.Markets,
|
||||||
)
|
)
|
||||||
|
|
||||||
interface Callbacks {
|
interface Callbacks {
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
||||||
cryptoData = cryptoCurrencyData,
|
cryptoData = cryptoCurrencyData,
|
||||||
tokenActionsHandler = tokenActionsHandler,
|
tokenActionsHandler = tokenActionsHandler,
|
||||||
isRedesignEnabled = false,
|
isRedesignEnabled = false,
|
||||||
|
context = params.context,
|
||||||
),
|
),
|
||||||
bottomActionText = bottomActionText(bottomAction),
|
bottomActionText = bottomActionText(bottomAction),
|
||||||
onBottomActionClick = {
|
onBottomActionClick = {
|
||||||
|
|
@ -124,6 +125,7 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
||||||
cryptoData = cryptoCurrencyData,
|
cryptoData = cryptoCurrencyData,
|
||||||
tokenActionsHandler = tokenActionsHandler,
|
tokenActionsHandler = tokenActionsHandler,
|
||||||
isRedesignEnabled = true,
|
isRedesignEnabled = true,
|
||||||
|
context = params.context,
|
||||||
),
|
),
|
||||||
bottomActionText = bottomActionText(bottomAction),
|
bottomActionText = bottomActionText(bottomAction),
|
||||||
onBottomActionClick = {
|
onBottomActionClick = {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.decompose.navigation.Route
|
||||||
import com.tangem.core.ui.DesignFeatureToggles
|
import com.tangem.core.ui.DesignFeatureToggles
|
||||||
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
||||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
||||||
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
import com.tangem.features.feed.components.earn.DefaultEarnComponent
|
import com.tangem.features.feed.components.earn.DefaultEarnComponent
|
||||||
import com.tangem.features.feed.components.feed.DefaultFeedComponent
|
import com.tangem.features.feed.components.feed.DefaultFeedComponent
|
||||||
import com.tangem.features.feed.components.feed.DefaultFeedComponent.FeedParams
|
import com.tangem.features.feed.components.feed.DefaultFeedComponent.FeedParams
|
||||||
|
|
@ -29,7 +30,7 @@ internal class FeedEntryChildFactory @Inject constructor(
|
||||||
private val portfolioComponentFactory: MarketsPortfolioComponent.Factory,
|
private val portfolioComponentFactory: MarketsPortfolioComponent.Factory,
|
||||||
private val portfolioBlockComponentFactory: PortfolioBlockComponent.Factory,
|
private val portfolioBlockComponentFactory: PortfolioBlockComponent.Factory,
|
||||||
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
||||||
private val addFundsComponentFactory: com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent.Factory,
|
private val manageFundsComponentFactory: ManageFundsComponent.Factory,
|
||||||
private val promoBannersBlockComponentFactory: PromoBannersBlockComponent.Factory,
|
private val promoBannersBlockComponentFactory: PromoBannersBlockComponent.Factory,
|
||||||
private val designFeatureToggles: DesignFeatureToggles,
|
private val designFeatureToggles: DesignFeatureToggles,
|
||||||
) {
|
) {
|
||||||
|
|
@ -84,7 +85,7 @@ internal class FeedEntryChildFactory @Inject constructor(
|
||||||
portfolioBlockComponentFactory = portfolioBlockComponentFactory,
|
portfolioBlockComponentFactory = portfolioBlockComponentFactory,
|
||||||
designFeatureToggles = designFeatureToggles,
|
designFeatureToggles = designFeatureToggles,
|
||||||
addToPortfolioComponentFactory = addToPortfolioComponentFactory,
|
addToPortfolioComponentFactory = addToPortfolioComponentFactory,
|
||||||
addFundsComponentFactory = addFundsComponentFactory,
|
manageFundsComponentFactory = manageFundsComponentFactory,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is Child.TokenList -> {
|
is Child.TokenList -> {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
||||||
import com.tangem.domain.markets.TokenMarketParams
|
import com.tangem.domain.markets.TokenMarketParams
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
||||||
import com.tangem.features.feed.components.market.details.portfolio.api.MarketsPortfolioComponent
|
import com.tangem.features.feed.components.market.details.portfolio.api.MarketsPortfolioComponent
|
||||||
import com.tangem.features.feed.components.market.details.portfolioblock.PortfolioBlockComponent
|
import com.tangem.features.feed.components.market.details.portfolioblock.PortfolioBlockComponent
|
||||||
|
|
@ -66,7 +66,7 @@ internal class DefaultMarketsTokenDetailsComponent(
|
||||||
portfolioBlockComponentFactory: PortfolioBlockComponent.Factory,
|
portfolioBlockComponentFactory: PortfolioBlockComponent.Factory,
|
||||||
val params: Params,
|
val params: Params,
|
||||||
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
private val addToPortfolioComponentFactory: AddToPortfolioComponent.Factory,
|
||||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
private val manageFundsComponentFactory: ManageFundsComponent.Factory,
|
||||||
) : ComposableModularBottomSheetContentComponent, AppComponentContext by appComponentContext {
|
) : ComposableModularBottomSheetContentComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
// applying l2 compatibility
|
// applying l2 compatibility
|
||||||
|
|
@ -174,10 +174,10 @@ internal class DefaultMarketsTokenDetailsComponent(
|
||||||
config: AddFundsSlotRoute,
|
config: AddFundsSlotRoute,
|
||||||
componentContext: ComponentContext,
|
componentContext: ComponentContext,
|
||||||
): ComposableBottomSheetComponent {
|
): ComposableBottomSheetComponent {
|
||||||
val launchMode = AddFundsComponent.LaunchMode.FilteredByRawId(rawCurrencyId = config.rawCurrencyId)
|
val launchMode = ManageFundsComponent.LaunchMode.FilteredByRawId(rawCurrencyId = config.rawCurrencyId)
|
||||||
return addFundsComponentFactory.create(
|
return manageFundsComponentFactory.create(
|
||||||
context = childByContext(componentContext),
|
context = childByContext(componentContext),
|
||||||
params = AddFundsComponent.Params(
|
params = ManageFundsComponent.Params(
|
||||||
launchMode = launchMode,
|
launchMode = launchMode,
|
||||||
onDismiss = { model.addFundsSheetNavigation.dismiss() },
|
onDismiss = { model.addFundsSheetNavigation.dismiss() },
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ interface SendEntryPointComponent : ComposableContentComponent {
|
||||||
data class Params(
|
data class Params(
|
||||||
val userWalletId: UserWalletId,
|
val userWalletId: UserWalletId,
|
||||||
val cryptoCurrency: CryptoCurrency,
|
val cryptoCurrency: CryptoCurrency,
|
||||||
|
val shouldStartWithSwap: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
interface Factory : ComponentFactory<Params, SendEntryPointComponent>
|
interface Factory : ComponentFactory<Params, SendEntryPointComponent>
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,11 @@ internal class DefaultSendEntryPointComponent @AssistedInject constructor(
|
||||||
model.currentRoute.emit(stack.active.configuration)
|
model.currentRoute.emit(stack.active.configuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (params.shouldStartWithSwap) {
|
||||||
|
// Direct Swap&Send entry: replicate the canonical "send with swap" trigger so the receive-token
|
||||||
|
// selector opens like the regular Send -> Send&Swap flow (this was the less-broken behaviour).
|
||||||
|
model.onConvertToAnotherToken(lastAmount = "", isEnterInFiatSelected = false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -565,12 +565,11 @@ internal class SwapAmountModel @Inject constructor(
|
||||||
(params as? SwapAmountComponentParams.AmountParams)?.callback?.resetSendWithSwapNavigation(
|
(params as? SwapAmountComponentParams.AmountParams)?.callback?.resetSendWithSwapNavigation(
|
||||||
data.shouldResetNavigation,
|
data.shouldResetNavigation,
|
||||||
)
|
)
|
||||||
|
ensurePrimaryReady()
|
||||||
|
initPairs(data.swapCurrencies, data.cryptoCurrency)
|
||||||
uiState.update { amountUM ->
|
uiState.update { amountUM ->
|
||||||
if (amountUM is SwapAmountUM.Content) {
|
if (amountUM is SwapAmountUM.Content) {
|
||||||
initPairs(data.swapCurrencies, data.cryptoCurrency)
|
amountUM.copy(isPrimaryButtonEnabled = false)
|
||||||
amountUM.copy(
|
|
||||||
isPrimaryButtonEnabled = false,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
amountUM
|
amountUM
|
||||||
}
|
}
|
||||||
|
|
@ -579,6 +578,32 @@ internal class SwapAmountModel @Inject constructor(
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces the amount UI into the primary-ready [SwapAmountUM.Content] state using the current primary
|
||||||
|
* status. Needed for the direct Send-with-Swap (Swap&Send) entry where the state can be [SwapAmountUM.Empty] and
|
||||||
|
* the balance-`distinctUntilChanged` primary status flow won't re-emit to rebuild it. No-op when already Content.
|
||||||
|
*/
|
||||||
|
private suspend fun ensurePrimaryReady() {
|
||||||
|
if (uiState.value is SwapAmountUM.Content) return
|
||||||
|
val primaryCurrencyStatus = params.primaryCryptoCurrencyStatusFlow.value
|
||||||
|
initCurrencies(primaryStatus = primaryCurrencyStatus, secondaryStatus = null)
|
||||||
|
val isOnlyOneWallet = getWalletsUseCase.invokeSync().size == 1
|
||||||
|
uiState.transformerUpdate(
|
||||||
|
SwapAmountPrimaryReadyStateTransformer(
|
||||||
|
userWallet = userWallet,
|
||||||
|
primaryCryptoCurrencyStatus = primaryCurrencyStatus,
|
||||||
|
appCurrency = appCurrency,
|
||||||
|
swapDirection = swapDirection,
|
||||||
|
clickIntents = this,
|
||||||
|
isBalanceHidden = params.isBalanceHidingFlow.value,
|
||||||
|
isShowBestRateAnimation = isShowBestRateAnimation,
|
||||||
|
isSingleWallet = isOnlyOneWallet,
|
||||||
|
isAccountsMode = params.isAccountModeFlow.value,
|
||||||
|
account = params.accountFlow.value,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun initPairs(swapCurrencies: SwapCurrencies, secondaryCryptoCurrency: CryptoCurrency?) {
|
private fun initPairs(swapCurrencies: SwapCurrencies, secondaryCryptoCurrency: CryptoCurrency?) {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
val secondaryCurrency = selectInitialPairUseCase(
|
val secondaryCurrency = selectInitialPairUseCase(
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@ package com.tangem.features.tokendetails
|
||||||
|
|
||||||
interface TokenDetailsFeatureToggles {
|
interface TokenDetailsFeatureToggles {
|
||||||
val isQuickTopUpEnabled: Boolean
|
val isQuickTopUpEnabled: Boolean
|
||||||
|
val isManageFundsEnabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.route.TokenDeta
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreenLegacy
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreenLegacy
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.ChooseAddressBottomSheetComponent
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.ChooseAddressBottomSheetComponent
|
||||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.TransferBottomSheetComponent
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.TransferBottomSheetComponent
|
||||||
|
|
@ -47,7 +47,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
||||||
expressTransactionsComponentFactory: ExpressTransactionsComponent.Factory,
|
expressTransactionsComponentFactory: ExpressTransactionsComponent.Factory,
|
||||||
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
||||||
private val yieldSupplyWarningComponentFactory: YieldSupplyDepositedWarningComponent.Factory,
|
private val yieldSupplyWarningComponentFactory: YieldSupplyDepositedWarningComponent.Factory,
|
||||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
private val manageFundsComponentFactory: ManageFundsComponent.Factory,
|
||||||
yieldSupplyComponentFactory: YieldSupplyComponent.Factory,
|
yieldSupplyComponentFactory: YieldSupplyComponent.Factory,
|
||||||
private val ratingComponentFactory: RatingComponent.Factory,
|
private val ratingComponentFactory: RatingComponent.Factory,
|
||||||
) : TokenDetailsComponent, AppComponentContext by appComponentContext {
|
) : TokenDetailsComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
@ -178,10 +178,10 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
||||||
dynamicAddressesDelegate = model.dynamicAddressesDelegate,
|
dynamicAddressesDelegate = model.dynamicAddressesDelegate,
|
||||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||||
)
|
)
|
||||||
is TokenDetailsBottomSheetConfig.AddFunds -> addFundsComponentFactory.create(
|
is TokenDetailsBottomSheetConfig.AddFunds -> manageFundsComponentFactory.create(
|
||||||
context = childByContext(componentContext),
|
context = childByContext(componentContext),
|
||||||
params = AddFundsComponent.Params(
|
params = ManageFundsComponent.Params(
|
||||||
launchMode = AddFundsComponent.LaunchMode.TokenActionsOnly(
|
launchMode = ManageFundsComponent.LaunchMode.TokenActionsOnly(
|
||||||
userWalletId = route.userWalletId,
|
userWalletId = route.userWalletId,
|
||||||
currency = route.currency,
|
currency = route.currency,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,13 @@ import com.tangem.features.tokendetails.TokenDetailsFeatureToggles
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class DefaultTokenDetailsFeatureToggles @Inject constructor(
|
internal class DefaultTokenDetailsFeatureToggles @Inject constructor(
|
||||||
featureTogglesManager: FeatureTogglesManager,
|
private val featureTogglesManager: FeatureTogglesManager,
|
||||||
) : TokenDetailsFeatureToggles {
|
) : TokenDetailsFeatureToggles {
|
||||||
|
|
||||||
override val isQuickTopUpEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
|
override val isQuickTopUpEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
|
||||||
toggle = FeatureToggles.AND_15258_QUICK_TOP_UP_ENABLED,
|
toggle = FeatureToggles.AND_15258_QUICK_TOP_UP_ENABLED,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override val isManageFundsEnabled: Boolean
|
||||||
|
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1377_MANAGE_FUNDS)
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,8 @@ interface TokenDetailsClickIntents {
|
||||||
|
|
||||||
fun onSwapFromClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
fun onSwapFromClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
||||||
|
|
||||||
|
fun onSwapAndSendClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
||||||
|
|
||||||
fun onSwapToClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
fun onSwapToClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
||||||
|
|
||||||
fun onBuyClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
fun onBuyClick(unavailabilityReason: ScenarioUnavailabilityReason)
|
||||||
|
|
@ -151,6 +153,8 @@ internal class EmptyTokenDetailsClickIntents : TokenDetailsClickIntents {
|
||||||
|
|
||||||
override fun onSwapFromClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ }
|
override fun onSwapFromClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ }
|
||||||
|
|
||||||
|
override fun onSwapAndSendClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ }
|
||||||
|
|
||||||
override fun onSwapToClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ }
|
override fun onSwapToClick(unavailabilityReason: ScenarioUnavailabilityReason) { /* no op */ }
|
||||||
|
|
||||||
override fun onHideClick() { /* no op */ }
|
override fun onHideClick() { /* no op */ }
|
||||||
|
|
|
||||||
|
|
@ -599,6 +599,15 @@ internal class TokenDetailsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTransferClick() {
|
override fun onTransferClick() {
|
||||||
|
val amount = cryptoCurrencyStatus?.value?.amount
|
||||||
|
if (amount == null || amount.signum() <= 0) {
|
||||||
|
uiMessageSender.send(
|
||||||
|
message = SnackbarMessage(
|
||||||
|
message = resourceReference(R.string.token_button_unavailability_reason_empty_balance_send),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
bottomSheetNavigation.activate(TokenDetailsBottomSheetConfig.Transfer)
|
bottomSheetNavigation.activate(TokenDetailsBottomSheetConfig.Transfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -832,6 +841,20 @@ internal class TokenDetailsModel @Inject constructor(
|
||||||
handleSwap(unavailabilityReason, AppRoute.Swap.CurrencyPosition.FROM, checkYieldSupply = true)
|
handleSwap(unavailabilityReason, AppRoute.Swap.CurrencyPosition.FROM, checkYieldSupply = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSwapAndSendClick(unavailabilityReason: ScenarioUnavailabilityReason) {
|
||||||
|
if (handleUnavailabilityReason(unavailabilityReason = unavailabilityReason)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
appRouter.push(
|
||||||
|
AppRoute.SendEntryPoint(
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
currency = cryptoCurrency,
|
||||||
|
shouldStartWithSwap = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSwapToClick(unavailabilityReason: ScenarioUnavailabilityReason) {
|
override fun onSwapToClick(unavailabilityReason: ScenarioUnavailabilityReason) {
|
||||||
handleSwap(unavailabilityReason, AppRoute.Swap.CurrencyPosition.TO, checkYieldSupply = false)
|
handleSwap(unavailabilityReason, AppRoute.Swap.CurrencyPosition.TO, checkYieldSupply = false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ internal sealed interface TransferUM : TangemBottomSheetConfigContent {
|
||||||
data class Content(
|
data class Content(
|
||||||
val send: Row?,
|
val send: Row?,
|
||||||
val swap: Row?,
|
val swap: Row?,
|
||||||
|
val swapAndSend: Row?,
|
||||||
val sell: Row?,
|
val sell: Row?,
|
||||||
) : TransferUM
|
) : TransferUM
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,16 @@ internal class UpdateTransferTransformer(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val swapAndSendRow = swapAction?.let { action ->
|
||||||
|
TransferUM.Row(
|
||||||
|
isLoading = action.unavailabilityReason.isLoading,
|
||||||
|
isEnabled = action.unavailabilityReason == ScenarioUnavailabilityReason.None,
|
||||||
|
onClick = {
|
||||||
|
onActionDispatched()
|
||||||
|
clickIntents.onSwapAndSendClick(action.unavailabilityReason)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
val sellRow = sellAction?.let { action ->
|
val sellRow = sellAction?.let { action ->
|
||||||
TransferUM.Row(
|
TransferUM.Row(
|
||||||
isLoading = action.unavailabilityReason.isOutdatedLoading(),
|
isLoading = action.unavailabilityReason.isOutdatedLoading(),
|
||||||
|
|
@ -55,7 +65,12 @@ internal class UpdateTransferTransformer(
|
||||||
}
|
}
|
||||||
|
|
||||||
return prevState.copy(
|
return prevState.copy(
|
||||||
transferUM = TransferUM.Content(send = sendRow, swap = swapRow, sell = sellRow),
|
transferUM = TransferUM.Content(
|
||||||
|
send = sendRow,
|
||||||
|
swap = swapRow,
|
||||||
|
swapAndSend = swapAndSendRow,
|
||||||
|
sell = sellRow,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ internal fun TransferBottomSheetContent(state: TransferUM, onCloseClick: () -> U
|
||||||
) {
|
) {
|
||||||
SendActionRow(state = state)
|
SendActionRow(state = state)
|
||||||
SwapActionRow(state = state)
|
SwapActionRow(state = state)
|
||||||
|
SwapAndSendActionRow(state = state)
|
||||||
SellActionRow(state = state)
|
SellActionRow(state = state)
|
||||||
|
|
||||||
SpacerH(TangemTheme.dimens2.x2)
|
SpacerH(TangemTheme.dimens2.x2)
|
||||||
|
|
@ -80,6 +81,19 @@ private fun SwapActionRow(state: TransferUM) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SwapAndSendActionRow(state: TransferUM) {
|
||||||
|
val row = (state as? TransferUM.Content)?.swapAndSend
|
||||||
|
if (state is TransferUM.Content && row == null) return
|
||||||
|
ActionRow(
|
||||||
|
iconRes = CoreR.drawable.ic_exchange_mini_24,
|
||||||
|
title = resourceReference(CoreR.string.common_send_with_swap),
|
||||||
|
description = resourceReference(CoreR.string.quick_action_send_and_swap_description),
|
||||||
|
row = row,
|
||||||
|
isLoading = state is TransferUM.Loading,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SellActionRow(state: TransferUM) {
|
private fun SellActionRow(state: TransferUM) {
|
||||||
val row = (state as? TransferUM.Content)?.sell
|
val row = (state as? TransferUM.Content)?.sell
|
||||||
|
|
@ -149,16 +163,19 @@ private class TransferPreviewProvider : PreviewParameterProvider<TransferUM> {
|
||||||
TransferUM.Content(
|
TransferUM.Content(
|
||||||
send = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
send = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||||
swap = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
swap = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||||
|
swapAndSend = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||||
sell = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
sell = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||||
),
|
),
|
||||||
TransferUM.Content(
|
TransferUM.Content(
|
||||||
send = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
send = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||||
swap = TransferUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
swap = TransferUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
||||||
|
swapAndSend = TransferUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
||||||
sell = TransferUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
sell = TransferUM.Row(isLoading = false, isEnabled = false, onClick = {}),
|
||||||
),
|
),
|
||||||
TransferUM.Content(
|
TransferUM.Content(
|
||||||
send = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
send = TransferUM.Row(isLoading = false, isEnabled = true, onClick = {}),
|
||||||
swap = null,
|
swap = null,
|
||||||
|
swapAndSend = null,
|
||||||
sell = null,
|
sell = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,57 @@ class UpdateTransferTransformerTest {
|
||||||
assertThat(content.swap?.isEnabled).isTrue()
|
assertThat(content.swap?.isEnabled).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN Swap action available WHEN transform THEN swapAndSend row is not null`() {
|
||||||
|
// Arrange
|
||||||
|
val transformer = createTransformer(
|
||||||
|
actions = listOf(TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, false)),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = transformer.transform(initialState())
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val content = result.transferUM as TransferUM.Content
|
||||||
|
assertThat(content.swapAndSend).isNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN Swap action available WHEN swapAndSend onClick invoked THEN onSwapAndSendClick is called`() {
|
||||||
|
// Arrange
|
||||||
|
val transformer = createTransformer(
|
||||||
|
actions = listOf(TokenActionsState.ActionState.Swap(ScenarioUnavailabilityReason.None, false)),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val content = transformer.transform(initialState()).transferUM as TransferUM.Content
|
||||||
|
content.swapAndSend!!.onClick()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verifyOrder {
|
||||||
|
onActionDispatched.invoke()
|
||||||
|
clickIntents.onSwapAndSendClick(ScenarioUnavailabilityReason.None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN no Swap action WHEN transform THEN swapAndSend row is null`() {
|
||||||
|
// Arrange
|
||||||
|
val transformer = createTransformer(
|
||||||
|
actions = listOf(
|
||||||
|
TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.None),
|
||||||
|
TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.None),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = transformer.transform(initialState())
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val content = result.transferUM as TransferUM.Content
|
||||||
|
assertThat(content.swapAndSend).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN row WHEN not clicked THEN no callbacks fire`() {
|
fun `GIVEN row WHEN not clicked THEN no callbacks fire`() {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,6 @@ interface WalletFeatureToggles {
|
||||||
val isAddAndManageTokensEnabled: Boolean
|
val isAddAndManageTokensEnabled: Boolean
|
||||||
|
|
||||||
val isAddFundsStage1Enabled: Boolean
|
val isAddFundsStage1Enabled: Boolean
|
||||||
|
|
||||||
|
val isManageFundsEnabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ import com.tangem.core.ui.utils.parseBigDecimal
|
||||||
import com.tangem.domain.tokens.model.details.TokenAction
|
import com.tangem.domain.tokens.model.details.TokenAction
|
||||||
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
|
||||||
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
||||||
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
|
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
|
||||||
import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
|
import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
|
||||||
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
|
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
|
||||||
import com.tangem.feature.wallet.child.wallet.model.WalletModel
|
import com.tangem.feature.wallet.child.wallet.model.WalletModel
|
||||||
|
|
@ -70,7 +70,7 @@ internal class WalletComponent @AssistedInject constructor(
|
||||||
private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
|
private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
|
||||||
private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
|
||||||
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||||
private val addFundsComponentFactory: AddFundsComponent.Factory,
|
private val manageFundsComponentFactory: ManageFundsComponent.Factory,
|
||||||
private val designFeatureToggles: DesignFeatureToggles,
|
private val designFeatureToggles: DesignFeatureToggles,
|
||||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
|
|
@ -191,10 +191,20 @@ internal class WalletComponent @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is WalletDialogConfig.AddFunds -> {
|
is WalletDialogConfig.AddFunds -> {
|
||||||
addFundsComponentFactory.create(
|
manageFundsComponentFactory.create(
|
||||||
context = childByContext(componentContext),
|
context = childByContext(componentContext),
|
||||||
params = AddFundsComponent.Params(
|
params = ManageFundsComponent.Params(
|
||||||
launchMode = AddFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
|
launchMode = ManageFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
|
||||||
|
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is WalletDialogConfig.Transfer -> {
|
||||||
|
manageFundsComponentFactory.create(
|
||||||
|
context = childByContext(componentContext),
|
||||||
|
params = ManageFundsComponent.Params(
|
||||||
|
launchMode = ManageFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
|
||||||
|
flowType = ManageFundsComponent.FlowType.Transfer,
|
||||||
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -566,6 +566,7 @@ internal class WalletModel @Inject constructor(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -613,6 +614,7 @@ internal class WalletModel @Inject constructor(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -635,6 +637,7 @@ internal class WalletModel @Inject constructor(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -650,6 +653,7 @@ internal class WalletModel @Inject constructor(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -712,6 +716,7 @@ internal class WalletModel @Inject constructor(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = walletFeatureToggles.isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = walletFeatureToggles.isManageFundsEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,10 @@ internal class WalletClickIntents @Inject constructor(
|
||||||
router.openAddFunds(userWalletId)
|
router.openAddFunds(userWalletId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onTransferClick(userWalletId: UserWalletId) {
|
||||||
|
router.openTransfer(userWalletId)
|
||||||
|
}
|
||||||
|
|
||||||
fun onAddFundsPromoClick(userWalletId: UserWalletId) {
|
fun onAddFundsPromoClick(userWalletId: UserWalletId) {
|
||||||
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.ButtonAddFundsPromo())
|
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.ButtonAddFundsPromo())
|
||||||
router.openAddFunds(userWalletId)
|
router.openAddFunds(userWalletId)
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,7 @@ internal class DefaultWalletFeatureToggles @Inject constructor(
|
||||||
|
|
||||||
override val isAddFundsStage1Enabled: Boolean
|
override val isAddFundsStage1Enabled: Boolean
|
||||||
get() = featureToggles.isFeatureEnabled(FeatureToggles.AND_15310_ADD_FUNDS_STAGE1)
|
get() = featureToggles.isFeatureEnabled(FeatureToggles.AND_15310_ADD_FUNDS_STAGE1)
|
||||||
|
|
||||||
|
override val isManageFundsEnabled: Boolean
|
||||||
|
get() = featureToggles.isFeatureEnabled(FeatureToggles.TWI_1377_MANAGE_FUNDS)
|
||||||
}
|
}
|
||||||
|
|
@ -125,6 +125,12 @@ internal class DefaultWalletRouter @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openTransfer(userWalletId: UserWalletId) {
|
||||||
|
dialogNavigation.activate(
|
||||||
|
configuration = WalletDialogConfig.Transfer(userWalletId = userWalletId),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun isWalletLastScreen(): Boolean {
|
override fun isWalletLastScreen(): Boolean {
|
||||||
return router.stack.lastOrNull() is AppRoute.Wallet
|
return router.stack.lastOrNull() is AppRoute.Wallet
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,4 +120,7 @@ internal interface InnerWalletRouter {
|
||||||
|
|
||||||
/** Open Add Funds screen */
|
/** Open Add Funds screen */
|
||||||
fun openAddFunds(userWalletId: UserWalletId)
|
fun openAddFunds(userWalletId: UserWalletId)
|
||||||
|
|
||||||
|
/** Open Transfer screen */
|
||||||
|
fun openTransfer(userWalletId: UserWalletId)
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ internal sealed class WalletActionButtons(
|
||||||
override val isEnabled: Boolean,
|
override val isEnabled: Boolean,
|
||||||
) : WalletActionButtons(
|
) : WalletActionButtons(
|
||||||
text = resourceReference(R.string.common_add_funds),
|
text = resourceReference(R.string.common_add_funds),
|
||||||
iconRes = R.drawable.ic_plus_default_24,
|
iconRes = R.drawable.ic_arrow_down_24,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Swap(
|
data class Swap(
|
||||||
|
|
@ -74,4 +74,12 @@ internal sealed class WalletActionButtons(
|
||||||
text = resourceReference(R.string.common_sell),
|
text = resourceReference(R.string.common_sell),
|
||||||
iconRes = R.drawable.ic_dollar_default_24,
|
iconRes = R.drawable.ic_dollar_default_24,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class Transfer(
|
||||||
|
override val onClick: () -> Unit,
|
||||||
|
override val isEnabled: Boolean,
|
||||||
|
) : WalletActionButtons(
|
||||||
|
text = resourceReference(R.string.common_transfer),
|
||||||
|
iconRes = R.drawable.ic_arrow_up_24,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -65,6 +65,9 @@ internal sealed interface WalletDialogConfig {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class AddFunds(val userWalletId: UserWalletId) : WalletDialogConfig
|
data class AddFunds(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Transfer(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class OrganizeTokens(val userWalletId: UserWalletId) : WalletDialogConfig
|
data class OrganizeTokens(val userWalletId: UserWalletId) : WalletDialogConfig
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
|
||||||
) : WalletManageButton(
|
) : WalletManageButton(
|
||||||
config = ActionButtonConfig(
|
config = ActionButtonConfig(
|
||||||
text = TextReference.Res(id = R.string.common_add_funds),
|
text = TextReference.Res(id = R.string.common_add_funds),
|
||||||
iconResId = R.drawable.ic_plus_24,
|
iconResId = R.drawable.ic_arrow_down_24,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
isEnabled = enabled,
|
isEnabled = enabled,
|
||||||
shouldDimContent = dimContent,
|
shouldDimContent = dimContent,
|
||||||
|
|
@ -145,6 +145,29 @@ internal sealed class WalletManageButton(val config: ActionButtonConfig) {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer
|
||||||
|
*
|
||||||
|
* @property enabled button click availability
|
||||||
|
* @property dimContent determines whether the button content will be dimmed
|
||||||
|
* @property onClick lambda be invoked when Transfer button is clicked
|
||||||
|
*/
|
||||||
|
data class Transfer(
|
||||||
|
override val enabled: Boolean,
|
||||||
|
override val dimContent: Boolean,
|
||||||
|
override val onClick: () -> Unit,
|
||||||
|
val isInProgress: Boolean = false,
|
||||||
|
) : WalletManageButton(
|
||||||
|
config = ActionButtonConfig(
|
||||||
|
text = TextReference.Res(id = R.string.common_transfer),
|
||||||
|
iconResId = R.drawable.ic_arrow_up_24,
|
||||||
|
onClick = onClick,
|
||||||
|
isEnabled = enabled,
|
||||||
|
shouldDimContent = dimContent,
|
||||||
|
isInProgress = isInProgress,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swap
|
* Swap
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ internal class AddWalletTransformer(
|
||||||
private val walletImageResolver: WalletImageResolver,
|
private val walletImageResolver: WalletImageResolver,
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val isAddFundsStage1Enabled: Boolean,
|
private val isAddFundsStage1Enabled: Boolean,
|
||||||
|
private val isManageFundsEnabled: Boolean,
|
||||||
) : WalletScreenStateTransformer {
|
) : WalletScreenStateTransformer {
|
||||||
|
|
||||||
private val walletLoadingStateFactory by lazy {
|
private val walletLoadingStateFactory by lazy {
|
||||||
|
|
@ -22,6 +23,7 @@ internal class AddWalletTransformer(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = isManageFundsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toPersistentList
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
import com.tangem.core.ui.R as CoreUiR
|
import com.tangem.core.ui.R as CoreUiR
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
internal class InitializeWalletsTransformer(
|
internal class InitializeWalletsTransformer(
|
||||||
private val selectedWalletIndex: Int,
|
private val selectedWalletIndex: Int,
|
||||||
private val wallets: List<UserWallet>,
|
private val wallets: List<UserWallet>,
|
||||||
|
|
@ -28,6 +29,7 @@ internal class InitializeWalletsTransformer(
|
||||||
private val walletImageResolver: WalletImageResolver,
|
private val walletImageResolver: WalletImageResolver,
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val isAddFundsStage1Enabled: Boolean,
|
private val isAddFundsStage1Enabled: Boolean,
|
||||||
|
private val isManageFundsEnabled: Boolean,
|
||||||
) : WalletScreenStateTransformer {
|
) : WalletScreenStateTransformer {
|
||||||
|
|
||||||
private val walletLoadingStateFactory by lazy {
|
private val walletLoadingStateFactory by lazy {
|
||||||
|
|
@ -36,6 +38,7 @@ internal class InitializeWalletsTransformer(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = isManageFundsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,10 +162,16 @@ internal class InitializeWalletsTransformer(
|
||||||
WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {})
|
WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val lastButton = if (isManageFundsEnabled) {
|
||||||
|
WalletManageButton.Transfer(enabled = false, dimContent = false, onClick = {})
|
||||||
|
} else {
|
||||||
|
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {})
|
||||||
|
}
|
||||||
|
|
||||||
return persistentListOf(
|
return persistentListOf(
|
||||||
firstButton,
|
firstButton,
|
||||||
WalletManageButton.Swap(enabled = false, dimContent = false, onClick = {}),
|
WalletManageButton.Swap(enabled = false, dimContent = false, onClick = {}),
|
||||||
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {}),
|
lastButton,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,12 +199,21 @@ internal class InitializeWalletsTransformer(
|
||||||
onClick = {},
|
onClick = {},
|
||||||
).buttonUM,
|
).buttonUM,
|
||||||
)
|
)
|
||||||
add(
|
if (isManageFundsEnabled) {
|
||||||
WalletActionButtons.Sell(
|
add(
|
||||||
isEnabled = false,
|
WalletActionButtons.Transfer(
|
||||||
onClick = {},
|
isEnabled = false,
|
||||||
).buttonUM,
|
onClick = {},
|
||||||
)
|
).buttonUM,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
add(
|
||||||
|
WalletActionButtons.Sell(
|
||||||
|
isEnabled = false,
|
||||||
|
onClick = {},
|
||||||
|
).buttonUM,
|
||||||
|
)
|
||||||
|
}
|
||||||
}.toPersistentList()
|
}.toPersistentList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||||
*
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
|
@Suppress("LongParameterList")
|
||||||
internal class ReinitializeNewWalletTransformer(
|
internal class ReinitializeNewWalletTransformer(
|
||||||
private val prevWalletId: UserWalletId,
|
private val prevWalletId: UserWalletId,
|
||||||
private val newUserWallet: UserWallet,
|
private val newUserWallet: UserWallet,
|
||||||
|
|
@ -25,6 +26,7 @@ internal class ReinitializeNewWalletTransformer(
|
||||||
private val walletImageResolver: WalletImageResolver,
|
private val walletImageResolver: WalletImageResolver,
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val isAddFundsStage1Enabled: Boolean,
|
private val isAddFundsStage1Enabled: Boolean,
|
||||||
|
private val isManageFundsEnabled: Boolean,
|
||||||
) : WalletScreenStateTransformer {
|
) : WalletScreenStateTransformer {
|
||||||
|
|
||||||
private val walletLoadingStateFactory by lazy {
|
private val walletLoadingStateFactory by lazy {
|
||||||
|
|
@ -33,6 +35,7 @@ internal class ReinitializeNewWalletTransformer(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = isManageFundsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ internal class ReinitializeWalletTransformer(
|
||||||
private val walletImageResolver: WalletImageResolver,
|
private val walletImageResolver: WalletImageResolver,
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val isAddFundsStage1Enabled: Boolean,
|
private val isAddFundsStage1Enabled: Boolean,
|
||||||
|
private val isManageFundsEnabled: Boolean,
|
||||||
) : WalletStateTransformer(userWalletId = userWallet.walletId) {
|
) : WalletStateTransformer(userWalletId = userWallet.walletId) {
|
||||||
|
|
||||||
private val walletLoadingStateFactory by lazy {
|
private val walletLoadingStateFactory by lazy {
|
||||||
|
|
@ -29,6 +30,7 @@ internal class ReinitializeWalletTransformer(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = isManageFundsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ internal class SetRefreshStateTransformer(
|
||||||
is WalletManageButton.AddFunds -> button.copy(enabled = isButtonsEnabled)
|
is WalletManageButton.AddFunds -> button.copy(enabled = isButtonsEnabled)
|
||||||
is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled)
|
is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled)
|
||||||
is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled)
|
is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled)
|
||||||
|
is WalletManageButton.Transfer -> button.copy(enabled = isButtonsEnabled)
|
||||||
is WalletManageButton.Receive -> button
|
is WalletManageButton.Receive -> button
|
||||||
is WalletManageButton.Stake -> null
|
is WalletManageButton.Stake -> null
|
||||||
is WalletManageButton.Swap -> null
|
is WalletManageButton.Swap -> null
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ internal class UnlockWalletTransformer(
|
||||||
private val walletImageResolver: WalletImageResolver,
|
private val walletImageResolver: WalletImageResolver,
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val isAddFundsStage1Enabled: Boolean,
|
private val isAddFundsStage1Enabled: Boolean,
|
||||||
|
private val isManageFundsEnabled: Boolean,
|
||||||
) : WalletScreenStateTransformer {
|
) : WalletScreenStateTransformer {
|
||||||
|
|
||||||
private val walletLoadingStateFactory by lazy {
|
private val walletLoadingStateFactory by lazy {
|
||||||
|
|
@ -27,6 +28,7 @@ internal class UnlockWalletTransformer(
|
||||||
walletImageResolver = walletImageResolver,
|
walletImageResolver = walletImageResolver,
|
||||||
getWalletIconUseCase = getWalletIconUseCase,
|
getWalletIconUseCase = getWalletIconUseCase,
|
||||||
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
isAddFundsStage1Enabled = isAddFundsStage1Enabled,
|
||||||
|
isManageFundsEnabled = isManageFundsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ private fun WalletState.MultiCurrency.Content.changeAvailability(enabled: Boolea
|
||||||
is WalletManageButton.Buy -> action.copy(enabled = enabled)
|
is WalletManageButton.Buy -> action.copy(enabled = enabled)
|
||||||
is WalletManageButton.AddFunds -> action.copy(enabled = enabled)
|
is WalletManageButton.AddFunds -> action.copy(enabled = enabled)
|
||||||
is WalletManageButton.Sell -> action.copy(enabled = enabled)
|
is WalletManageButton.Sell -> action.copy(enabled = enabled)
|
||||||
|
is WalletManageButton.Transfer -> action.copy(enabled = enabled)
|
||||||
is WalletManageButton.Swap -> action.copy(enabled = enabled)
|
is WalletManageButton.Swap -> action.copy(enabled = enabled)
|
||||||
else -> action
|
else -> action
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ internal class WalletLoadingStateFactory(
|
||||||
private val walletImageResolver: WalletImageResolver,
|
private val walletImageResolver: WalletImageResolver,
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val isAddFundsStage1Enabled: Boolean,
|
private val isAddFundsStage1Enabled: Boolean,
|
||||||
|
private val isManageFundsEnabled: Boolean,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(userWallet: UserWallet): WalletState {
|
fun create(userWallet: UserWallet): WalletState {
|
||||||
|
|
@ -171,6 +172,20 @@ internal class WalletLoadingStateFactory(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val lastButton = if (isManageFundsEnabled) {
|
||||||
|
WalletManageButton.Transfer(
|
||||||
|
enabled = true,
|
||||||
|
dimContent = false,
|
||||||
|
onClick = { clickIntents.onTransferClick(userWallet.walletId) },
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
WalletManageButton.Sell(
|
||||||
|
enabled = true,
|
||||||
|
dimContent = false,
|
||||||
|
onClick = { clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return persistentListOf(
|
return persistentListOf(
|
||||||
firstButton,
|
firstButton,
|
||||||
WalletManageButton.Swap(
|
WalletManageButton.Swap(
|
||||||
|
|
@ -178,11 +193,7 @@ internal class WalletLoadingStateFactory(
|
||||||
dimContent = false,
|
dimContent = false,
|
||||||
onClick = { clickIntents.onMultiWalletSwapClick(userWalletId = userWallet.walletId) },
|
onClick = { clickIntents.onMultiWalletSwapClick(userWalletId = userWallet.walletId) },
|
||||||
),
|
),
|
||||||
WalletManageButton.Sell(
|
lastButton,
|
||||||
enabled = true,
|
|
||||||
dimContent = false,
|
|
||||||
onClick = { clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId) },
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,14 +216,25 @@ internal class WalletLoadingStateFactory(
|
||||||
},
|
},
|
||||||
).buttonUM,
|
).buttonUM,
|
||||||
)
|
)
|
||||||
add(
|
if (isManageFundsEnabled) {
|
||||||
WalletActionButtons.Sell(
|
add(
|
||||||
isEnabled = false,
|
WalletActionButtons.Transfer(
|
||||||
onClick = {
|
isEnabled = false,
|
||||||
clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId)
|
onClick = {
|
||||||
},
|
clickIntents.onTransferClick(userWalletId = userWallet.walletId)
|
||||||
).buttonUM,
|
},
|
||||||
)
|
).buttonUM,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
add(
|
||||||
|
WalletActionButtons.Sell(
|
||||||
|
isEnabled = false,
|
||||||
|
onClick = {
|
||||||
|
clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId)
|
||||||
|
},
|
||||||
|
).buttonUM,
|
||||||
|
)
|
||||||
|
}
|
||||||
}.toPersistentList()
|
}.toPersistentList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue