diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/block/information/InformationBlock.kt b/core/ui/src/main/java/com/tangem/core/ui/components/block/information/InformationBlock.kt index 3c5b7a606d..e5c28bf0a6 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/block/information/InformationBlock.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/block/information/InformationBlock.kt @@ -30,7 +30,7 @@ class InformationBlockContentScope(val scope: BoxScope) : BoxScope by scope @Composable fun InformationBlock( - title: @Composable BoxScope.() -> Unit, + title: (@Composable BoxScope.() -> Unit)?, modifier: Modifier = Modifier, contentHorizontalPadding: Dp = TangemTheme.dimens.spacing12, shape: Shape = TangemTheme.shapes.roundedCornersXMedium, @@ -43,7 +43,9 @@ fun InformationBlock( .background(color = TangemTheme.colors.background.action), horizontalAlignment = Alignment.Start, ) { - NetworkTitle(title = title, action = action) + if (title != null) { + NetworkTitle(title = title, action = action) + } if (content != null) { Box( diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/entity/NFTAssetUM.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/entity/NFTAssetUM.kt index e5bea7ed65..2b85b58fe8 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/entity/NFTAssetUM.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/entity/NFTAssetUM.kt @@ -7,29 +7,31 @@ import kotlinx.collections.immutable.ImmutableList data class NFTAssetUM( val name: String, - val salePrice: SalePrice, - val description: String?, - val rarity: Rarity?, - val media: Media?, + val media: Media, + val topInfo: TopInfo, val traits: ImmutableList, val baseInfoItems: ImmutableList, ) { - data class Media( - val mimetype: String?, - val url: String, - ) - data class Rarity( - val rank: String, - val label: String, - ) + @Immutable + sealed class TopInfo { + data object Empty : TopInfo() + data class Content( + val title: TextReference?, + val salePrice: SalePrice, + val description: String?, + val rarity: Rarity, + ) : TopInfo() + } - data class BlockItem( - val title: TextReference, - val titleTextEllipsis: TextEllipsis = TextEllipsis.End, - val value: String, - val valueTextEllipsis: TextEllipsis = TextEllipsis.End, - ) + @Immutable + sealed class Media { + data object Empty : Media() + data class Content( + val mimetype: String?, + val url: String, + ) : Media() + } @Immutable sealed class SalePrice { @@ -37,4 +39,21 @@ data class NFTAssetUM( data object Empty : SalePrice() data class Content(val value: String, val fiatValue: String) : SalePrice() } + + @Immutable + sealed class Rarity { + data object Empty : Rarity() + data class Content( + val rank: String, + val label: String, + val showDivider: Boolean, + ) : Rarity() + } + + data class BlockItem( + val title: TextReference, + val titleTextEllipsis: TextEllipsis = TextEllipsis.End, + val value: String, + val valueTextEllipsis: TextEllipsis = TextEllipsis.End, + ) } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt index 19448754bf..e421efcde8 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt @@ -28,10 +28,8 @@ internal class NFTDetailsModel @Inject constructor( value = NFTDetailsUM( nftAsset = NFTAssetUM( name = "", - salePrice = NFTAssetUM.SalePrice.Empty, - description = null, - rarity = null, - media = null, + media = NFTAssetUM.Media.Empty, + topInfo = NFTAssetUM.TopInfo.Empty, traits = persistentListOf(), baseInfoItems = persistentListOf(), ), diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsInfoGroup.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsInfoGroup.kt new file mode 100644 index 0000000000..974a3329d9 --- /dev/null +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsInfoGroup.kt @@ -0,0 +1,281 @@ +package com.tangem.features.nft.details.ui + +import android.content.res.Configuration +import androidx.compose.animation.* +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.TextShimmer +import com.tangem.core.ui.components.atoms.text.EllipsisText +import com.tangem.core.ui.components.block.information.InformationBlock +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.nft.details.entity.NFTAssetUM +import com.tangem.features.nft.impl.R + +@Composable +internal fun NFTDetailsInfoGroup( + state: NFTAssetUM.TopInfo, + onReadMoreClick: () -> Unit, + modifier: Modifier = Modifier, +) { + when (state) { + is NFTAssetUM.TopInfo.Empty -> Unit + is NFTAssetUM.TopInfo.Content -> { + InformationBlock( + modifier = modifier, + title = if (state.title != null) { + { NFTDetailsGroupTitle(state.title) } + } else { + null + }, + contentHorizontalPadding = 0.dp, + ) { + Column( + modifier = Modifier, + ) { + SalePrice(state.salePrice) + Description(state.description, onReadMoreClick) + Rarity(state.rarity) + } + } + } + } +} + +@Composable +private fun SalePrice(state: NFTAssetUM.SalePrice, modifier: Modifier = Modifier) { + AnimatedVisibility( + modifier = Modifier.fillMaxWidth().animateContentSize(), + visible = state !is NFTAssetUM.SalePrice.Empty, + enter = fadeIn(), + exit = fadeOut(), + ) { + when (state) { + is NFTAssetUM.SalePrice.Empty -> Unit + is NFTAssetUM.SalePrice.Loading -> { + Column( + modifier = modifier + .padding( + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing12, + ), + ) { + TextShimmer( + modifier = Modifier + .width(TangemTheme.dimens.size158), + style = TangemTheme.typography.head, + textSizeHeight = true, + ) + TextShimmer( + modifier = Modifier + .padding(top = TangemTheme.dimens.spacing4) + .width(TangemTheme.dimens.size90), + style = TangemTheme.typography.caption2, + textSizeHeight = true, + ) + } + } + is NFTAssetUM.SalePrice.Content -> { + Column( + modifier = modifier + .padding( + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing12, + ), + verticalArrangement = Arrangement.SpaceAround, + ) { + Text( + text = state.value, + style = TangemTheme.typography.head, + color = TangemTheme.colors.text.primary1, + ) + Text( + modifier = Modifier + .padding(top = TangemTheme.dimens.spacing4), + text = state.fiatValue, + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + ) + } + } + } + } +} + +@Composable +private fun Description(description: String?, onReadMoreClick: () -> Unit, modifier: Modifier = Modifier) { + if (!description.isNullOrEmpty()) { + // TODO configure right way to display 3 rows and "Read more" label + EllipsisText( + modifier = modifier + .clickable { onReadMoreClick() } + .padding( + horizontal = TangemTheme.dimens.spacing12, + vertical = TangemTheme.dimens.spacing8, + ), + text = description, + style = TangemTheme.typography.body2.copy( + color = TangemTheme.colors.text.tertiary, + ), + ) + } +} + +@Composable +private fun Rarity(state: NFTAssetUM.Rarity, modifier: Modifier = Modifier) { + when (state) { + is NFTAssetUM.Rarity.Empty -> Unit + is NFTAssetUM.Rarity.Content -> { + if (state.showDivider) { + Divider( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12), + ) + } + Row( + modifier = modifier + .fillMaxWidth() + .padding( + horizontal = TangemTheme.dimens.spacing6, + vertical = TangemTheme.dimens.spacing8, + ), + ) { + NFTDetailsGroupBlock( + modifier = Modifier + .weight(1f) + .padding( + horizontal = TangemTheme.dimens.spacing6, + vertical = TangemTheme.dimens.spacing4, + ), + title = resourceReference(R.string.nft_details_rarity_label), + value = stringReference(state.label), + ) + NFTDetailsGroupBlock( + modifier = Modifier + .weight(1f) + .padding( + horizontal = TangemTheme.dimens.spacing6, + vertical = TangemTheme.dimens.spacing4, + ), + title = resourceReference(R.string.nft_details_rarity_rank), + value = stringReference(state.rank), + ) + } + } + } +} + +@Composable +private fun Divider(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxWidth() + .height(TangemTheme.dimens.size8), + contentAlignment = Alignment.Center, + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(TangemTheme.dimens.size1) + .background(TangemTheme.colors.stroke.primary), + ) + } +} + +@Preview(widthDp = 360) +@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun Preview_NFTDetailsInfoBlock(@PreviewParameter(NFTAssetInfoProvider::class) state: NFTAssetUM.TopInfo) { + TangemThemePreview { + NFTDetailsInfoGroup( + state = state, + onReadMoreClick = { }, + ) + } +} + +@Suppress("LongMethod", "MagicNumber") +private class NFTAssetInfoProvider : CollectionPreviewParameterProvider( + collection = listOf( + NFTAssetUM.TopInfo.Content( + title = resourceReference(R.string.nft_details_last_sale_price), + salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"), + description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3), + rarity = NFTAssetUM.Rarity.Content( + rank = "Top 1% rarity", + label = "115.28", + showDivider = true, + ), + ), + NFTAssetUM.TopInfo.Content( + title = resourceReference(R.string.nft_details_last_sale_price), + salePrice = NFTAssetUM.SalePrice.Loading, + description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3), + rarity = NFTAssetUM.Rarity.Content( + rank = "Top 1% rarity", + label = "115.28", + showDivider = true, + ), + ), + NFTAssetUM.TopInfo.Content( + title = resourceReference(R.string.nft_details_last_sale_price), + salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"), + description = null, + rarity = NFTAssetUM.Rarity.Content( + rank = "Top 1% rarity", + label = "115.28", + showDivider = true, + ), + ), + NFTAssetUM.TopInfo.Content( + title = resourceReference(R.string.nft_details_last_sale_price), + salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"), + description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3), + rarity = NFTAssetUM.Rarity.Empty, + ), + NFTAssetUM.TopInfo.Content( + title = resourceReference(R.string.nft_details_last_sale_price), + salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"), + description = null, + rarity = NFTAssetUM.Rarity.Empty, + ), + NFTAssetUM.TopInfo.Content( + title = null, + salePrice = NFTAssetUM.SalePrice.Empty, + description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3), + rarity = NFTAssetUM.Rarity.Content( + rank = "Top 1% rarity", + label = "115.28", + showDivider = true, + ), + ), + NFTAssetUM.TopInfo.Content( + title = null, + salePrice = NFTAssetUM.SalePrice.Empty, + description = null, + rarity = NFTAssetUM.Rarity.Content( + rank = "Top 1% rarity", + label = "115.28", + showDivider = false, + ), + ), + NFTAssetUM.TopInfo.Content( + title = null, + salePrice = NFTAssetUM.SalePrice.Empty, + description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3), + rarity = NFTAssetUM.Rarity.Empty, + ), + ), +) \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsLogo.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsLogo.kt index 6c49a7f86e..3111614efd 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsLogo.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/ui/NFTDetailsLogo.kt @@ -26,30 +26,32 @@ import com.tangem.features.nft.details.entity.NFTAssetUM import com.tangem.features.nft.impl.R @Composable -internal fun NFTDetailsLogo(state: NFTAssetUM.Media?, modifier: Modifier = Modifier) { - if (state == null) { - Placeholder( - modifier = modifier - .fillMaxWidth(), - ) - } else { - SubcomposeAsyncImage( - modifier = modifier - .fillMaxWidth() - .clip(TangemTheme.shapes.roundedCornersXMedium), - model = ImageRequest.Builder(LocalContext.current) - .data(state.url) - .crossfade(true) - .build(), - loading = { - RectangleShimmer(radius = TangemTheme.dimens.radius16) - }, - error = { - Placeholder() - }, - contentScale = ContentScale.Crop, - contentDescription = null, - ) +internal fun NFTDetailsLogo(state: NFTAssetUM.Media, modifier: Modifier = Modifier) { + when (state) { + is NFTAssetUM.Media.Empty -> { + Placeholder( + modifier = modifier.fillMaxWidth(), + ) + } + is NFTAssetUM.Media.Content -> { + SubcomposeAsyncImage( + modifier = modifier + .fillMaxWidth() + .clip(TangemTheme.shapes.roundedCornersXMedium), + model = ImageRequest.Builder(LocalContext.current) + .data(state.url) + .crossfade(true) + .build(), + loading = { + RectangleShimmer(radius = TangemTheme.dimens.radius16) + }, + error = { + Placeholder() + }, + contentScale = ContentScale.Crop, + contentDescription = null, + ) + } } } @@ -72,7 +74,7 @@ private fun Placeholder(modifier: Modifier = Modifier) { @Preview(widthDp = 360) @Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -private fun Preview_NFTDetailsInfoBlock(@PreviewParameter(NFTAssetMediaProvider::class) state: NFTAssetUM.Media?) { +private fun Preview_NFTDetailsInfoBlock(@PreviewParameter(NFTAssetMediaProvider::class) state: NFTAssetUM.Media) { TangemThemePreview { NFTDetailsLogo( state = state, @@ -82,10 +84,10 @@ private fun Preview_NFTDetailsInfoBlock(@PreviewParameter(NFTAssetMediaProvider: } } -private class NFTAssetMediaProvider : CollectionPreviewParameterProvider( +private class NFTAssetMediaProvider : CollectionPreviewParameterProvider( collection = listOf( - null, - NFTAssetUM.Media( + NFTAssetUM.Media.Empty, + NFTAssetUM.Media.Content( mimetype = "image/jpeg", url = "img1", ),