diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/row/TangemRowContainer.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/row/TangemRowContainer.kt index b1a24c2067..553edfc0e9 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/row/TangemRowContainer.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/row/TangemRowContainer.kt @@ -16,7 +16,7 @@ import kotlin.math.max /** * A custom layout composable that arranges its children in a row with specific layout IDs. */ -internal enum class TangemRowLayoutId { +enum class TangemRowLayoutId { HEAD, START_TOP, END_TOP, START_BOTTOM, END_BOTTOM, TAIL, EXTRA_TOP } @@ -29,7 +29,7 @@ internal enum class TangemRowLayoutId { */ @Suppress("LongMethod") @Composable -internal fun TangemRowContainer( +fun TangemRowContainer( modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(TangemTheme.dimens2.x3), content: @Composable () -> Unit, diff --git a/core/ui/src/main/res/drawable-night/img_nft_empty_collection.webp b/core/ui/src/main/res/drawable-night/img_nft_empty_collection.webp new file mode 100644 index 0000000000..8844ed902d Binary files /dev/null and b/core/ui/src/main/res/drawable-night/img_nft_empty_collection.webp differ diff --git a/core/ui/src/main/res/drawable/ic_chevron_small_right_24.xml b/core/ui/src/main/res/drawable/ic_chevron_small_right_24.xml new file mode 100644 index 0000000000..6ee9686437 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_chevron_small_right_24.xml @@ -0,0 +1,12 @@ + + + diff --git a/core/ui/src/main/res/drawable/img_nft_empty_collection.webp b/core/ui/src/main/res/drawable/img_nft_empty_collection.webp new file mode 100644 index 0000000000..9d18888c54 Binary files /dev/null and b/core/ui/src/main/res/drawable/img_nft_empty_collection.webp differ diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RemoveNFTCollectionsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RemoveNFTCollectionsTransformer.kt index 9308e8370f..ae06ec59bd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RemoveNFTCollectionsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/RemoveNFTCollectionsTransformer.kt @@ -20,6 +20,11 @@ internal class RemoveNFTCollectionsTransformer( } override fun transform(walletUM: WalletUM): WalletUM { - return walletUM // todo redesign main + return when (walletUM) { + is WalletUM.Content -> walletUM.copy( + nftState = WalletNFTItemUM.Hidden, + ) + is WalletUM.Locked -> walletUM + } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetNFTCollectionsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetNFTCollectionsTransformer.kt index 10a816e576..caa9d7ec25 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetNFTCollectionsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetNFTCollectionsTransformer.kt @@ -30,7 +30,16 @@ internal class SetNFTCollectionsTransformer( } override fun transform(walletUM: WalletUM): WalletUM { - return walletUM // todo redesign main + return when (walletUM) { + is WalletUM.Content -> walletUM.copy( + nftState = when { + nftCollections.allLoadedCollectionsEmpty() -> + WalletNFTItemUM.Empty(onItemClick) + else -> createContentNFTItemUM(onItemClick) + }, + ) + is WalletUM.Locked -> walletUM + } } private fun createContentNFTItemUM(onItemClick: () -> Unit): WalletNFTItemUM.Content { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletNFTItem2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletNFTItem2.kt new file mode 100644 index 0000000000..8759ecdf11 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletNFTItem2.kt @@ -0,0 +1,422 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.components + +import android.content.res.Configuration +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +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.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import coil.compose.SubcomposeAsyncImage +import com.tangem.core.ui.R +import com.tangem.core.ui.components.RectangleShimmer +import com.tangem.core.ui.components.TextShimmer +import com.tangem.core.ui.components.text.applyBladeBrush +import com.tangem.core.ui.ds.row.TangemRowContainer +import com.tangem.core.ui.ds.row.TangemRowLayoutId +import com.tangem.core.ui.extensions.clickableSingle +import com.tangem.core.ui.extensions.stringResourceSafe +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreviewRedesign +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNFTItemUM +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNFTItemUM.Content.CollectionPreview +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +@Composable +internal fun WalletNFTItem2(state: WalletNFTItemUM, modifier: Modifier = Modifier) { + val nftModifier = modifier + .clip(RoundedCornerShape(18.dp)) + .background(TangemTheme.colors2.surface.level3) + when (state) { + is WalletNFTItemUM.Hidden -> Unit + is WalletNFTItemUM.Empty -> WalletNFTItemEmpty( + modifier = nftModifier, + onClick = state.onItemClick, + ) + is WalletNFTItemUM.Failed -> WalletNFTItemFailed(modifier = nftModifier) + is WalletNFTItemUM.Loading -> WalletNFTItemLoading(modifier = nftModifier) + + is WalletNFTItemUM.Content -> WalletNFTItemContent( + state = state, + onClick = state.onItemClick, + modifier = nftModifier, + ) + } +} + +@Composable +private fun WalletNFTItemEmpty(onClick: () -> Unit, modifier: Modifier = Modifier) { + TangemRowContainer( + modifier = modifier.clickableSingle( + onClick = onClick, + ), + ) { + Image( + painter = painterResource(R.drawable.img_nft_empty_collection), + contentDescription = null, + modifier = Modifier + .size(TangemTheme.dimens2.x10) + .layoutId(TangemRowLayoutId.HEAD), + ) + Text( + text = stringResourceSafe(R.string.nft_wallet_title), + style = TangemTheme.typography2.bodySemibold16, + color = TangemTheme.colors2.text.neutral.primary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_TOP) + .padding(start = TangemTheme.dimens2.x2), + ) + Text( + text = stringResourceSafe(R.string.nft_wallet_receive_nft), + style = TangemTheme.typography2.captionSemibold12, + color = TangemTheme.colors2.text.neutral.secondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_BOTTOM) + .padding(start = TangemTheme.dimens2.x2), + ) + Icon( + imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24), + contentDescription = null, + tint = TangemTheme.colors2.graphic.neutral.tertiaryConstant, + modifier = Modifier.layoutId(TangemRowLayoutId.TAIL), + ) + } +} + +@Composable +private fun WalletNFTItemContent(state: WalletNFTItemUM.Content, onClick: () -> Unit, modifier: Modifier = Modifier) { + TangemRowContainer( + modifier = modifier.clickableSingle( + onClick = onClick, + ), + ) { + Box(modifier = Modifier.layoutId(TangemRowLayoutId.HEAD)) { + CollectionsPreviews( + previews = state.previews, + ) + } + Text( + text = stringResourceSafe(R.string.nft_wallet_title), + style = TangemTheme.typography2.bodySemibold16.applyBladeBrush( + isEnabled = state.isFlickering, + textColor = TangemTheme.colors2.text.neutral.primary, + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_TOP) + .padding(horizontal = TangemTheme.dimens2.x2), + ) + Text( + text = stringResourceSafe( + id = R.string.nft_wallet_count, + state.allAssetsCount, + state.collectionsCount, + ), + style = TangemTheme.typography2.captionSemibold12.applyBladeBrush( + isEnabled = state.isFlickering, + textColor = TangemTheme.colors2.text.neutral.secondary, + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_BOTTOM) + .padding(horizontal = TangemTheme.dimens2.x2), + ) + Icon( + imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_small_right_24), + contentDescription = null, + tint = TangemTheme.colors2.graphic.neutral.tertiaryConstant, + modifier = Modifier.layoutId(TangemRowLayoutId.TAIL), + ) + } +} + +@Composable +private fun WalletNFTItemFailed(modifier: Modifier = Modifier) { + TangemRowContainer( + modifier = modifier, + ) { + Box( + modifier = Modifier + .layoutId(TangemRowLayoutId.HEAD) + .size(TangemTheme.dimens2.x10) + .clip(RoundedCornerShape(TangemTheme.dimens2.x3)) + .background(TangemTheme.colors2.skeleton.backgroundPrimary), + contentAlignment = Alignment.Center, + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens2.x5), + painter = painterResource(R.drawable.ic_error_sync_24), + tint = TangemTheme.colors.icon.informative, + contentDescription = null, + ) + } + Text( + text = stringResourceSafe(R.string.nft_wallet_title), + style = TangemTheme.typography2.bodySemibold16, + color = TangemTheme.colors2.text.neutral.primary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_TOP) + .padding(start = TangemTheme.dimens2.x2), + ) + Text( + text = stringResourceSafe(R.string.nft_wallet_unable_to_load), + style = TangemTheme.typography2.captionSemibold12, + color = TangemTheme.colors2.text.neutral.secondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_BOTTOM) + .padding(start = TangemTheme.dimens2.x2), + ) + } +} + +@Composable +private fun WalletNFTItemLoading(modifier: Modifier = Modifier) { + TangemRowContainer( + modifier = modifier, + ) { + Box( + modifier = Modifier + .size(TangemTheme.dimens2.x10) + .clip(RoundedCornerShape(TangemTheme.dimens2.x3)) + .background(TangemTheme.colors2.skeleton.backgroundPrimary) + .layoutId(TangemRowLayoutId.HEAD), + ) + TextShimmer( + style = TangemTheme.typography2.bodySemibold16, + radius = TangemTheme.dimens2.x25, + + modifier = Modifier + .layoutId(TangemRowLayoutId.START_TOP) + .padding(start = TangemTheme.dimens2.x2) + .width(TangemTheme.dimens.size110), + ) + TextShimmer( + style = TangemTheme.typography2.captionSemibold12, + radius = TangemTheme.dimens2.x25, + modifier = Modifier + .layoutId(TangemRowLayoutId.START_BOTTOM) + .padding(start = TangemTheme.dimens2.x2) + .width(TangemTheme.dimens.size80), + ) + } +} + +@Composable +@Suppress("MagicNumber", "ReusedModifierInstance") +private fun BoxScope.CollectionsPreviews(previews: ImmutableList, modifier: Modifier = Modifier) { + val modifiers = when (previews.size) { + 1 -> previews1Modifiers() + 2 -> previews2Modifiers() + 3 -> previews3Modifiers() + else -> previews4Modifiers() + } + Box( + modifier = modifier + .size(TangemTheme.dimens2.x10), + ) { + previews.take(modifiers.size).forEachIndexed { index, s -> + val previewModifier = modifiers[index] + when (s) { + is CollectionPreview.Image -> { + SubcomposeAsyncImage( + modifier = previewModifier, + model = s.url, + loading = { + RectangleShimmer() + }, + error = { + Box( + modifier = previewModifier.background(TangemTheme.colors2.surface.level2), + ) + }, + contentDescription = null, + ) + } + is CollectionPreview.More -> { + Icon( + modifier = previewModifier + .background(TangemTheme.colors2.surface.level2), + imageVector = ImageVector.vectorResource(R.drawable.ic_nft_preview_more_16), + tint = TangemTheme.colors2.text.neutral.secondary, + contentDescription = null, + ) + } + } + } + } +} + +@Composable +private fun previews1Modifiers(): List = listOf( + Modifier + .size(TangemTheme.dimens2.x10) + .clip(RoundedCornerShape(TangemTheme.dimens2.x3)), +) + +@Composable +private fun BoxScope.previews2Modifiers(): List = listOf( + Modifier + .padding(start = TangemTheme.dimens2.x0_5, top = TangemTheme.dimens2.x0_5) + .size(TangemTheme.dimens2.x6) + .clip(RoundedCornerShape(TangemTheme.dimens2.x2)) + .align(Alignment.TopStart), + Modifier + .zIndex(1f) + .padding(TangemTheme.dimens2.x0_5) + .clip(RoundedCornerShape(topStart = 10.dp)) + .background(TangemTheme.colors2.surface.level3) + .padding(start = TangemTheme.dimens2.x0_5, top = TangemTheme.dimens2.x0_5) + .size(TangemTheme.dimens2.x6) + .clip(RoundedCornerShape(TangemTheme.dimens2.x2)) + .align(Alignment.BottomEnd), +) + +@Composable +private fun BoxScope.previews3Modifiers(): List = listOf( + Modifier + .padding(start = 3.dp, top = 3.dp) + .size(17.8.dp) + .clip(RoundedCornerShape(6.dp)) + .align(Alignment.TopStart), + Modifier + .zIndex(1f) + .padding(top = 10.dp, end = 1.dp) + .clip(RoundedCornerShape(8.dp)) + .background(TangemTheme.colors2.surface.level3) + .padding(TangemTheme.dimens2.x0_5) + .size(18.dp) + .clip(RoundedCornerShape(6.dp)) + .align(Alignment.TopEnd), + Modifier + .padding(start = 9.dp, top = 2.dp) + .size(14.dp) + .clip(RoundedCornerShape(4.dp)) + .align(Alignment.BottomStart), +) + +@Composable +private fun BoxScope.previews4Modifiers(): List = listOf( + Modifier + .clip(RoundedCornerShape(6.dp)) + .size(18.dp) + .align(Alignment.TopStart), + Modifier + .clip(RoundedCornerShape(6.dp)) + .size(18.dp) + .align(Alignment.TopEnd), + Modifier + .clip(RoundedCornerShape(6.dp)) + .size(18.dp) + .align(Alignment.BottomStart), + Modifier + .clip(RoundedCornerShape(6.dp)) + .size(18.dp) + .align(Alignment.BottomEnd), +) + +@Preview(widthDp = 360) +@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun Preview_WalletNFTItem(@PreviewParameter(WalletNFTItemProvider2::class) state: WalletNFTItemUM) { + TangemThemePreviewRedesign { + WalletNFTItem2( + state = state, + modifier = Modifier + .background(TangemTheme.colors2.surface.level1), + ) + } +} + +private class WalletNFTItemProvider2 : CollectionPreviewParameterProvider( + collection = listOf( + WalletNFTItemUM.Empty( + onItemClick = { }, + ), + WalletNFTItemUM.Loading, + WalletNFTItemUM.Failed, + WalletNFTItemUM.Content( + previews = persistentListOf( + CollectionPreview.Image("img1"), + ), + allAssetsCount = 125, + collectionsCount = 11, + noCollectionAssetsCount = 0, + isFlickering = true, + onItemClick = { }, + ), + WalletNFTItemUM.Content( + previews = persistentListOf( + CollectionPreview.Image("img1"), + CollectionPreview.Image("img2"), + ), + allAssetsCount = 125, + collectionsCount = 11, + noCollectionAssetsCount = 0, + isFlickering = false, + onItemClick = { }, + ), + WalletNFTItemUM.Content( + previews = persistentListOf( + CollectionPreview.Image("img1"), + CollectionPreview.Image("img2"), + CollectionPreview.Image("img3"), + ), + allAssetsCount = 125, + collectionsCount = 11, + noCollectionAssetsCount = 0, + isFlickering = false, + onItemClick = { }, + ), + WalletNFTItemUM.Content( + previews = persistentListOf( + CollectionPreview.Image("img1"), + CollectionPreview.Image("img2"), + CollectionPreview.Image("img3"), + CollectionPreview.Image("img4"), + ), + allAssetsCount = 125, + collectionsCount = 11, + noCollectionAssetsCount = 0, + isFlickering = false, + onItemClick = { }, + ), + WalletNFTItemUM.Content( + previews = persistentListOf( + CollectionPreview.Image("img1"), + CollectionPreview.Image("img2"), + CollectionPreview.Image("img3"), + CollectionPreview.More, + ), + allAssetsCount = 125, + collectionsCount = 11, + isFlickering = true, + noCollectionAssetsCount = 0, + onItemClick = { }, + ), + ), +) \ No newline at end of file