Updated on 2026-08-14
This commit is contained in:
parent
2d0bc9d9e6
commit
ac9a3d15c3
28 changed files with 1528 additions and 127 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.common.ui.markets.action
|
||||
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
|
|
@ -8,4 +9,6 @@ data class CryptoCurrencyData(
|
|||
val userWallet: UserWallet,
|
||||
val status: CryptoCurrencyStatus,
|
||||
val actions: List<TokenActionsState.ActionState>,
|
||||
val isAccountMode: Boolean,
|
||||
val account: AccountStatus.CryptoPortfolio,
|
||||
)
|
||||
|
|
@ -9,43 +9,103 @@ import com.tangem.core.ui.extensions.wrappedList
|
|||
|
||||
@Immutable
|
||||
sealed class QuickActionUM(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
@DrawableRes val icon: Int,
|
||||
val isLongClickAvailable: Boolean = false,
|
||||
open val title: TextReference,
|
||||
open val description: TextReference,
|
||||
@param:DrawableRes open val icon: Int,
|
||||
open val isLongClickAvailable: Boolean = false,
|
||||
) {
|
||||
data object Buy : QuickActionUM(
|
||||
title = resourceReference(R.string.common_buy),
|
||||
description = resourceReference(R.string.buy_token_description),
|
||||
icon = R.drawable.ic_plus_24,
|
||||
)
|
||||
|
||||
data class Exchange(
|
||||
val shouldShowBadge: Boolean,
|
||||
sealed class V1(
|
||||
override val title: TextReference,
|
||||
override val description: TextReference,
|
||||
@param:DrawableRes override val icon: Int,
|
||||
override val isLongClickAvailable: Boolean = false,
|
||||
) : QuickActionUM(
|
||||
title = resourceReference(R.string.common_exchange),
|
||||
description = resourceReference(R.string.exсhange_token_description),
|
||||
icon = R.drawable.ic_exchange_vertical_24,
|
||||
)
|
||||
title = title,
|
||||
description = description,
|
||||
icon = icon,
|
||||
isLongClickAvailable = isLongClickAvailable,
|
||||
) {
|
||||
data object Buy : V1(
|
||||
title = resourceReference(R.string.common_buy),
|
||||
description = resourceReference(R.string.buy_token_description),
|
||||
icon = R.drawable.ic_plus_24,
|
||||
)
|
||||
|
||||
data object Receive : QuickActionUM(
|
||||
title = resourceReference(R.string.common_receive),
|
||||
description = resourceReference(R.string.receive_token_description),
|
||||
icon = R.drawable.ic_arrow_down_24,
|
||||
isLongClickAvailable = true,
|
||||
)
|
||||
data class Exchange(
|
||||
val shouldShowBadge: Boolean,
|
||||
) : V1(
|
||||
title = resourceReference(R.string.common_exchange),
|
||||
description = resourceReference(R.string.exсhange_token_description),
|
||||
icon = R.drawable.ic_exchange_vertical_24,
|
||||
)
|
||||
|
||||
data object Stake : QuickActionUM(
|
||||
title = resourceReference(R.string.common_stake),
|
||||
description = resourceReference(R.string.stake_token_description),
|
||||
icon = R.drawable.ic_staking_24,
|
||||
)
|
||||
data object Receive : V1(
|
||||
title = resourceReference(R.string.common_receive),
|
||||
description = resourceReference(R.string.receive_token_description),
|
||||
icon = R.drawable.ic_arrow_down_24,
|
||||
isLongClickAvailable = true,
|
||||
)
|
||||
|
||||
data class YieldMode(
|
||||
private val apy: String,
|
||||
data object Stake : V1(
|
||||
title = resourceReference(R.string.common_stake),
|
||||
description = resourceReference(R.string.stake_token_description),
|
||||
icon = R.drawable.ic_staking_24,
|
||||
)
|
||||
|
||||
data class YieldMode(
|
||||
private val apy: String,
|
||||
) : V1(
|
||||
title = resourceReference(R.string.common_yield_mode),
|
||||
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
||||
icon = R.drawable.ic_analytics_up_mini_24,
|
||||
)
|
||||
}
|
||||
|
||||
sealed class V2(
|
||||
override val title: TextReference,
|
||||
override val description: TextReference,
|
||||
@param:DrawableRes override val icon: Int,
|
||||
override val isLongClickAvailable: Boolean = false,
|
||||
) : QuickActionUM(
|
||||
title = resourceReference(R.string.common_yield_mode),
|
||||
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
||||
icon = R.drawable.ic_analytics_up_mini_24,
|
||||
)
|
||||
title = title,
|
||||
description = description,
|
||||
icon = icon,
|
||||
isLongClickAvailable = isLongClickAvailable,
|
||||
) {
|
||||
data object Buy : V2(
|
||||
title = resourceReference(R.string.common_buy),
|
||||
description = resourceReference(R.string.quick_action_buy_description),
|
||||
icon = R.drawable.ic_credit_card_20,
|
||||
)
|
||||
|
||||
data class Exchange(
|
||||
val shouldShowBadge: Boolean,
|
||||
) : V2(
|
||||
title = resourceReference(R.string.common_exchange),
|
||||
description = resourceReference(R.string.quick_action_swap_description),
|
||||
icon = R.drawable.ic_exchange_mini_24,
|
||||
)
|
||||
|
||||
data object Receive : V2(
|
||||
title = resourceReference(R.string.common_receive),
|
||||
description = resourceReference(R.string.quick_action_receive_description),
|
||||
icon = R.drawable.ic_qrcode_new_24,
|
||||
isLongClickAvailable = true,
|
||||
)
|
||||
|
||||
data object Stake : V2(
|
||||
title = resourceReference(R.string.common_stake),
|
||||
description = resourceReference(R.string.stake_token_description),
|
||||
icon = R.drawable.ic_staking_24,
|
||||
)
|
||||
|
||||
data class YieldMode(
|
||||
private val apy: String,
|
||||
) : V2(
|
||||
title = resourceReference(R.string.common_yield_mode),
|
||||
description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)),
|
||||
icon = R.drawable.ic_analytics_up_mini_24,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,39 +2,64 @@ package com.tangem.common.ui.markets.action
|
|||
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
object QuickActionsConverter {
|
||||
|
||||
fun quickActions(cryptoData: CryptoCurrencyData, tokenActionsHandler: TokenActionsHandler): QuickActions {
|
||||
fun quickActions(
|
||||
cryptoData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
isRedesignEnabled: Boolean,
|
||||
): QuickActions {
|
||||
return QuickActions(
|
||||
actions = toQuickActions(cryptoData.actions),
|
||||
actions = toQuickActions(cryptoData.actions, isRedesignEnabled),
|
||||
onQuickActionClick = { quickActionUM ->
|
||||
when (quickActionUM) {
|
||||
QuickActionUM.Buy -> tokenActionsHandler.handle(
|
||||
QuickActionUM.V1.Buy -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Buy,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
is QuickActionUM.Exchange -> tokenActionsHandler.handle(
|
||||
is QuickActionUM.V1.Exchange -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Exchange,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Receive -> tokenActionsHandler.handle(
|
||||
QuickActionUM.V1.Receive -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Receive,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Stake -> tokenActionsHandler.handle(
|
||||
QuickActionUM.V1.Stake -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Stake,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
is QuickActionUM.YieldMode -> tokenActionsHandler.handle(
|
||||
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 ->
|
||||
if (actionUM == QuickActionUM.Receive) {
|
||||
if (actionUM == QuickActionUM.V1.Receive || actionUM == QuickActionUM.V2.Receive) {
|
||||
tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.CopyAddress,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
|
|
@ -44,18 +69,44 @@ object QuickActionsConverter {
|
|||
)
|
||||
}
|
||||
|
||||
fun toQuickActions(actions: List<TokenActionsState.ActionState>) = buildList {
|
||||
actions.forEach { action ->
|
||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
when (action) {
|
||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy
|
||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(action.shouldShowBadge)
|
||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive
|
||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.Stake
|
||||
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.YieldMode(action.apy)
|
||||
else -> null
|
||||
}?.let(::add)
|
||||
}
|
||||
fun toQuickActions(actions: List<TokenActionsState.ActionState>, isRedesignEnabled: Boolean) =
|
||||
if (isRedesignEnabled) {
|
||||
redesignedQuickActions(actions)
|
||||
} else {
|
||||
legacyQuickActions(actions)
|
||||
}
|
||||
}.toImmutableList()
|
||||
|
||||
private fun redesignedQuickActions(actions: List<TokenActionsState.ActionState>): ImmutableList<QuickActionUM> {
|
||||
return buildList {
|
||||
actions.forEach { action ->
|
||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
when (action) {
|
||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.V2.Buy
|
||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.V2.Exchange(action.shouldShowBadge)
|
||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.V2.Receive
|
||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.V2.Stake
|
||||
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.V2.YieldMode(action.apy)
|
||||
else -> null
|
||||
}?.let(::add)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
private fun legacyQuickActions(actions: List<TokenActionsState.ActionState>): ImmutableList<QuickActionUM> {
|
||||
return buildList {
|
||||
actions.forEach { action ->
|
||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
when (action) {
|
||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.V1.Buy
|
||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.V1.Exchange(action.shouldShowBadge)
|
||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.V1.Receive
|
||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.V1.Stake
|
||||
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.V1.YieldMode(action.apy)
|
||||
else -> null
|
||||
}?.let(::add)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -3,16 +3,15 @@ package com.tangem.common.ui.account
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -22,12 +21,16 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.components.SpacerW12
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
|
||||
@Composable
|
||||
|
|
@ -80,6 +83,66 @@ fun PortfolioSelectRow(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PortfolioSelectRowV2(
|
||||
state: PortfolioSelectUM,
|
||||
modifier: Modifier = Modifier,
|
||||
leftContent: @Composable RowScope.() -> Unit = {},
|
||||
) {
|
||||
val leftText = if (state.isAccountMode) R.string.account_details_title else R.string.wc_common_wallet
|
||||
TangemRowContainer(
|
||||
modifier.clickable(enabled = state.isMultiChoice, onClick = state.onClick),
|
||||
) {
|
||||
if (state.icon != null) {
|
||||
Box(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.HEAD),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
AccountIcon(
|
||||
modifier = Modifier.padding(end = TangemTheme.dimens2.x3),
|
||||
name = state.name,
|
||||
icon = state.icon,
|
||||
size = AccountIconSize.RedesignedDefault,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
leftContent()
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResourceSafe(leftText),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = state.name.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
if (state.isMultiChoice) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.TAIL)
|
||||
.size(TangemTheme.dimens2.x5),
|
||||
painter = painterResource(id = R.drawable.ic_select_choice_20),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class PortfolioSelectUM(
|
||||
val icon: AccountIconUM?,
|
||||
|
|
@ -101,6 +164,20 @@ private fun PortfolioSelectRowPreview(@PreviewParameter(PreviewProvider::class)
|
|||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PortfolioSelectRowPreviewV2(@PreviewParameter(PreviewProvider::class) state: PortfolioSelectUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
PortfolioSelectRowV2(
|
||||
state = state,
|
||||
modifier = Modifier.background(TangemTheme.colors2.surface.level3),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PreviewProvider : PreviewParameterProvider<PortfolioSelectUM> {
|
||||
|
||||
override val values: Sequence<PortfolioSelectUM>
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ private fun Preview(@PreviewParameter(PreviewProvider::class) state: AddTokenUM)
|
|||
}
|
||||
}
|
||||
|
||||
private class PreviewProvider : PreviewParameterProvider<AddTokenUM> {
|
||||
internal class PreviewProvider : PreviewParameterProvider<AddTokenUM> {
|
||||
private val tokenState
|
||||
get() = TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,213 @@
|
|||
package com.tangem.common.ui.addtoken
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.account.PortfolioSelectRowV2
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.button.PrimaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
fun AddTokenContentV2(state: AddTokenUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
TokenHeader(
|
||||
cryptoCurrencyIconState = state.tokenToAdd.iconState,
|
||||
tokenName = state.tokenToAdd.titleState,
|
||||
)
|
||||
Column {
|
||||
if (state.portfolio.isMultiChoice) {
|
||||
PortfolioSelectRowV2(
|
||||
modifier = Modifier.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens2.x5),
|
||||
),
|
||||
state = state.portfolio,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
}
|
||||
|
||||
NetworkRow(state.network)
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
|
||||
AddButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.button,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenHeader(
|
||||
cryptoCurrencyIconState: CurrencyIconState,
|
||||
tokenName: TokenItemState.TitleState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens2.x8),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = cryptoCurrencyIconState,
|
||||
iconSize = 70.dp,
|
||||
shouldDisplayNetwork = false,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x4)
|
||||
|
||||
when (tokenName) {
|
||||
is TokenItemState.TitleState.Content -> {
|
||||
Text(
|
||||
text = tokenName.text.resolveReference(),
|
||||
style = TangemTheme.typography2.headingSemibold28,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
}
|
||||
TokenItemState.TitleState.Loading -> {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = TangemTheme.dimens2.x17, height = TangemTheme.dimens2.x9),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
TokenItemState.TitleState.Locked -> {
|
||||
Box(
|
||||
modifier = Modifier.background(
|
||||
color = TangemTheme.colors2.surface.level4,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens2.x25),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkRow(state: AddTokenUM.Network, modifier: Modifier = Modifier) {
|
||||
TangemRowContainer(
|
||||
modifier
|
||||
.clickable(enabled = state.editable, onClick = state.onClick)
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens2.x5),
|
||||
),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.size(TangemTheme.dimens2.x10)
|
||||
.padding(end = TangemTheme.dimens2.x3),
|
||||
tint = Color.Unspecified,
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
|
||||
text = stringResourceSafe(R.string.wc_common_network),
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = state.name.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
if (state.editable) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.TAIL)
|
||||
.size(TangemTheme.dimens2.x5),
|
||||
painter = painterResource(id = com.tangem.common.ui.R.drawable.ic_select_choice_20),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddButton(state: AddTokenUM.Button, modifier: Modifier = Modifier) {
|
||||
val isIconExists = state.isEnabled && state.isTangemIconVisible
|
||||
PrimaryTangemButton(
|
||||
modifier = modifier,
|
||||
text = state.text,
|
||||
onClick = state.onConfirmClick,
|
||||
tangemIconUM = if (isIconExists) {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_tangem_24,
|
||||
tintReference = {
|
||||
if (state.isEnabled) {
|
||||
TangemTheme.colors2.graphic.neutral.primaryInverted
|
||||
} else {
|
||||
TangemTheme.colors2.graphic.neutral.quaternary
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
iconPosition = TangemButtonIconPosition.Start,
|
||||
isEnabled = state.isEnabled,
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(PreviewProvider::class) state: AddTokenUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors2.surface.level2)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
AddTokenContentV2(state = state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1177,6 +1177,9 @@
|
|||
<string name="qr_scanner_error_unsupported_network_title">No supported tokens found</string>
|
||||
<string name="qr_scanner_warning_unknown_parameters_message">This QR code contains parameters that are not recognized: %s. Some payment details may be lost if you continue.</string>
|
||||
<string name="qr_scanner_warning_unknown_parameters_title">Unknown Parameters</string>
|
||||
<string name="quick_action_buy_description">Credit card or bank account</string>
|
||||
<string name="quick_action_receive_description">Share your address or QR-code</string>
|
||||
<string name="quick_action_swap_description">Between your portfolios</string>
|
||||
<string name="receive_bottom_sheet_no_memo_required_message">No memo required</string>
|
||||
<string name="receive_bottom_sheet_warning_message">%1$s (%2$s) on %3$s network</string>
|
||||
<string name="receive_bottom_sheet_warning_message_compact">%1$s on %2$s network</string>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
enum class AccountIconSize {
|
||||
Default, Large, Medium, Small, ExtraSmall
|
||||
Default, Large, Medium, Small, ExtraSmall, RedesignedDefault
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -128,6 +128,7 @@ fun AccountCharIcon(char: Char, color: Color, size: AccountIconSize, modifier: M
|
|||
AccountIconSize.Medium -> TangemTheme.typography.subtitle1
|
||||
AccountIconSize.Small -> TangemTheme.typography.subtitle2
|
||||
AccountIconSize.ExtraSmall -> TangemTheme.typography.caption1
|
||||
AccountIconSize.RedesignedDefault -> TangemTheme.typography2.headingSemibold28
|
||||
}
|
||||
|
||||
val textSize by animateFloatAsState(
|
||||
|
|
@ -159,6 +160,7 @@ private fun AccountIconSize.iconSizeInDp(): Dp = when (this) {
|
|||
AccountIconSize.Medium -> 16.dp
|
||||
AccountIconSize.Small -> 12.dp
|
||||
AccountIconSize.ExtraSmall -> 8.dp
|
||||
AccountIconSize.RedesignedDefault -> 20.dp
|
||||
}
|
||||
|
||||
private fun AccountIconSize.boxSizeInDp(): Dp = when (this) {
|
||||
|
|
@ -167,6 +169,7 @@ private fun AccountIconSize.boxSizeInDp(): Dp = when (this) {
|
|||
AccountIconSize.Medium -> 28.dp
|
||||
AccountIconSize.Small -> 20.dp
|
||||
AccountIconSize.ExtraSmall -> 14.dp
|
||||
AccountIconSize.RedesignedDefault -> 40.dp
|
||||
}
|
||||
|
||||
private fun AccountIconSize.boxShapeSizeInDp(): Dp = when (this) {
|
||||
|
|
@ -175,6 +178,7 @@ private fun AccountIconSize.boxShapeSizeInDp(): Dp = when (this) {
|
|||
AccountIconSize.Medium -> 8.dp
|
||||
AccountIconSize.Small -> 6.dp
|
||||
AccountIconSize.ExtraSmall -> 4.dp
|
||||
AccountIconSize.RedesignedDefault -> 12.dp
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
|
|
@ -203,6 +207,7 @@ private fun Sample() {
|
|||
AccountIconSize.Medium -> AccountIconSize.Small
|
||||
AccountIconSize.Small -> AccountIconSize.ExtraSmall
|
||||
AccountIconSize.ExtraSmall -> AccountIconSize.Default
|
||||
AccountIconSize.RedesignedDefault -> AccountIconSize.Large
|
||||
}
|
||||
}) { Text("Change") }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
package com.tangem.core.ui.components.token.internal
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -13,11 +9,11 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
|
|
@ -25,7 +21,10 @@ import com.tangem.core.ui.components.RectangleShimmer
|
|||
import com.tangem.core.ui.components.icons.IconTint
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState as TokenFiatAmountState
|
||||
|
||||
@Composable
|
||||
|
|
@ -60,6 +59,11 @@ internal fun TokenFiatAmount(state: TokenFiatAmountState?, isBalanceHidden: Bool
|
|||
// Empty box for proper measurements
|
||||
Box(modifier)
|
||||
}
|
||||
is TokenFiatAmountState.AnnotatedContent -> FiatAmountAnnotatedText(
|
||||
text = state.text.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
|
||||
modifier = modifier,
|
||||
isFlickering = state.isFlickering,
|
||||
)
|
||||
null -> Unit
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +81,7 @@ private fun IconAmount(state: TokenFiatAmountState.Icon, modifier: Modifier = Mo
|
|||
@Composable
|
||||
private fun ContentFiatAmount(
|
||||
text: String,
|
||||
icons: List<TokenFiatAmountState.Content.IconUM>,
|
||||
icons: ImmutableList<TokenFiatAmountState.Content.IconUM>,
|
||||
isAmountFlickering: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -135,6 +139,25 @@ private fun FiatAmountText(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FiatAmountAnnotatedText(
|
||||
text: AnnotatedString,
|
||||
modifier: Modifier = Modifier,
|
||||
isAvailable: Boolean = true,
|
||||
isFlickering: Boolean = false,
|
||||
) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTheme.typography.body2.applyBladeBrush(
|
||||
isEnabled = isFlickering,
|
||||
textColor = if (isAvailable) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.tertiary,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun Modifier.placeholderSize(): Modifier = composed {
|
||||
return@composed this
|
||||
.padding(vertical = 4.dp)
|
||||
|
|
|
|||
|
|
@ -230,6 +230,11 @@ sealed class TokenItemState {
|
|||
val tint: IconTint = IconTint.Inactive,
|
||||
) : FiatAmountState()
|
||||
|
||||
data class AnnotatedContent(
|
||||
val text: TextReference,
|
||||
val isFlickering: Boolean = false,
|
||||
) : FiatAmountState()
|
||||
|
||||
data object Loading : FiatAmountState()
|
||||
|
||||
data object Locked : FiatAmountState()
|
||||
|
|
|
|||
9
core/ui/src/main/res/drawable/ic_credit_card_20.xml
Normal file
9
core/ui/src/main/res/drawable/ic_credit_card_20.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M13.832,3.945C14.803,3.945 15.289,3.946 15.686,4.061C16.648,4.339 17.4,5.091 17.678,6.053C17.792,6.449 17.793,6.935 17.793,7.906V11.354L17.788,12.435C17.773,13.382 17.714,13.959 17.476,14.427L17.362,14.628C17.082,15.085 16.68,15.458 16.2,15.702L16.081,15.758C15.634,15.95 15.077,16.001 14.208,16.015L13.126,16.02H6.873C5.342,16.02 4.529,16.02 3.919,15.758L3.8,15.702C3.32,15.458 2.918,15.085 2.638,14.628L2.525,14.427C2.287,13.959 2.227,13.382 2.212,12.435L2.207,11.354V7.906C2.207,7.057 2.207,6.579 2.283,6.207L2.321,6.053C2.582,5.151 3.26,4.433 4.137,4.118L4.313,4.061C4.71,3.946 5.197,3.945 6.168,3.945H13.832ZM3.457,11.354C3.457,12.19 3.458,12.743 3.492,13.167C3.526,13.575 3.585,13.753 3.639,13.859C3.798,14.173 4.053,14.428 4.366,14.588C4.473,14.642 4.651,14.701 5.06,14.734C5.483,14.769 6.036,14.769 6.873,14.769H13.126C13.963,14.769 14.517,14.769 14.94,14.734C15.349,14.701 15.526,14.642 15.633,14.588C15.946,14.428 16.201,14.173 16.361,13.859C16.416,13.753 16.473,13.575 16.507,13.167C16.541,12.743 16.543,12.19 16.543,11.354V8.531H3.457V11.354ZM10.136,12.227C10.481,12.228 10.761,12.508 10.761,12.852C10.761,13.198 10.481,13.477 10.136,13.477H9.081C8.736,13.477 8.456,13.198 8.456,12.852C8.456,12.507 8.736,12.227 9.081,12.227H10.136ZM14.589,12.227C14.934,12.228 15.214,12.508 15.214,12.852C15.214,13.198 14.934,13.477 14.589,13.477H12.164C11.819,13.477 11.539,13.198 11.539,12.852C11.539,12.508 11.819,12.228 12.164,12.227H14.589ZM6.168,5.196C5.111,5.196 4.845,5.208 4.661,5.261C4.111,5.42 3.68,5.851 3.521,6.4C3.481,6.541 3.465,6.73 3.459,7.281H16.54C16.534,6.729 16.518,6.541 16.478,6.4C16.319,5.851 15.889,5.42 15.339,5.261C15.155,5.208 14.889,5.196 13.832,5.196H6.168Z"
|
||||
android:fillColor="#0099FF"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_select_choice_20.xml
Normal file
9
core/ui/src/main/res/drawable/ic_select_choice_20.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M13.46,11.793C13.85,11.402 14.483,11.402 14.874,11.793C15.264,12.183 15.264,12.816 14.874,13.207L10.708,17.374C10.317,17.764 9.684,17.764 9.294,17.374L5.127,13.207C4.736,12.816 4.736,12.183 5.127,11.793C5.517,11.402 6.15,11.402 6.541,11.793L10,15.252L13.46,11.793ZM9.294,2.626C9.684,2.236 10.317,2.235 10.708,2.626L14.874,6.793C15.264,7.183 15.264,7.816 14.874,8.207C14.483,8.597 13.85,8.597 13.46,8.207L10,4.748L6.541,8.207C6.15,8.597 5.517,8.597 5.127,8.207C4.736,7.816 4.736,7.183 5.127,6.793L9.294,2.626Z"
|
||||
android:fillColor="#B0B0B0"/>
|
||||
</vector>
|
||||
|
|
@ -4,15 +4,17 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.addtoken.AddTokenContent
|
||||
import com.tangem.common.ui.addtoken.AddTokenContentV2
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddTokenModel
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedNetwork
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedPortfolio
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddTokenModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -29,10 +31,17 @@ internal class AddTokenComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val um = state.value ?: return
|
||||
AddTokenContent(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
AddTokenContentV2(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
} else {
|
||||
AddTokenContent(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ import com.tangem.core.decompose.factory.ComponentFactory
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.TokenActionsContent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.TokenActionsContentV2
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -44,10 +46,17 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
|||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
val tokenActionsUM = state.value ?: return
|
||||
TokenActionsContent(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenActionsContentV2(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
} else {
|
||||
TokenActionsContent(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
}
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ private const val TOKEN_ACTIONS_DELAY = 500L
|
|||
@Suppress("LongParameterList", "LargeClass")
|
||||
internal class AddToPortfolioModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
designFeatureToggles: DesignFeatureToggles,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
val portfolioSelectorController: PortfolioSelectorController,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val callbackDelegate: AddToPortfolioCallbackDelegate,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val getTokenMarketCryptoCurrency: GetTokenMarketCryptoCurrency,
|
||||
|
|
@ -441,7 +441,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
currency = addedToken.currency,
|
||||
accountId = selectedPortfolio.account.account.account.accountId,
|
||||
).onEach { state ->
|
||||
val requestedQuickActions = toQuickActions(state.states)
|
||||
val requestedQuickActions = toQuickActions(state.states, designFeatureToggles.isRedesignEnabled)
|
||||
when {
|
||||
requestedQuickActions.isNotEmpty() -> {
|
||||
timerJob.cancel()
|
||||
|
|
@ -458,6 +458,8 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
userWallet = selectedPortfolio.userWallet,
|
||||
status = actionsState.cryptoCurrencyStatus,
|
||||
actions = actionsState.states,
|
||||
isAccountMode = selectedPortfolio.isAccountMode,
|
||||
account = selectedPortfolio.account.account,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,17 +10,15 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -29,6 +27,7 @@ import javax.inject.Inject
|
|||
internal class TokenActionsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
tokenActionsIntentsFactory: TokenActionsHandler.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val uiBuilder: TokenActionsUiBuilder,
|
||||
|
|
@ -52,13 +51,29 @@ internal class TokenActionsModel @Inject constructor(
|
|||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TokenReceiveConfig> = SlotNavigation()
|
||||
val uiState: StateFlow<TokenActionsUM?> = params.data
|
||||
.mapLatest { uiBuilder.build(it, tokenActionsHandler, analyticsEventBuilder.first()) }
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val uiState: StateFlow<TokenActionsUM?> =
|
||||
combine(
|
||||
params.data,
|
||||
getBalanceHidingSettingsUseCase.isBalanceHidden(),
|
||||
) { cryptoCurrencyData, isBalanceHidden ->
|
||||
cryptoCurrencyData to isBalanceHidden
|
||||
}
|
||||
.mapLatest { (cryptoCurrencyData, isBalanceHidden) ->
|
||||
uiBuilder.build(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
eventBuilder = analyticsEventBuilder.first(),
|
||||
appCurrency = currentAppCurrency.value,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
private fun handledQuickAction(handledAction: TokenActionsHandler.HandledQuickAction) = modelScope.launch {
|
||||
val event = analyticsEventBuilder.first().getTokenActionClick(actionUM = handledAction.action)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,73 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.model
|
||||
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
import com.tangem.common.getTotalFiatAmount
|
||||
import com.tangem.common.ui.account.*
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.QuickActionsConverter.quickActions
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeIconPosition
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeSize
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeUM
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.TokenActionsComponent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class TokenActionsUiBuilder @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) {
|
||||
private val params = paramsContainer.require<TokenActionsComponent.Params>()
|
||||
|
||||
fun build(
|
||||
data: CryptoCurrencyData,
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
): TokenActionsUM {
|
||||
return if (designFeatureToggles.isRedesignEnabled) {
|
||||
buildV2(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
eventBuilder = eventBuilder,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
} else {
|
||||
buildV1(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
eventBuilder = eventBuilder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildV1(
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
): TokenActionsUM {
|
||||
val status = data.status
|
||||
val status = cryptoCurrencyData.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
id = status.currency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(status.currency),
|
||||
|
|
@ -39,11 +80,147 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
)
|
||||
return TokenActionsUM(
|
||||
token = tokenUM,
|
||||
quickActions = quickActions(
|
||||
cryptoData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = false,
|
||||
),
|
||||
onLaterClick = {
|
||||
analyticsEventHandler.send(eventBuilder.getTokenLater())
|
||||
params.callbacks.onLaterClick()
|
||||
},
|
||||
quickActions = quickActions(data, tokenActionsHandler),
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildV2(
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
): TokenActionsUM {
|
||||
val status = cryptoCurrencyData.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
id = status.currency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(status.currency),
|
||||
titleState = TokenItemState.TitleState.Content(stringReference(status.currency.name)),
|
||||
fiatAmountState = createFiatAmountState(status, appCurrency),
|
||||
subtitle2State = createSubtitle2State(status),
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(status.currency.symbol)),
|
||||
onItemClick = null,
|
||||
onItemLongClick = null,
|
||||
)
|
||||
return TokenActionsUM(
|
||||
token = tokenUM,
|
||||
quickActions = quickActions(
|
||||
cryptoData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = true,
|
||||
),
|
||||
onLaterClick = {
|
||||
analyticsEventHandler.send(eventBuilder.getTokenLater())
|
||||
params.callbacks.onLaterClick()
|
||||
},
|
||||
isBalancesHidden = isBalanceHidden,
|
||||
portfolioBadge = createPortfolioBadge(cryptoCurrencyData),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPortfolioBadge(cryptoCurrencyData: CryptoCurrencyData): TangemBadgeUM {
|
||||
val icon: AccountIconUM?
|
||||
val name = if (cryptoCurrencyData.isAccountMode) {
|
||||
icon = CryptoPortfolioIconConverter.convert(cryptoCurrencyData.account.account.icon)
|
||||
cryptoCurrencyData
|
||||
.account
|
||||
.account
|
||||
.accountName
|
||||
.toUM()
|
||||
.value
|
||||
} else {
|
||||
icon = null
|
||||
stringReference(cryptoCurrencyData.userWallet.name)
|
||||
}
|
||||
return TangemBadgeUM(
|
||||
text = name,
|
||||
tangemIconUM = if (icon == null) {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_key_card_20,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
)
|
||||
} else {
|
||||
TangemIconUM.Icon(
|
||||
iconRes = icon.value.getResId(),
|
||||
tintReference = { icon.color.getUiColor() },
|
||||
)
|
||||
},
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = if (cryptoCurrencyData.isAccountMode) {
|
||||
TangemBadgeIconPosition.Start
|
||||
} else {
|
||||
TangemBadgeIconPosition.End
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSubtitle2State(status: CryptoCurrencyStatus): TokenItemState.Subtitle2State? {
|
||||
return when (status.value) {
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
is CryptoCurrencyStatus.Custom,
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> {
|
||||
TokenItemState.Subtitle2State.TextContent(
|
||||
text = status.getTotalCryptoAmount().format {
|
||||
crypto(status.currency)
|
||||
},
|
||||
)
|
||||
}
|
||||
is CryptoCurrencyStatus.Loading,
|
||||
is CryptoCurrencyStatus.MissedDerivation,
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> TokenItemState.Subtitle2State.TextContent(
|
||||
text = BigDecimal.ZERO.format {
|
||||
crypto(status.currency)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFiatAmountState(
|
||||
status: CryptoCurrencyStatus,
|
||||
appCurrency: AppCurrency,
|
||||
): TokenItemState.FiatAmountState? {
|
||||
return when (status.value) {
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
is CryptoCurrencyStatus.Custom,
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> {
|
||||
TokenItemState.FiatAmountState.AnnotatedContent(
|
||||
text = status.getTotalFiatAmount().formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
).price()
|
||||
},
|
||||
)
|
||||
}
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
is CryptoCurrencyStatus.MissedDerivation,
|
||||
is CryptoCurrencyStatus.Loading,
|
||||
-> TokenItemState.FiatAmountState.AnnotatedContent(
|
||||
text = BigDecimal.ZERO.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
).price()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,47 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.components.label.Label
|
||||
import com.tangem.core.ui.components.label.entity.LabelStyle
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.components.rows.BlockchainRow
|
||||
import com.tangem.core.ui.components.rows.model.BlockchainRowUM
|
||||
import com.tangem.core.ui.ds.badge.TangemBadge
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeSize
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.ChooseNetworkUM
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.ChooseNetworkUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.util.UUID
|
||||
|
||||
|
|
@ -33,13 +49,28 @@ private const val DISABLED_ALPHA = 0.4f
|
|||
|
||||
@Composable
|
||||
internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
ChooseNetworkContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
ChooseNetworkContentV1(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ChooseNetworkContentV1(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.action),
|
||||
) {
|
||||
state.networks.fastForEachIndexed { index, model ->
|
||||
state.networks.fastForEach { model ->
|
||||
key(model.id) {
|
||||
BlockchainRow(
|
||||
model = model,
|
||||
|
|
@ -66,6 +97,120 @@ internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = M
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ChooseNetworkContentV2(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(34.dp),
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens2.x4, vertical = TangemTheme.dimens2.x2),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens2.x4, bottom = TangemTheme.dimens2.x2),
|
||||
text = stringResourceSafe(R.string.common_choose_network),
|
||||
style = TangemTheme.typography2.subheadlineMedium14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
|
||||
state.networks.fastForEach { model ->
|
||||
key(model.id) {
|
||||
TangemRowContainer(
|
||||
modifier = Modifier.clickable(
|
||||
enabled = model.isEnabled,
|
||||
onClick = { state.onNetworkClick(model) },
|
||||
),
|
||||
contentPadding = PaddingValues(vertical = TangemTheme.dimens2.x3),
|
||||
content = {
|
||||
NetworkIcon(
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3),
|
||||
model = model,
|
||||
)
|
||||
|
||||
NetworkText(
|
||||
modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.START_TOP),
|
||||
model = model,
|
||||
)
|
||||
if (!model.isEnabled) {
|
||||
TangemBadge(
|
||||
modifier = Modifier
|
||||
.layoutId(layoutId = TangemRowLayoutId.TAIL)
|
||||
.padding(start = TangemTheme.dimens2.x2),
|
||||
text = resourceReference(R.string.common_added),
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkIcon(model: BlockchainRowUM, modifier: Modifier = Modifier) {
|
||||
if (model.isSelected && model.isEnabled) {
|
||||
Image(
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens2.x10),
|
||||
painter = painterResource(id = model.iconResId),
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors2.button.backgroundSecondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.size(TangemTheme.dimens2.x10),
|
||||
painter = painterResource(id = model.iconResId),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkText(model: BlockchainRowUM, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(weight = 10f, fill = false),
|
||||
text = model.name,
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = when {
|
||||
model.isEnabled && model.isMainNetwork -> TangemTheme.colors2.text.neutral.primary
|
||||
model.isEnabled -> TangemTheme.colors2.text.neutral.secondary
|
||||
else -> TangemTheme.colors2.text.status.disabled
|
||||
},
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.weight(weight = 5f, fill = false),
|
||||
text = model.type,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = if (model.isEnabled) {
|
||||
TangemTheme.colors2.text.neutral.tertiary
|
||||
} else {
|
||||
TangemTheme.colors2.text.status.disabled
|
||||
},
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
|
|
@ -77,6 +222,19 @@ private fun Preview(@PreviewParameter(ChooseNetworkContentProvider::class) conte
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun PreviewV2(@PreviewParameter(ChooseNetworkContentProvider::class) content: ChooseNetworkUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
ChooseNetworkContent(
|
||||
state = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ChooseNetworkContentProvider : PreviewParameterProvider<ChooseNetworkUM> {
|
||||
|
||||
private val blockchainRow = BlockchainRowUM(
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ private fun ActionRow(
|
|||
.size(36.dp)
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
if (state is QuickActionUM.V1.Exchange && state.shouldShowBadge) {
|
||||
drawBadge(containerColor = containerColor, offset = 4.dp)
|
||||
}
|
||||
},
|
||||
|
|
@ -190,9 +190,9 @@ private class TokenActionsContentPreviewProvider : PreviewParameterProvider<Toke
|
|||
TokenActionsUM(
|
||||
quickActions = QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,292 @@
|
|||
package com.tangem.features.commonfeatures.impl.addtoportfolio.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.common.ui.markets.action.QuickActionUM
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.*
|
||||
import com.tangem.core.ui.ds.button.SecondaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.formatStyled
|
||||
import com.tangem.core.ui.format.bigdecimal.price
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state.TokenActionsUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
import java.util.UUID
|
||||
|
||||
private const val ACTION_BACKGROUND_ALPHA = .1f
|
||||
|
||||
@Composable
|
||||
internal fun TokenActionsContentV2(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
TokenHeader(
|
||||
addedToken = state.token,
|
||||
portfolioBadge = state.portfolioBadge,
|
||||
isBalanceHidden = state.isBalancesHidden,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
state.quickActions.actions.fastForEach { actionUM ->
|
||||
key(actionUM.title) {
|
||||
ActionRow(
|
||||
state = actionUM,
|
||||
onClick = { state.quickActions.onQuickActionClick(actionUM) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(actionUM) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
|
||||
SecondaryTangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = state.onLaterClick,
|
||||
text = resourceReference(R.string.common_later),
|
||||
size = TangemButtonSize.X12,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ActionRow(
|
||||
state: QuickActionUM,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: (() -> Unit),
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
val onLongClickInternal = {
|
||||
hapticManager.perform(TangemHapticEffect.View.LongPress)
|
||||
onLongClick()
|
||||
}
|
||||
|
||||
TangemRowContainer(
|
||||
modifier = modifier
|
||||
.combinedClickable(
|
||||
onLongClick = onLongClickInternal.takeIf { state.isLongClickAvailable },
|
||||
onClick = {
|
||||
hapticManager.perform(TangemHapticEffect.View.SegmentTick)
|
||||
onClick()
|
||||
},
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = RoundedCornerShape(TangemTheme.dimens2.x5),
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3)
|
||||
.size(40.dp)
|
||||
.background(
|
||||
color = TangemTheme.colors2.graphic.status.accent.copy(alpha = ACTION_BACKGROUND_ALPHA),
|
||||
shape = CircleShape,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.status.accent,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP),
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM),
|
||||
text = state.description.resolveReference(),
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.TAIL)
|
||||
.padding(start = TangemTheme.dimens2.x2)
|
||||
.size(24.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenHeader(
|
||||
addedToken: TokenItemState,
|
||||
isBalanceHidden: Boolean,
|
||||
portfolioBadge: TangemBadgeUM?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens2.x8),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = addedToken.iconState,
|
||||
iconSize = 70.dp,
|
||||
networkBadgeSize = 24.dp,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x5)
|
||||
|
||||
when (val fiat = addedToken.fiatAmountState) {
|
||||
is TokenItemState.FiatAmountState.AnnotatedContent -> {
|
||||
Text(
|
||||
text = fiat.text.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography2.titleRegular44,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
when (val cryptoAmount = addedToken.subtitle2State) {
|
||||
is TokenItemState.Subtitle2State.TextContent -> {
|
||||
Text(
|
||||
text = cryptoAmount.text.orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
SpacerH(TangemTheme.dimens2.x7)
|
||||
|
||||
if (portfolioBadge == null) return
|
||||
TangemBadge(portfolioBadge)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(TokenActionsContentPreviewProviderV2::class) state: TokenActionsUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors2.surface.level2)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
TokenActionsContentV2(
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenActionsContentPreviewProviderV2 : PreviewParameterProvider<TokenActionsUM> {
|
||||
private val tokenState
|
||||
get() = TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
iconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = R.drawable.img_eth_22,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
),
|
||||
titleState = TokenItemState.TitleState.Content(
|
||||
text = stringReference(value = "Tether"),
|
||||
),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.AnnotatedContent(
|
||||
text = BigDecimal.ONE.formatStyled {
|
||||
fiat(
|
||||
fiatCurrencyCode = "USD",
|
||||
fiatCurrencySymbol = "$",
|
||||
spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) },
|
||||
).price()
|
||||
},
|
||||
),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(
|
||||
"1.01 USDT",
|
||||
),
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(value = stringReference("USDT")),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
)
|
||||
|
||||
override val values: Sequence<TokenActionsUM>
|
||||
get() = sequenceOf(
|
||||
TokenActionsUM(
|
||||
quickActions = QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.V2.Buy,
|
||||
QuickActionUM.V2.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V2.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
),
|
||||
token = tokenState,
|
||||
onLaterClick = {},
|
||||
portfolioBadge = TangemBadgeUM(
|
||||
text = stringReference("Wallet 2"),
|
||||
tangemIconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_key_card_20,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
),
|
||||
size = TangemBadgeSize.X6,
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
iconPosition = TangemBadgeIconPosition.End,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -2,9 +2,12 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio.ui.state
|
|||
|
||||
import com.tangem.common.ui.markets.action.QuickActions
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeUM
|
||||
|
||||
internal data class TokenActionsUM(
|
||||
val token: TokenItemState,
|
||||
val quickActions: QuickActions,
|
||||
val onLaterClick: () -> Unit,
|
||||
val isBalancesHidden: Boolean = false,
|
||||
val portfolioBadge: TangemBadgeUM? = null,
|
||||
)
|
||||
|
|
@ -7,9 +7,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorBS
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContent
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContentV2
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -43,10 +45,17 @@ internal class DefaultPortfolioSelectorComponent @AssistedInject constructor(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.res.Configuration
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -12,8 +13,10 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.commonfeatures.impl.R
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
|
||||
|
||||
|
|
@ -41,11 +44,19 @@ internal fun PortfolioSelectorBS(
|
|||
)
|
||||
},
|
||||
content = {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
} else {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -62,4 +73,20 @@ private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::cla
|
|||
onBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewV2(@PreviewParameter(PortfolioSelectorPreviewStateProvider::class) params: PortfolioSelectorUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
PortfolioSelectorBS(
|
||||
state = params,
|
||||
onDismiss = {},
|
||||
modifier = Modifier,
|
||||
onBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
package com.tangem.features.commonfeatures.impl.portfolioselector.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.userwallet.CardImage
|
||||
import com.tangem.common.ui.userwallet.getBalanceValueAndFlickerState
|
||||
import com.tangem.common.ui.userwallet.getInformationValue
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorItemUM
|
||||
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
|
||||
import com.tangem.utils.StringsSigns.DOT
|
||||
|
||||
private const val DISABLED_WALLET_ALPHA = 0.5f
|
||||
|
||||
@Composable
|
||||
internal fun PortfolioSelectorContentV2(
|
||||
state: PortfolioSelectorUM,
|
||||
modifier: Modifier = Modifier,
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio ->
|
||||
PortfolioSelectorItem(
|
||||
state = item.item,
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = TangemTheme.colors2.surface.level3,
|
||||
radius = TangemTheme.dimens2.x5,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PortfolioSelectorItem(state: UserWalletItemUM, modifier: Modifier = Modifier) {
|
||||
TangemRowContainer(modifier = modifier) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.layoutId(TangemRowLayoutId.HEAD)
|
||||
.padding(end = TangemTheme.dimens2.x3),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CardImage(
|
||||
modifier = Modifier.size(40.dp),
|
||||
imageState = state.imageState,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.START_TOP),
|
||||
text = state.name.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
InfoRow(
|
||||
modifier = Modifier.layoutId(layoutId = TangemRowLayoutId.START_BOTTOM),
|
||||
information = state.information,
|
||||
balance = state.balance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InfoRow(
|
||||
information: UserWalletItemUM.Information,
|
||||
balance: UserWalletItemUM.Balance,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = information,
|
||||
label = "Information content",
|
||||
) { information ->
|
||||
val informationValue = getInformationValue(information)
|
||||
|
||||
if (informationValue == null) {
|
||||
TextShimmer(
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
text = "aaaaa",
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = informationValue,
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Text(
|
||||
text = " $DOT ",
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
||||
val (balanceValue, isFlickering) = getBalanceValueAndFlickerState(balance)
|
||||
|
||||
if (balanceValue == null) {
|
||||
TextShimmer(
|
||||
style = TangemTheme.typography2.captionMedium12,
|
||||
text = "aaaaa",
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = balanceValue,
|
||||
style = TangemTheme.typography2.captionMedium12.applyBladeBrush(
|
||||
isEnabled = isFlickering,
|
||||
textColor = TangemTheme.colors2.text.neutral.secondary,
|
||||
),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WalletNameRow(model: PortfolioSelectorItemUM.GroupTitle, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier.padding(top = TangemTheme.dimens2.x4, bottom = TangemTheme.dimens2.x2),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
text = model.name.resolveReference(),
|
||||
style = TangemTheme.typography2.subheadlineMedium14,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_key_card_20),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Bottom)
|
||||
.size(TangemTheme.dimens2.x5),
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::class) params: PortfolioSelectorUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = params,
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
|||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.common.ui.markets.action.CryptoCurrencyData
|
||||
import com.tangem.common.ui.markets.action.TokenActionsHandler
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
|
|
@ -53,6 +54,7 @@ internal class MarketsPortfolioDelegate @AssistedInject constructor(
|
|||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val yieldSupplyGetAvailabilityUseCase: YieldSupplyGetAvailabilityUseCase,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
@Assisted private val token: TokenMarketParams,
|
||||
|
|
@ -229,6 +231,7 @@ internal class MarketsPortfolioDelegate @AssistedInject constructor(
|
|||
isBalanceHidden = isBalanceHidden,
|
||||
onTokenItemClick = { },
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = designFeatureToggles.isRedesignEnabled,
|
||||
)
|
||||
|
||||
portfolio.portfolios.forEach { portfolioItem ->
|
||||
|
|
@ -253,6 +256,8 @@ internal class MarketsPortfolioDelegate @AssistedInject constructor(
|
|||
userWallet = userWallet,
|
||||
status = currencyStatus,
|
||||
actions = actions,
|
||||
isAccountMode = isAccountMode,
|
||||
account = accountWithAdded.accountStatus,
|
||||
)
|
||||
val expandedKey = portfolioItem.userWallet.walletId to currencyStatus.currency.id
|
||||
val isExpand = expanded.contains(expandedKey)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ internal class PortfolioTokenUMConverter(
|
|||
private val isBalanceHidden: Boolean,
|
||||
private val onTokenItemClick: (CryptoCurrencyStatus) -> Unit,
|
||||
private val tokenActionsHandler: TokenActionsHandler,
|
||||
private val isRedesignEnabled: Boolean,
|
||||
) : Converter<CryptoCurrencyData, PortfolioTokenUM> {
|
||||
|
||||
fun convertV2(
|
||||
|
|
@ -38,7 +39,11 @@ internal class PortfolioTokenUMConverter(
|
|||
walletId = value.userWallet.walletId,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isQuickActionsShown = isQuickActionsShown,
|
||||
quickActions = quickActions(cryptoData = value, tokenActionsHandler = tokenActionsHandler),
|
||||
quickActions = quickActions(
|
||||
cryptoData = value,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = isRedesignEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +62,11 @@ internal class PortfolioTokenUMConverter(
|
|||
walletId = value.userWallet.walletId,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isQuickActionsShown = false,
|
||||
quickActions = quickActions(cryptoData = value, tokenActionsHandler = tokenActionsHandler),
|
||||
quickActions = quickActions(
|
||||
cryptoData = value,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = isRedesignEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
|||
)
|
||||
.size(TangemTheme.dimens.size32)
|
||||
.semantics {
|
||||
contentDescription = if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
contentDescription = if (state is QuickActionUM.V1.Exchange && state.shouldShowBadge) {
|
||||
"Badge shown"
|
||||
} else {
|
||||
"Badge hidden"
|
||||
|
|
@ -188,7 +188,7 @@ private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
|||
}
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
if (state is QuickActionUM.V1.Exchange && state.shouldShowBadge) {
|
||||
drawBadge(containerColor = containerColor, offset = 4.dp)
|
||||
}
|
||||
},
|
||||
|
|
@ -229,9 +229,9 @@ private fun Preview() {
|
|||
) {
|
||||
PortfolioQuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
isVisible = isVisible,
|
||||
onActionClick = {},
|
||||
|
|
@ -250,9 +250,9 @@ private fun PreviewRtl() {
|
|||
Box(modifier = Modifier.background(color = TangemTheme.colors.background.action)) {
|
||||
PortfolioQuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
isVisible = true,
|
||||
onActionClick = {},
|
||||
|
|
|
|||
|
|
@ -129,9 +129,9 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
|
|||
isQuickActionsShown = false,
|
||||
quickActions = QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
QuickActionUM.V1.Buy,
|
||||
QuickActionUM.V1.Exchange(shouldShowBadge = true),
|
||||
QuickActionUM.V1.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue