Updated on 2026-08-14
This commit is contained in:
parent
b0fc7b3057
commit
80d00dfb6b
26 changed files with 1003 additions and 56 deletions
|
|
@ -14,6 +14,11 @@ fun SpacerH(height: Dp, modifier: Modifier = Modifier) {
|
|||
Spacer(modifier = modifier.height(height))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SpacerH2(modifier: Modifier = Modifier) {
|
||||
SpacerH(2.dp, modifier)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SpacerH4(modifier: Modifier = Modifier) {
|
||||
SpacerH(4.dp, modifier)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.markets.tokenlist.impl.ui.components
|
||||
package com.tangem.core.ui.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
|
|
@ -8,16 +8,16 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.SecondarySmallButton
|
||||
import com.tangem.core.ui.components.buttons.SmallButtonConfig
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun UnableToLoadData(onRetryClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
fun UnableToLoadData(onRetryClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
|
|
@ -109,7 +109,7 @@ private fun BoxScope.ContentIconContainer(
|
|||
)
|
||||
|
||||
if (icon.topBadgeIconResId != null && shouldShowTopBadge) {
|
||||
TopBadge(
|
||||
CurrencyIconTopBadge(
|
||||
modifier = Modifier
|
||||
.offset(x = networkBadgeOffset, y = -networkBadgeOffset)
|
||||
.align(Alignment.TopEnd),
|
||||
|
|
@ -120,7 +120,7 @@ private fun BoxScope.ContentIconContainer(
|
|||
}
|
||||
|
||||
if (icon.showCustomBadge) {
|
||||
BottomBadge(
|
||||
CurrencyIconBottomBadge(
|
||||
modifier = Modifier.align(Alignment.BottomEnd),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.core.ui.components.currency.icon
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun CurrencyIconBottomBadge(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens.size12)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = CircleShape,
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(all = TangemTheme.dimens.spacing2)
|
||||
.matchParentSize()
|
||||
.background(
|
||||
color = TangemTheme.colors.icon.informative,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ import androidx.compose.ui.res.painterResource
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun TopBadge(
|
||||
fun CurrencyIconTopBadge(
|
||||
@DrawableRes iconResId: Int,
|
||||
alpha: Float,
|
||||
colorFilter: ColorFilter?,
|
||||
|
|
@ -38,26 +38,4 @@ internal fun TopBadge(
|
|||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun BottomBadge(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens.size12)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = CircleShape,
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(all = TangemTheme.dimens.spacing2)
|
||||
.matchParentSize()
|
||||
.background(
|
||||
color = TangemTheme.colors.icon.informative,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.text.KeyboardActions
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusManager
|
||||
|
|
@ -36,7 +37,11 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
@Composable
|
||||
fun SearchBar(state: SearchBarUM, modifier: Modifier = Modifier, colors: TextFieldColors = TangemSearchBarColors) {
|
||||
fun SearchBar(
|
||||
state: SearchBarUM,
|
||||
modifier: Modifier = Modifier,
|
||||
colors: TextFieldColors = TangemSearchBarDefaults.defaultTextFieldColors,
|
||||
) {
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
|
|
@ -161,18 +166,30 @@ private fun ClearButton(
|
|||
}
|
||||
}
|
||||
|
||||
private val TangemSearchBarColors: TextFieldColors
|
||||
@Composable
|
||||
get() = TextFieldDefaults.colors().copy(
|
||||
focusedContainerColor = TangemTheme.colors.field.primary,
|
||||
unfocusedContainerColor = TangemTheme.colors.field.primary,
|
||||
focusedTextColor = TangemTheme.colors.text.primary1,
|
||||
unfocusedTextColor = TangemTheme.colors.text.primary1,
|
||||
cursorColor = TangemTheme.colors.icon.primary1,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
)
|
||||
object TangemSearchBarDefaults {
|
||||
val defaultTextFieldColors: TextFieldColors
|
||||
@Composable @Stable get() = TextFieldDefaults.colors().copy(
|
||||
focusedContainerColor = TangemTheme.colors.field.primary,
|
||||
unfocusedContainerColor = TangemTheme.colors.field.primary,
|
||||
focusedTextColor = TangemTheme.colors.text.primary1,
|
||||
unfocusedTextColor = TangemTheme.colors.text.primary1,
|
||||
cursorColor = TangemTheme.colors.icon.primary1,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
)
|
||||
val secondaryTextFieldColors: TextFieldColors
|
||||
@Composable @Stable get() = TextFieldDefaults.colors().copy(
|
||||
focusedContainerColor = TangemTheme.colors.field.focused,
|
||||
unfocusedContainerColor = TangemTheme.colors.field.focused,
|
||||
focusedTextColor = TangemTheme.colors.text.primary1,
|
||||
unfocusedTextColor = TangemTheme.colors.text.primary1,
|
||||
cursorColor = TangemTheme.colors.icon.primary1,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
)
|
||||
}
|
||||
|
||||
// region Previews
|
||||
@Preview(widthDp = 328)
|
||||
|
|
|
|||
16
core/ui/src/main/res/drawable/ic_nft_placeholder_76.xml
Normal file
16
core/ui/src/main/res/drawable/ic_nft_placeholder_76.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="76dp"
|
||||
android:height="76dp"
|
||||
android:viewportWidth="76"
|
||||
android:viewportHeight="76">
|
||||
<path
|
||||
android:pathData="M26.284,20.9C23.136,20.9 20.584,23.451 20.584,26.6C20.584,29.748 23.136,32.3 26.284,32.3C29.432,32.3 31.984,29.748 31.984,26.6C31.984,23.451 29.432,20.9 26.284,20.9Z"
|
||||
android:fillColor="#C9C9C9"/>
|
||||
<path
|
||||
android:pathData="M9.118,18.911L33.829,4.644C34.961,3.99 36.411,4.418 37.007,5.581C37.564,6.666 37.172,7.996 36.116,8.606L11.602,22.758V47.139L20.57,40.834C21.884,39.911 23.61,39.822 25.012,40.604L35.544,46.484L50.911,35.182C52.29,34.169 54.147,34.097 55.599,35.003L64.399,40.49V25.046C64.399,23.782 65.423,22.758 66.686,22.758C67.949,22.758 68.973,23.782 68.973,25.046V53.468C68.973,54.961 68.176,56.341 66.883,57.088L40.09,72.557C38.797,73.303 37.204,73.303 35.911,72.557L9.118,57.088C7.825,56.341 7.028,54.961 7.028,53.468V22.531C7.028,21.038 7.825,19.658 9.118,18.911ZM53.406,39.026L64.399,45.881V53.24L38,68.481L11.602,53.24V52.731L22.999,44.719L33.535,50.602C34.965,51.4 36.73,51.29 38.049,50.319L53.406,39.026Z"
|
||||
android:fillColor="#C9C9C9"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M56.891,1.843C55.743,1.843 54.813,2.774 54.813,3.921V9.265H48.875C47.727,9.265 46.797,10.196 46.797,11.343C46.797,12.491 47.727,13.421 48.875,13.421H54.813V18.765C54.813,19.913 55.743,20.843 56.891,20.843C58.038,20.843 58.969,19.913 58.969,18.765V13.421H64.906C66.054,13.421 66.984,12.491 66.984,11.343C66.984,10.196 66.054,9.265 64.906,9.265H58.969V3.921C58.969,2.774 58.038,1.843 56.891,1.843Z"
|
||||
android:fillColor="#C9C9C9"/>
|
||||
</vector>
|
||||
|
|
@ -16,7 +16,7 @@ import com.tangem.common.ui.charts.state.MarketChartLook
|
|||
import com.tangem.common.ui.charts.state.rememberMarketChartState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.markets.details.impl.ui.state.MarketsTokenDetailsUM
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
|
||||
@Composable
|
||||
internal fun MarketTokenDetailsChart(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.markets.details.impl.ui.state.MarketsTokenDetailsUM
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
|
||||
internal fun LazyListScope.tokenMarketDetailsBody(
|
||||
state: MarketsTokenDetailsUM.Body,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.components.buttons.SecondarySmallButton
|
||||
import com.tangem.core.ui.components.buttons.SmallButtonConfig
|
||||
import com.tangem.core.ui.components.list.InfiniteListHandler
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
internal data class NFTCollectionAssetUM(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val imageUrl: String?,
|
||||
val price: NFTSalePriceUM,
|
||||
val onItemClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal sealed class NFTCollectionAssetsListUM {
|
||||
data object Collapsed : NFTCollectionAssetsListUM()
|
||||
|
||||
@Immutable
|
||||
sealed class Expanded : NFTCollectionAssetsListUM() {
|
||||
data class Loading(val itemsCount: Int) : Expanded()
|
||||
data class Failed(val onRetryClick: () -> Unit) : Expanded()
|
||||
data class Content(val items: ImmutableList<NFTCollectionAssetUM>) : Expanded()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class NFTCollectionUM(
|
||||
val id: String,
|
||||
val name: String,
|
||||
@DrawableRes val networkIconId: Int,
|
||||
val logoUrl: String?,
|
||||
val description: TextReference,
|
||||
val assets: NFTCollectionAssetsListUM,
|
||||
val onExpandClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal sealed class NFTCollectionsUM {
|
||||
|
||||
data class Empty(
|
||||
val onReceiveClick: () -> Unit,
|
||||
) : NFTCollectionsUM()
|
||||
|
||||
data class Loading(
|
||||
val onReceiveClick: () -> Unit,
|
||||
) : NFTCollectionsUM()
|
||||
|
||||
data class Failed(
|
||||
val onRetryClick: () -> Unit,
|
||||
val onReceiveClick: () -> Unit,
|
||||
) : NFTCollectionsUM()
|
||||
|
||||
data class Content(
|
||||
val search: SearchBarUM,
|
||||
val collections: ImmutableList<NFTCollectionUM>,
|
||||
val warnings: ImmutableList<NFTCollectionsWarningUM>,
|
||||
val onReceiveClick: () -> Unit,
|
||||
) : NFTCollectionsUM()
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
|
||||
internal data class NFTCollectionsWarningUM(val config: NotificationConfig)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
internal sealed class NFTSalePriceUM {
|
||||
data object Loading : NFTSalePriceUM()
|
||||
data object Failed : NFTSalePriceUM()
|
||||
data class Content(val price: String) : NFTSalePriceUM()
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
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.datasource.CollectionPreviewParameterProvider
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconTopBadge
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetsListUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
||||
private const val CHEVRON_ROTATION_EXPANDED = 180f
|
||||
private const val CHEVRON_ROTATION_COLLAPSED = 0f
|
||||
|
||||
@Composable
|
||||
internal fun NFTCollection(state: NFTCollectionUM, modifier: Modifier = Modifier) {
|
||||
val isExpanded = state.assets is NFTCollectionAssetsListUM.Expanded
|
||||
|
||||
Column(
|
||||
modifier = modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = state.onExpandClick)
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing16,
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Logo(state)
|
||||
|
||||
Text(state)
|
||||
|
||||
val rotation by animateFloatAsState(
|
||||
targetValue = if (isExpanded) {
|
||||
CHEVRON_ROTATION_EXPANDED
|
||||
} else {
|
||||
CHEVRON_ROTATION_COLLAPSED
|
||||
},
|
||||
label = "chevron_rotation",
|
||||
)
|
||||
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.rotate(rotation)
|
||||
.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = R.drawable.ic_chevron_24),
|
||||
tint = if (isExpanded) {
|
||||
TangemTheme.colors.icon.primary1
|
||||
} else {
|
||||
TangemTheme.colors.icon.inactive
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Logo(state: NFTCollectionUM) {
|
||||
val networkBadgeOffset = TangemTheme.dimens.spacing6
|
||||
|
||||
Box(
|
||||
modifier = Modifier,
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.size(TangemTheme.dimens.size36),
|
||||
model = state.logoUrl,
|
||||
loading = {
|
||||
RectangleShimmer(radius = TangemTheme.dimens.radius8)
|
||||
},
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(shape = TangemTheme.shapes.roundedCorners8)
|
||||
.background(TangemTheme.colors.field.primary),
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
CurrencyIconTopBadge(
|
||||
modifier = Modifier
|
||||
.offset(x = networkBadgeOffset, y = -networkBadgeOffset)
|
||||
.align(Alignment.TopEnd),
|
||||
iconResId = state.networkIconId,
|
||||
alpha = 1f,
|
||||
colorFilter = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.Text(state: NFTCollectionUM) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
text = state.name,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing2),
|
||||
text = state.description.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollection(@PreviewParameter(NFTCollectionProvider::class) item: NFTCollectionUM) {
|
||||
TangemThemePreview {
|
||||
NFTCollection(
|
||||
state = item,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class NFTCollectionProvider : CollectionPreviewParameterProvider<NFTCollectionUM>(
|
||||
collection = listOf(
|
||||
NFTCollectionUM(
|
||||
id = "item1",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Collapsed,
|
||||
onExpandClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
id = "item2",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Expanded.Loading(
|
||||
itemsCount = 3,
|
||||
),
|
||||
onExpandClick = { },
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
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 coil.compose.SubcomposeAsyncImage
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH2
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetUM
|
||||
import com.tangem.features.nft.collections.entity.NFTSalePriceUM
|
||||
|
||||
@Composable
|
||||
internal fun NFTCollectionAsset(state: NFTCollectionAssetUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clickable { state.onItemClick() },
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier
|
||||
.aspectRatio(1f),
|
||||
model = state.imageUrl,
|
||||
loading = {
|
||||
RectangleShimmer(radius = TangemTheme.dimens.radius16)
|
||||
},
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.field.primary),
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
SpacerH12()
|
||||
Text(
|
||||
text = state.name,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
SpacerH2()
|
||||
NFTSalePrice(
|
||||
state = state.price,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 180, showBackground = true)
|
||||
@Preview(widthDp = 180, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollectionAsset(
|
||||
@PreviewParameter(NFTCollectionAssetProvider::class) state: NFTCollectionAssetUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
NFTCollectionAsset(
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class NFTCollectionAssetProvider : CollectionPreviewParameterProvider<NFTCollectionAssetUM>(
|
||||
collection = listOf(
|
||||
NFTCollectionAssetUM(
|
||||
id = "item1",
|
||||
name = "Nethers #0853",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Loading,
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
id = "item2",
|
||||
name = "Nethers #0854",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Failed,
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
id = "item3",
|
||||
name = "Nethers #0855",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Content("0.05 ETH"),
|
||||
onItemClick = { },
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
@Composable
|
||||
internal fun NFTCollectionAssetLoading(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.aspectRatio(1f),
|
||||
)
|
||||
SpacerH12()
|
||||
TextShimmer(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size86),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
SpacerH2()
|
||||
TextShimmer(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size48),
|
||||
style = TangemTheme.typography.caption2,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 180, showBackground = true)
|
||||
@Preview(widthDp = 180, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollectionAsset() {
|
||||
TangemThemePreview {
|
||||
NFTCollectionAssetLoading()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsWarningUM
|
||||
|
||||
@Composable
|
||||
internal fun NFTCollectionWarning(state: NFTCollectionsWarningUM, modifier: Modifier = Modifier) {
|
||||
Notification(
|
||||
modifier = modifier,
|
||||
config = state.config,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,318 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
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.tooling.preview.Preview
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.*
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetsListUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsUM
|
||||
import com.tangem.features.nft.collections.entity.NFTSalePriceUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun NFTCollectionsContent(state: NFTCollectionsUM.Content, modifier: Modifier = Modifier) {
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier,
|
||||
) {
|
||||
SearchBar(
|
||||
state = state.search,
|
||||
colors = TangemSearchBarDefaults.secondaryTextFieldColors,
|
||||
)
|
||||
state.warnings.fastForEach {
|
||||
NFTCollectionWarning(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing16),
|
||||
state = it,
|
||||
)
|
||||
}
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
state = listState,
|
||||
) {
|
||||
state.collections.fastForEach { collection ->
|
||||
item(key = collection.id) {
|
||||
NFTCollection(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = collection,
|
||||
)
|
||||
}
|
||||
when (val assets = collection.assets) {
|
||||
is NFTCollectionAssetsListUM.Collapsed -> Unit
|
||||
is NFTCollectionAssetsListUM.Expanded.Loading -> {
|
||||
assetsListLoading(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
)
|
||||
}
|
||||
is NFTCollectionAssetsListUM.Expanded.Failed -> {
|
||||
assetsListFailed(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
)
|
||||
}
|
||||
is NFTCollectionAssetsListUM.Expanded.Content -> {
|
||||
assetsListContent(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter),
|
||||
text = stringResourceSafe(R.string.nft_collections_receive),
|
||||
onClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.assetsListLoading(
|
||||
collectionId: String,
|
||||
content: NFTCollectionAssetsListUM.Expanded.Loading,
|
||||
) {
|
||||
val itemsCount = content.itemsCount
|
||||
val rowCount = (itemsCount + 1) / 2
|
||||
repeat(rowCount) { rowIndex ->
|
||||
item(
|
||||
key = "loading_${collectionId}_$rowIndex",
|
||||
) {
|
||||
val paddingValues = PaddingValues(
|
||||
start = TangemTheme.dimens.spacing6,
|
||||
top = TangemTheme.dimens.spacing6,
|
||||
end = TangemTheme.dimens.spacing6,
|
||||
bottom = TangemTheme.dimens.spacing20,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing6)
|
||||
.animateItem(),
|
||||
) {
|
||||
NFTCollectionAssetLoading(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues),
|
||||
)
|
||||
if (rowIndex == rowCount - 1 && itemsCount % 2 != 0) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues),
|
||||
)
|
||||
} else {
|
||||
NFTCollectionAssetLoading(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.assetsListFailed(collectionId: String, content: NFTCollectionAssetsListUM.Expanded.Failed) {
|
||||
item(
|
||||
key = "failed_$collectionId",
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size142),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
UnableToLoadData(
|
||||
onRetryClick = content.onRetryClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.assetsListContent(
|
||||
collectionId: String,
|
||||
content: NFTCollectionAssetsListUM.Expanded.Content,
|
||||
) {
|
||||
val items = content.items
|
||||
val itemsCount = items.size
|
||||
val rowCount = (itemsCount + 1) / 2
|
||||
repeat(rowCount) { rowIndex ->
|
||||
val item1 = items[rowIndex * 2]
|
||||
val item2 = items.getOrNull(rowIndex * 2 + 1)
|
||||
item(
|
||||
key = "content_${collectionId}_${item1.id}_${item2?.id}",
|
||||
) {
|
||||
val paddingValues = PaddingValues(
|
||||
start = TangemTheme.dimens.spacing6,
|
||||
top = TangemTheme.dimens.spacing6,
|
||||
end = TangemTheme.dimens.spacing6,
|
||||
bottom = TangemTheme.dimens.spacing20,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing6)
|
||||
.animateItem(),
|
||||
) {
|
||||
NFTCollectionAsset(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues),
|
||||
state = item1,
|
||||
)
|
||||
if (item2 == null) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues),
|
||||
)
|
||||
} else {
|
||||
NFTCollectionAsset(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(paddingValues),
|
||||
state = item2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollectionsContent() {
|
||||
TangemThemePreview {
|
||||
NFTCollectionsContent(
|
||||
state = NFTCollectionsUM.Content(
|
||||
search = SearchBarUM(
|
||||
placeholderText = resourceReference(R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = {},
|
||||
isActive = false,
|
||||
onActiveChange = { },
|
||||
),
|
||||
collections = persistentListOf(
|
||||
NFTCollectionUM(
|
||||
id = "item1",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Collapsed,
|
||||
onExpandClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
id = "item2",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Expanded.Loading(
|
||||
itemsCount = 1,
|
||||
),
|
||||
onExpandClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
id = "item3",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Expanded.Failed(
|
||||
onRetryClick = { },
|
||||
),
|
||||
onExpandClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
id = "item4",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Expanded.Content(
|
||||
items = persistentListOf(
|
||||
NFTCollectionAssetUM(
|
||||
id = "item1",
|
||||
name = "Nethers #0854",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Content("0.05 ETH"),
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
id = "item2",
|
||||
name = "Nethers #0855",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Loading,
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
id = "item3",
|
||||
name = "Nethers #0856",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Failed,
|
||||
onItemClick = { },
|
||||
),
|
||||
),
|
||||
),
|
||||
onExpandClick = { },
|
||||
),
|
||||
),
|
||||
warnings = persistentListOf(
|
||||
NFTCollectionsWarningUM(
|
||||
config = NotificationConfig(
|
||||
title = TextReference.Res(R.string.nft_collections_warning_title),
|
||||
subtitle = TextReference.Res(R.string.nft_collections_warning_subtitle),
|
||||
iconResId = R.drawable.ic_alert_triangle_20,
|
||||
),
|
||||
),
|
||||
),
|
||||
onReceiveClick = { },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
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.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun NFTCollectionsEmpty(state: NFTCollectionsUM.Empty, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing16)
|
||||
.align(Alignment.Center),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_nft_placeholder_76),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing24),
|
||||
text = stringResource(R.string.nft_collections_empty_title),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
||||
text = stringResource(R.string.nft_collections_empty_description),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing48)
|
||||
.wrapContentWidth(),
|
||||
text = stringResourceSafe(R.string.nft_collections_receive),
|
||||
onClick = state.onReceiveClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollectionsEmpty() {
|
||||
TangemThemePreview {
|
||||
NFTCollectionsEmpty(
|
||||
state = NFTCollectionsUM.Empty(
|
||||
onReceiveClick = { },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun NFTCollectionsFailed(state: NFTCollectionsUM.Failed, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
UnableToLoadData(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center),
|
||||
onRetryClick = state.onRetryClick,
|
||||
)
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter),
|
||||
text = stringResourceSafe(R.string.nft_collections_receive),
|
||||
onClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollectionsFailed() {
|
||||
TangemThemePreview {
|
||||
NFTCollectionsFailed(
|
||||
state = NFTCollectionsUM.Failed(
|
||||
onRetryClick = { },
|
||||
onReceiveClick = { },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.features.nft.collections.ui
|
||||
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.collections.entity.NFTSalePriceUM
|
||||
|
||||
@Composable
|
||||
internal fun NFTSalePrice(state: NFTSalePriceUM, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
is NFTSalePriceUM.Content -> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = state.price,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
is NFTSalePriceUM.Failed -> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = "",
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
is NFTSalePriceUM.Loading -> {
|
||||
TextShimmer(
|
||||
modifier = modifier
|
||||
.width(TangemTheme.dimens.size48),
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,9 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -18,6 +16,7 @@ import androidx.compose.ui.util.fastForEachIndexed
|
|||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.tokenlist.TokenListItem
|
||||
|
|
@ -74,16 +73,7 @@ internal fun TokenList(state: TokenListUM, modifier: Modifier = Modifier) {
|
|||
private fun SearchBar(searchBarUM: SearchBarUM) {
|
||||
SearchBar(
|
||||
state = searchBarUM,
|
||||
colors = TextFieldDefaults.colors().copy(
|
||||
focusedContainerColor = TangemTheme.colors.field.focused,
|
||||
unfocusedContainerColor = TangemTheme.colors.field.focused,
|
||||
focusedTextColor = TangemTheme.colors.text.primary1,
|
||||
unfocusedTextColor = TangemTheme.colors.text.primary1,
|
||||
cursorColor = TangemTheme.colors.icon.primary1,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
),
|
||||
colors = TangemSearchBarDefaults.secondaryTextFieldColors,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ private fun RowContentContainer(
|
|||
@Preview(widthDp = 360)
|
||||
@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_WalletNFTItem_InLight(@PreviewParameter(WalletNFTItemProvider::class) state: WalletNFTItemUM) {
|
||||
private fun Preview_WalletNFTItem(@PreviewParameter(WalletNFTItemProvider::class) state: WalletNFTItemUM) {
|
||||
TangemThemePreview {
|
||||
WalletNFTItem(
|
||||
state = state,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue