Updated on 2026-08-14
This commit is contained in:
parent
c6fc1ab4da
commit
56992e4431
3 changed files with 91 additions and 294 deletions
|
|
@ -1,58 +1,26 @@
|
|||
package com.tangem.features.markets.portfolio.impl.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.material3.Text
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.currency.icon.CoinIcon
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.token.TokenItem
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.portfolio.impl.ui.preview.PreviewMyPortfolioUMProvider
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.PortfolioTokenUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState as TokenFiatAmountState
|
||||
|
||||
// TODO add rest of the balance states ([REDACTED_TASK_KEY] [Markets] Portfolio token item UI Improvement)
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun PortfolioItem(state: PortfolioTokenUM, lastInList: Boolean, modifier: Modifier = Modifier) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
|
||||
Column(modifier) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
hapticManager.perform(TangemHapticEffect.View.ContextClick)
|
||||
state.onClick()
|
||||
},
|
||||
onLongClick = {
|
||||
hapticManager.perform(TangemHapticEffect.View.LongPress)
|
||||
state.onLongTap()
|
||||
},
|
||||
)
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing15,
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Content(state)
|
||||
}
|
||||
TokenItem(state = state.tokenItemState, isBalanceHidden = state.isBalanceHidden)
|
||||
|
||||
PortfolioQuickActions(
|
||||
modifier = Modifier.padding(
|
||||
|
|
@ -68,225 +36,77 @@ internal fun PortfolioItem(state: PortfolioTokenUM, lastInList: Boolean, modifie
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.Content(state: PortfolioTokenUM) {
|
||||
// TODO add custom token
|
||||
CoinIcon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size36),
|
||||
url = state.iconUrl,
|
||||
alpha = 1f, // TODO add disabled state
|
||||
colorFilter = null,
|
||||
fallbackResId = R.drawable.ic_custom_token_44,
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2),
|
||||
) {
|
||||
when (state.balanceContent) {
|
||||
is PortfolioTokenUM.BalanceContent.Disabled -> {
|
||||
Disabled(
|
||||
state = state,
|
||||
disabledText = state.balanceContent.text.resolveReference(),
|
||||
)
|
||||
}
|
||||
PortfolioTokenUM.BalanceContent.Loading -> {
|
||||
Loading(state = state)
|
||||
}
|
||||
is PortfolioTokenUM.BalanceContent.TokenBalance -> {
|
||||
TokenBalance(
|
||||
state = state,
|
||||
content = state.balanceContent,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColumnScope.TokenBalance(state: PortfolioTokenUM, content: PortfolioTokenUM.BalanceContent.TokenBalance) {
|
||||
val balance = if (content.hidden) {
|
||||
StringsSigns.STARS
|
||||
} else {
|
||||
content.balance
|
||||
}
|
||||
val tokenAmount = if (content.hidden) {
|
||||
StringsSigns.STARS
|
||||
} else {
|
||||
content.tokenAmount
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
text = state.title,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
text = balance,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = state.subtitle,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
Text(
|
||||
text = tokenAmount,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColumnScope.Loading(state: PortfolioTokenUM) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
text = state.title,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
TextShimmer(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size40)
|
||||
.alignByBaseline(),
|
||||
style = TangemTheme.typography.body2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = state.subtitle,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
TextShimmer(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size40)
|
||||
.alignByBaseline(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Disabled(state: PortfolioTokenUM, disabledText: String, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
Modifier.weight(1f),
|
||||
) {
|
||||
Text(
|
||||
text = state.title,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = state.subtitle,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = disabledText,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
private fun Preview(@PreviewParameter(PortfolioTokenUMProvider::class) tokenUM: PortfolioTokenUM) {
|
||||
TangemThemePreview {
|
||||
var quickActionsShown by remember { mutableStateOf(false) }
|
||||
var quickActionsShown2 by remember { mutableStateOf(false) }
|
||||
val sampleToken = PreviewMyPortfolioUMProvider().sampleToken
|
||||
var quickActionsShown by remember { mutableStateOf(value = false) }
|
||||
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
) {
|
||||
Column {
|
||||
PortfolioItem(
|
||||
state = sampleToken
|
||||
.copy(
|
||||
onClick = {
|
||||
if (quickActionsShown2) {
|
||||
quickActionsShown2 = false
|
||||
}
|
||||
quickActionsShown = quickActionsShown.not()
|
||||
},
|
||||
isQuickActionsShown = quickActionsShown,
|
||||
),
|
||||
lastInList = true,
|
||||
)
|
||||
PortfolioItem(
|
||||
state = sampleToken
|
||||
.copy(
|
||||
onClick = {
|
||||
if (quickActionsShown) {
|
||||
quickActionsShown = false
|
||||
}
|
||||
quickActionsShown2 = quickActionsShown2.not()
|
||||
},
|
||||
isQuickActionsShown = quickActionsShown2,
|
||||
),
|
||||
lastInList = true,
|
||||
)
|
||||
PortfolioItem(
|
||||
state = sampleToken
|
||||
.copy(
|
||||
balanceContent = (
|
||||
sampleToken.balanceContent
|
||||
as PortfolioTokenUM.BalanceContent.TokenBalance
|
||||
)
|
||||
.copy(hidden = true),
|
||||
),
|
||||
lastInList = true,
|
||||
)
|
||||
PortfolioItem(
|
||||
state = sampleToken
|
||||
.copy(
|
||||
balanceContent = PortfolioTokenUM.BalanceContent.Disabled(
|
||||
stringReference("No Address"),
|
||||
),
|
||||
),
|
||||
lastInList = true,
|
||||
)
|
||||
PortfolioItem(
|
||||
state = sampleToken
|
||||
.copy(balanceContent = PortfolioTokenUM.BalanceContent.Loading),
|
||||
lastInList = true,
|
||||
)
|
||||
}
|
||||
val onItemClick = {
|
||||
quickActionsShown = quickActionsShown.not()
|
||||
}
|
||||
|
||||
PortfolioItem(
|
||||
state = tokenUM.copy(
|
||||
tokenItemState = when (tokenUM.tokenItemState) {
|
||||
is TokenItemState.Content -> tokenUM.tokenItemState.copy(onItemClick = onItemClick)
|
||||
is TokenItemState.Unreachable -> tokenUM.tokenItemState.copy(onItemClick = onItemClick)
|
||||
else -> tokenUM.tokenItemState
|
||||
},
|
||||
isQuickActionsShown = quickActionsShown,
|
||||
),
|
||||
lastInList = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class PortfolioTokenUMProvider : CollectionPreviewParameterProvider<PortfolioTokenUM>(
|
||||
collection = listOf(
|
||||
tokenUM.copy(
|
||||
tokenItemState = (tokenUM.tokenItemState as TokenItemState.Content).copy(
|
||||
fiatAmountState = contentFiatAmount.copy(hasStaked = true),
|
||||
),
|
||||
),
|
||||
tokenUM.copy(
|
||||
tokenItemState = tokenUM.tokenItemState.copy(
|
||||
fiatAmountState = contentFiatAmount.copy(text = DASH_SIGN),
|
||||
cryptoAmountState = tokenUM.tokenItemState.cryptoAmountState.copy(text = DASH_SIGN),
|
||||
),
|
||||
),
|
||||
tokenUM.copy(isBalanceHidden = true),
|
||||
tokenUM.copy(
|
||||
tokenItemState = TokenItemState.Unreachable(
|
||||
id = tokenUM.tokenItemState.id,
|
||||
iconState = tokenUM.tokenItemState.iconState,
|
||||
titleState = tokenUM.tokenItemState.titleState,
|
||||
subtitleState = tokenUM.tokenItemState.subtitleState,
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
),
|
||||
),
|
||||
tokenUM.copy(
|
||||
tokenItemState = TokenItemState.NoAddress(
|
||||
id = tokenUM.tokenItemState.id,
|
||||
iconState = tokenUM.tokenItemState.iconState,
|
||||
titleState = tokenUM.tokenItemState.titleState,
|
||||
subtitleState = tokenUM.tokenItemState.subtitleState,
|
||||
onItemLongClick = {},
|
||||
),
|
||||
),
|
||||
tokenUM.copy(
|
||||
tokenItemState = TokenItemState.Loading(
|
||||
id = tokenUM.tokenItemState.id,
|
||||
iconState = tokenUM.tokenItemState.iconState,
|
||||
titleState = tokenUM.tokenItemState.titleState as TokenItemState.TitleState.Content,
|
||||
subtitleState = tokenUM.tokenItemState.subtitleState,
|
||||
),
|
||||
),
|
||||
),
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val tokenUM = PreviewMyPortfolioUMProvider().sampleToken
|
||||
val contentFiatAmount = tokenUM.tokenItemState.fiatAmountState as TokenFiatAmountState.Content
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.features.markets.portfolio.impl.ui.preview
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.PortfolioTokenUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -32,19 +34,18 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
|
|||
)
|
||||
|
||||
val sampleToken = PortfolioTokenUM(
|
||||
id = "",
|
||||
networkId = "",
|
||||
iconUrl = "",
|
||||
balanceContent = PortfolioTokenUM.BalanceContent.TokenBalance(
|
||||
balance = "486,65 \$",
|
||||
tokenAmount = "733,71097 MATIC",
|
||||
hidden = false,
|
||||
tokenItemState = TokenItemState.Content(
|
||||
id = "",
|
||||
iconState = CurrencyIconState.Locked,
|
||||
titleState = TokenItemState.TitleState.Content(text = "My wallet"),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "486,65 \$"),
|
||||
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "733,71097 MATIC"),
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(value = "XRP Ledger token"),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
),
|
||||
title = "My wallet",
|
||||
subtitle = "XRP Ledger token",
|
||||
onClick = {},
|
||||
onLongTap = {},
|
||||
isQuickActionsShown = false,
|
||||
onQuickActionClick = {},
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,34 +1,10 @@
|
|||
package com.tangem.features.markets.portfolio.impl.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
|
||||
internal data class PortfolioTokenUM(
|
||||
val id: String,
|
||||
val networkId: String,
|
||||
val iconUrl: String,
|
||||
val title: String,
|
||||
val subtitle: String,
|
||||
val balanceContent: BalanceContent,
|
||||
val onClick: () -> Unit,
|
||||
val onLongTap: () -> Unit,
|
||||
val tokenItemState: TokenItemState,
|
||||
val isBalanceHidden: Boolean,
|
||||
val isQuickActionsShown: Boolean,
|
||||
val onQuickActionClick: (QuickActionUM) -> Unit,
|
||||
) {
|
||||
|
||||
// TODO add rest of the balance states ([REDACTED_TASK_KEY] [Markets] Portfolio token item UI Improvement)
|
||||
@Immutable
|
||||
sealed class BalanceContent {
|
||||
data class TokenBalance( // TODO Add stacking ([REDACTED_TASK_KEY] [Markets] Add staking info to portfolio token item)
|
||||
val balance: String,
|
||||
val tokenAmount: String,
|
||||
val hidden: Boolean,
|
||||
) : BalanceContent()
|
||||
|
||||
data class Disabled(
|
||||
val text: TextReference,
|
||||
) : BalanceContent()
|
||||
|
||||
data object Loading : BalanceContent()
|
||||
}
|
||||
}
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue