Updated on 2026-08-14
This commit is contained in:
parent
7f4454c8d2
commit
98d0d9c75e
39 changed files with 266 additions and 3536 deletions
|
|
@ -10,9 +10,8 @@ class DefaultDesignFeatureToggles @Inject constructor(
|
|||
) : DesignFeatureToggles {
|
||||
|
||||
override val isRedesignEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.APP_REDESIGN_ENABLED)
|
||||
get() = true
|
||||
|
||||
override val isWarningsRefactoringEnabled: Boolean
|
||||
get() = isRedesignEnabled &&
|
||||
featureTogglesManager.isFeatureEnabled(FeatureToggles.AND_14829_WARNINGS_REFACTORING_ENABLED)
|
||||
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.AND_14829_WARNINGS_REFACTORING_ENABLED)
|
||||
}
|
||||
|
|
@ -98,15 +98,13 @@ internal fun RootContent(
|
|||
hostState = snackbarHostState,
|
||||
)
|
||||
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TangemTopSnackbarHost(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.statusBarsPadding()
|
||||
.padding(all = 16.dp),
|
||||
hostState = LocalTopSnackbarHostState.current,
|
||||
)
|
||||
}
|
||||
TangemTopSnackbarHost(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.statusBarsPadding()
|
||||
.padding(all = 16.dp),
|
||||
hostState = LocalTopSnackbarHostState.current,
|
||||
)
|
||||
}
|
||||
}
|
||||
EventMessageEffect()
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ import com.tangem.common.ui.charts.state.*
|
|||
import com.tangem.core.ui.components.SpacerH16
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
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.utils.DateTimeFormatters
|
||||
|
|
@ -317,19 +316,9 @@ private fun rememberMarketChartBottomAxis(
|
|||
|
||||
@Composable
|
||||
private fun rememberChartAxisGuidelineComponent(color: Color, isWithPadding: Boolean = true): LineComponent {
|
||||
val isRedesign = LocalRedesignEnabled.current
|
||||
val startPadding = TangemTheme.dimens2.x2_5
|
||||
|
||||
val startPadding = if (isRedesign) {
|
||||
TangemTheme.dimens2.x2_5
|
||||
} else {
|
||||
TangemTheme.dimens.spacing4
|
||||
}
|
||||
|
||||
val endPadding = if (isRedesign) {
|
||||
TangemTheme.dimens2.x2
|
||||
} else {
|
||||
TangemTheme.dimens.spacing4
|
||||
}
|
||||
val endPadding = TangemTheme.dimens2.x2
|
||||
|
||||
return rememberAxisGuidelineComponent(
|
||||
color = color,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ fun MarketListItemContentV2(model: MarketsListItemUM, modifier: Modifier = Modif
|
|||
.layoutId(layoutId = TangemRowLayoutId.END_TOP)
|
||||
.padding(start = TangemTheme.dimens2.x3)
|
||||
.testTag(tag = TokenElementsTestTags.TOKEN_FIAT_AMOUNT),
|
||||
price = model.price.text,
|
||||
priceChangeType = model.price.changeType,
|
||||
priceAnnotated = model.price.annotated,
|
||||
priceValue = model.price.fiatPrice,
|
||||
|
|
|
|||
|
|
@ -3,21 +3,12 @@ package com.tangem.common.ui.markets
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
|
||||
@Composable
|
||||
fun MarketsListItem(model: MarketsListItemUM, modifier: Modifier = Modifier, onClick: () -> Unit = {}) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
MarketsListItemV2(
|
||||
model = model,
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
)
|
||||
} else {
|
||||
MarketsListItemV1(
|
||||
model = model,
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
MarketsListItemV2(
|
||||
model = model,
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
|
@ -7,92 +7,15 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.core.ui.windowsize.WindowSizeType
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun MarketsListItemPlaceholder() {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
MarketsListItemPlaceholderV2()
|
||||
} else {
|
||||
MarketsListItemPlaceholderV1()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun MarketsListItemPlaceholderV1() {
|
||||
val density = LocalDensity.current
|
||||
val windowSize = LocalWindowSize.current
|
||||
val sp12 = with(density) { 12.sp.toDp() }
|
||||
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = TangemTheme.dimens.spacing16,
|
||||
vertical = TangemTheme.dimens.spacing15,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
CircleShimmer(Modifier.size(TangemTheme.dimens.size36))
|
||||
|
||||
SpacerW12()
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens.spacing4),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size70)
|
||||
.height(sp12),
|
||||
radius = TangemTheme.dimens.radius3,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(height = TangemTheme.dimens.spacing2)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens.spacing2),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size52)
|
||||
.height(sp12),
|
||||
radius = TangemTheme.dimens.radius3,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (windowSize.widthAtLeast(WindowSizeType.Small)) {
|
||||
Spacer(Modifier.width(TangemTheme.dimens.spacing10))
|
||||
|
||||
Box {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.width(TangemTheme.dimens.size56)
|
||||
.height(TangemTheme.dimens.size12),
|
||||
radius = TangemTheme.dimens.radius3,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun MarketsListItemPlaceholderV2() {
|
||||
val windowSize = LocalWindowSize.current
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
|
|
|
|||
|
|
@ -1,330 +0,0 @@
|
|||
package com.tangem.common.ui.markets
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import com.tangem.common.ui.charts.MarketChartMini
|
||||
import com.tangem.common.ui.charts.state.MarketChartLook
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.common.ui.markets.preview.MarketChartListItemPreviewDataProvider
|
||||
import com.tangem.common.ui.tokens.TokenPriceText
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.currency.icon.CoinIcon
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeInPercent
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
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.res.LocalWindowSize
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.MarketsTestTags
|
||||
import com.tangem.core.ui.windowsize.WindowSizeType
|
||||
import com.tangem.utils.StringsSigns.MINUS
|
||||
import java.math.BigDecimal
|
||||
import kotlin.random.Random
|
||||
|
||||
@Composable
|
||||
fun MarketsListItemV1(model: MarketsListItemUM, modifier: Modifier = Modifier, onClick: () -> Unit = {}) {
|
||||
MarketsListItemContentV1(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RectangleShape)
|
||||
.clickable(onClick = onClick)
|
||||
.testTag(MarketsTestTags.TOKENS_LIST_ITEM),
|
||||
model = model,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MarketsListItemContentV1(model: MarketsListItemUM, modifier: Modifier = Modifier) {
|
||||
val windowSize = LocalWindowSize.current
|
||||
|
||||
Row(
|
||||
modifier = modifier.padding(
|
||||
horizontal = TangemTheme.dimens.spacing16,
|
||||
vertical = TangemTheme.dimens.spacing15,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
CoinIcon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size36),
|
||||
url = model.iconUrl,
|
||||
alpha = 1f,
|
||||
colorFilter = null,
|
||||
fallbackResId = R.drawable.ic_custom_token_44,
|
||||
)
|
||||
|
||||
SpacerW12()
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
TokenTitle(
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
name = model.name,
|
||||
currencySymbol = model.currencySymbol,
|
||||
)
|
||||
SpacerW8()
|
||||
TokenPriceText(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
price = model.price.text,
|
||||
priceChangeType = model.price.changeType,
|
||||
priceAnnotated = model.price.annotated,
|
||||
priceValue = model.price.fiatPrice,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(height = TangemTheme.dimens.spacing2)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
TokenSubtitle(
|
||||
modifier = Modifier
|
||||
.weight(1f, fill = false)
|
||||
.alignByBaseline(),
|
||||
ratingPosition = model.ratingPosition,
|
||||
marketCap = model.marketCap,
|
||||
stakingRate = model.stakingRate,
|
||||
)
|
||||
PriceChangeInPercent(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
textStyle = TangemTheme.typography.caption2,
|
||||
type = model.trendType,
|
||||
valueInPercent = model.trendPercentText,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (windowSize.widthAtLeast(WindowSizeType.Small)) {
|
||||
Spacer(Modifier.width(TangemTheme.dimens.spacing10))
|
||||
|
||||
Chart(
|
||||
chartType = model.chartType,
|
||||
chartRawData = model.chartData,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenTitle(name: String, currencySymbol: String, modifier: Modifier = Modifier) {
|
||||
Row(modifier = modifier) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.weight(1f, fill = false)
|
||||
.alignByBaseline(),
|
||||
text = name,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
SpacerW4()
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
text = currencySymbol,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption1,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Visible,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenSubtitle(
|
||||
ratingPosition: String?,
|
||||
marketCap: String?,
|
||||
stakingRate: TextReference?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
TokenRatingPlace(ratingPosition = ratingPosition)
|
||||
if (marketCap != null) {
|
||||
SpacerW4()
|
||||
TokenMarketCapText(
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
text = marketCap,
|
||||
)
|
||||
}
|
||||
if (stakingRate != null) {
|
||||
SpacerW4()
|
||||
StakingRate(stakingRate = stakingRate.resolveReference())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.TokenRatingPlace(ratingPosition: String?) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.alignByBaseline()
|
||||
.heightIn(min = TangemTheme.dimens.size16)
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = TangemTheme.shapes.roundedCornersSmall2,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing5),
|
||||
) {
|
||||
Text(
|
||||
text = ratingPosition ?: MINUS,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.StakingRate(stakingRate: String) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.alignByBaseline()
|
||||
.heightIn(min = TangemTheme.dimens.size16)
|
||||
.border(
|
||||
width = TangemTheme.dimens.size1,
|
||||
color = TangemTheme.colors.field.primary,
|
||||
shape = TangemTheme.shapes.roundedCornersSmall2,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing5),
|
||||
) {
|
||||
Text(
|
||||
text = stakingRate,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.TokenMarketCapText(text: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = modifier.alignByBaseline(),
|
||||
text = text,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Chart(chartType: MarketChartLook.Type, chartRawData: MarketChartRawData?) {
|
||||
val chartWidth = TangemTheme.dimens.size56
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = TangemTheme.dimens.spacing2)
|
||||
.size(height = TangemTheme.dimens.size24, width = chartWidth),
|
||||
) {
|
||||
if (chartRawData != null) {
|
||||
MarketChartMini(
|
||||
rawData = chartRawData,
|
||||
type = chartType,
|
||||
)
|
||||
} else {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size12)
|
||||
.align(Alignment.Center),
|
||||
radius = TangemTheme.dimens.radius3,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region preview
|
||||
@Preview(showBackground = true, widthDp = 360, name = "normal")
|
||||
@Preview(showBackground = true, widthDp = 360, name = "normal night", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Preview(showBackground = true, widthDp = 260, name = "small width")
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(MarketChartListItemPreviewDataProvider::class) state: MarketsListItemUM) {
|
||||
TangemThemePreview {
|
||||
var state1 by remember { mutableStateOf(state) }
|
||||
var state2 by remember { mutableStateOf(state) }
|
||||
var prices by remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
100 to PriceChangeType.NEUTRAL,
|
||||
200 to PriceChangeType.NEUTRAL,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.background(TangemTheme.colors.background.primary)) {
|
||||
MarketsListItemV1(
|
||||
modifier = Modifier,
|
||||
model = state1,
|
||||
)
|
||||
MarketsListItemV1(
|
||||
modifier = Modifier,
|
||||
model = state2,
|
||||
)
|
||||
Row {
|
||||
Button(
|
||||
onClick = {
|
||||
state1 = state1.copy(
|
||||
trendType = PriceChangeType.entries.random(),
|
||||
)
|
||||
state2 = state2.copy(
|
||||
trendType = PriceChangeType.entries.random(),
|
||||
)
|
||||
},
|
||||
) { Text(text = "trend") }
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
prices = prices.map { (price, _) ->
|
||||
if (Random.nextBoolean()) {
|
||||
price.inc() to PriceChangeType.UP
|
||||
} else {
|
||||
price.dec() to PriceChangeType.DOWN
|
||||
}
|
||||
}
|
||||
state1 = state1.copy(
|
||||
price = MarketsListItemUM.Price(
|
||||
text = "0.${prices[0].first}023 $",
|
||||
changeType = prices[0].second,
|
||||
fiatPrice = BigDecimal(123123),
|
||||
annotated = stringReference("0.${prices[0].first}023 $"),
|
||||
),
|
||||
)
|
||||
state2 = state2.copy(
|
||||
price = MarketsListItemUM.Price(
|
||||
text = "0.${prices[1].first}023 $",
|
||||
changeType = prices[1].second,
|
||||
fiatPrice = BigDecimal(123123),
|
||||
annotated = stringReference("0.${prices[0].first}023 $"),
|
||||
),
|
||||
)
|
||||
},
|
||||
) { Text(text = "price") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,81 +10,18 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Text view for token price.
|
||||
*
|
||||
* @param price Plain price string (used by V1 and as fallback for V2 when [priceAnnotated] is null).
|
||||
* @param priceAnnotated Optional styled price (locale-aware decimal separator + secondary fractional color).
|
||||
* @param priceValue Numeric price; drives the change animation (used as the LaunchedEffect key).
|
||||
* @param priceAnnotated Styled price (locale-aware decimal separator + secondary fractional color).
|
||||
* @param priceChangeType Type of the price change.
|
||||
*/
|
||||
@Composable
|
||||
fun TokenPriceText(
|
||||
priceValue: BigDecimal,
|
||||
price: String,
|
||||
priceAnnotated: TextReference,
|
||||
modifier: Modifier = Modifier,
|
||||
priceChangeType: PriceChangeType? = null,
|
||||
) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenPriceTextV2(
|
||||
priceValue = priceValue,
|
||||
priceAnnotated = priceAnnotated,
|
||||
modifier = modifier,
|
||||
priceChangeType = priceChangeType,
|
||||
)
|
||||
} else {
|
||||
TokenPriceTextV1(
|
||||
price = price,
|
||||
modifier = modifier,
|
||||
priceChangeType = priceChangeType,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenPriceTextV1(price: String, modifier: Modifier = Modifier, priceChangeType: PriceChangeType? = null) {
|
||||
val growColor = TangemTheme.colors.text.accent
|
||||
val fallColor = TangemTheme.colors.text.warning
|
||||
val generalColor = TangemTheme.colors.text.primary1
|
||||
|
||||
val color = remember(generalColor) { Animatable(generalColor) }
|
||||
var isAnimationSkipped by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(price) {
|
||||
if (isAnimationSkipped.not()) {
|
||||
isAnimationSkipped = true
|
||||
return@LaunchedEffect
|
||||
}
|
||||
|
||||
if (priceChangeType != null) {
|
||||
val nextColor = when (priceChangeType) {
|
||||
PriceChangeType.UP,
|
||||
-> growColor
|
||||
PriceChangeType.DOWN -> fallColor
|
||||
PriceChangeType.NEUTRAL -> return@LaunchedEffect
|
||||
}
|
||||
|
||||
color.animateTo(nextColor, snap())
|
||||
color.animateTo(generalColor, tween(durationMillis = 500))
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = price,
|
||||
color = color.value,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.body2,
|
||||
overflow = TextOverflow.Visible,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenPriceTextV2(
|
||||
priceValue: BigDecimal,
|
||||
priceAnnotated: TextReference,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.State
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioRoutes
|
||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||
|
||||
|
|
@ -16,19 +15,11 @@ internal fun AddToPortfolioBottomSheetSwitch(
|
|||
userPortfolioState: State<UserPortfolioUM?>? = null,
|
||||
onAddFromUserPortfolioClick: (() -> Unit)? = null,
|
||||
) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
AddToPortfolioBottomSheetV2(
|
||||
childStack = childStack,
|
||||
onBack = onBack,
|
||||
onDismiss = onDismiss,
|
||||
userPortfolioState = userPortfolioState,
|
||||
onAddFromUserPortfolioClick = onAddFromUserPortfolioClick,
|
||||
)
|
||||
} else {
|
||||
AddToPortfolioBottomSheet(
|
||||
childStack = childStack,
|
||||
onBack = onBack,
|
||||
onDismiss = onDismiss,
|
||||
)
|
||||
}
|
||||
AddToPortfolioBottomSheetV2(
|
||||
childStack = childStack,
|
||||
onBack = onBack,
|
||||
onDismiss = onDismiss,
|
||||
userPortfolioState = userPortfolioState,
|
||||
onAddFromUserPortfolioClick = onAddFromUserPortfolioClick,
|
||||
)
|
||||
}
|
||||
|
|
@ -3,13 +3,11 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio
|
|||
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.api.addtoportfolio.SelectedNetwork
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedPortfolio
|
||||
|
|
@ -31,17 +29,10 @@ internal class AddTokenComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val um = state.value ?: return
|
||||
if (LocalRedesignEnabled.current) {
|
||||
AddTokenContentV2(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
} else {
|
||||
AddTokenContent(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
}
|
||||
AddTokenContentV2(
|
||||
modifier = modifier,
|
||||
state = um,
|
||||
)
|
||||
}
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import com.tangem.core.decompose.di.ModelScoped
|
|||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.ToastMessage
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
|
|
@ -56,7 +55,6 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
val portfolioSelectorController: PortfolioSelectorController,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val callbackDelegate: AddToPortfolioCallbackDelegate,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||
private val getTokenMarketCryptoCurrency: GetTokenMarketCryptoCurrency,
|
||||
|
|
@ -182,9 +180,9 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
|
||||
setupPortfolioSelector(initialData, launchMode)
|
||||
|
||||
val shouldShowUserPortfolio = designFeatureToggles.isRedesignEnabled &&
|
||||
val shouldShowUserPortfolio =
|
||||
launchMode is AddToPortfolioManager.LaunchMode.ViaUserPortfolio &&
|
||||
initialData.hasAnyAddedCurrency(tokenMarketParams.id)
|
||||
initialData.hasAnyAddedCurrency(tokenMarketParams.id)
|
||||
|
||||
if (shouldShowUserPortfolio) {
|
||||
// suspend, must prepare UM before navigate to UserPortfolio
|
||||
|
|
@ -200,11 +198,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
AddToPortfolioManager.LaunchMode.Preselected -> null
|
||||
is AddToPortfolioManager.LaunchMode.ViaUserPortfolio,
|
||||
AddToPortfolioManager.LaunchMode.DirectAdd,
|
||||
-> if (designFeatureToggles.isRedesignEnabled) {
|
||||
getInitialSelection(initialData)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
-> getInitialSelection(initialData)
|
||||
}
|
||||
|
||||
val firstSelectedPortfolioFlow: Flow<SelectedPortfolio> =
|
||||
|
|
@ -272,15 +266,11 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
callbackDelegate.onChangePortfolioClick.receiveAsFlow()
|
||||
.onEach {
|
||||
middleNavigationJob?.cancel()
|
||||
middleNavigationJob = if (designFeatureToggles.isRedesignEnabled) {
|
||||
changePortfolioNavigationNewFlow(
|
||||
data = initialData,
|
||||
orderedNetworks = paramsSnapshot.networks,
|
||||
tokenParams = tokenMarketParams,
|
||||
)
|
||||
} else {
|
||||
changePortfolioNavigationFlow(initialData)
|
||||
}.launchIn(this)
|
||||
middleNavigationJob = changePortfolioNavigationNewFlow(
|
||||
data = initialData,
|
||||
orderedNetworks = paramsSnapshot.networks,
|
||||
tokenParams = tokenMarketParams,
|
||||
).launchIn(this)
|
||||
logAccountSelector(isAccountMode)
|
||||
navigation.pushNew(AddToPortfolioRoutes.PortfolioSelector)
|
||||
}
|
||||
|
|
@ -369,33 +359,6 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun changePortfolioNavigationFlow(data: AvailableToAddData): Flow<Unit> = flow {
|
||||
val selectedPortfolioValue = selectedPortfolio.first()
|
||||
val selectedAccount = selectedPortfolioValue.account.account.account.accountId
|
||||
portfolioSelectorController.selectAccount(selectedAccount)
|
||||
val changedPortfolio = setupPortfolioFlow(data)
|
||||
.drop(1)
|
||||
.onEach { portfolio ->
|
||||
val isSingleAvailableNetwork = portfolio.account.isSingleNetwork
|
||||
if (isSingleAvailableNetwork) {
|
||||
val singleNetwork = portfolio.account.availableToAddNetworks.first()
|
||||
callbackDelegate.onNetworkSelected.send(singleNetwork)
|
||||
} else {
|
||||
navigation.pushNew(routeToNetworkSelector(portfolio))
|
||||
}
|
||||
}
|
||||
val changedNetwork = setupNetworkFlow(changedPortfolio)
|
||||
combine(
|
||||
flow = changedPortfolio,
|
||||
flow2 = changedNetwork,
|
||||
transform = { newPortfolio, newNetwork ->
|
||||
selectedPortfolio.tryEmit(newPortfolio)
|
||||
selectedNetwork.tryEmit(newNetwork)
|
||||
navigation.popToFirst()
|
||||
},
|
||||
).collect { emit(it) }
|
||||
}
|
||||
|
||||
private fun changePortfolioNavigationNewFlow(
|
||||
data: AvailableToAddData,
|
||||
orderedNetworks: List<TokenMarketInfo.Network>,
|
||||
|
|
@ -432,7 +395,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
|||
currency = addedToken.currency,
|
||||
accountId = selectedPortfolio.account.account.account.accountId,
|
||||
).onEach { state ->
|
||||
val requestedQuickActions = toQuickActions(state.states, designFeatureToggles.isRedesignEnabled)
|
||||
val requestedQuickActions = toQuickActions(state.states, isRedesignEnabled = true)
|
||||
when {
|
||||
requestedQuickActions.isNotEmpty() -> {
|
||||
timerJob.cancel()
|
||||
|
|
|
|||
|
|
@ -49,17 +49,10 @@ 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,
|
||||
)
|
||||
}
|
||||
ChooseNetworkContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ import com.tangem.core.ui.ds.row.token.TangemTokenRow
|
|||
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
|
||||
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -136,13 +135,7 @@ private val ChooseTokenFullUM.isEmptyState: Boolean
|
|||
internal fun ChooseTokenScreen(state: ChooseTokenFullUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = if (LocalRedesignEnabled.current) {
|
||||
TangemTheme.colors2.surface.level2
|
||||
} else {
|
||||
TangemTheme.colors.background.secondary
|
||||
},
|
||||
)
|
||||
.background(color = TangemTheme.colors2.surface.level2)
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
|
|
@ -747,11 +740,7 @@ private fun LazyListScope.predefinedTokensListItems(state: PredefinedTokensUM) {
|
|||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.items.lastIndex,
|
||||
backgroundColor = if (LocalRedesignEnabled.current) {
|
||||
TangemTheme.colors2.surface.level1
|
||||
} else {
|
||||
TangemTheme.colors.background.primary
|
||||
},
|
||||
backgroundColor = TangemTheme.colors2.surface.level1,
|
||||
)
|
||||
.testTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
|
||||
.semantics { lazyListItemPosition = index },
|
||||
|
|
@ -811,13 +800,7 @@ private fun LazyListScope.emptyTokensList(modifier: Modifier = Modifier) {
|
|||
item("EmptyTokensList") {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = if (LocalRedesignEnabled.current) {
|
||||
TangemTheme.colors2.surface.level2
|
||||
} else {
|
||||
TangemTheme.colors.background.secondary
|
||||
},
|
||||
)
|
||||
.background(color = TangemTheme.colors2.surface.level2)
|
||||
.fillParentMaxSize(),
|
||||
) {
|
||||
Column(modifier = Modifier.align(Alignment.Center)) {
|
||||
|
|
@ -848,13 +831,7 @@ private fun LazyListScope.tokensNotFound(modifier: Modifier = Modifier) {
|
|||
item("TokensNotFound") {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = if (LocalRedesignEnabled.current) {
|
||||
TangemTheme.colors2.surface.level2
|
||||
} else {
|
||||
TangemTheme.colors.background.secondary
|
||||
},
|
||||
)
|
||||
.background(color = TangemTheme.colors2.surface.level2)
|
||||
.fillParentMaxSize(),
|
||||
) {
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -9,10 +9,8 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
||||
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
|
||||
|
|
@ -48,19 +46,11 @@ internal class DefaultPortfolioSelectorComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val listBottomPadding = PaddingValues(bottom = LocalTangemBottomSheetContentBottomInset.current)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
contentPadding = listBottomPadding,
|
||||
)
|
||||
} else {
|
||||
PortfolioSelectorContent(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
contentPadding = listBottomPadding,
|
||||
)
|
||||
}
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
contentPadding = listBottomPadding,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -45,19 +45,11 @@ internal fun PortfolioSelectorBS(
|
|||
)
|
||||
},
|
||||
content = {
|
||||
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),
|
||||
)
|
||||
}
|
||||
PortfolioSelectorContentV2(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,9 @@ 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.api.tokenactions.BottomAction
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.model.TokenActionsModel
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.TokenActionsContent
|
||||
import com.tangem.features.commonfeatures.impl.tokenactions.ui.TokenActionsContentV2
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -49,17 +47,10 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
|||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
val tokenActionsUM = state.value ?: return
|
||||
if (LocalRedesignEnabled.current || params.isRedesignForced) {
|
||||
TokenActionsContentV2(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
} else {
|
||||
TokenActionsContent(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
}
|
||||
TokenActionsContentV2(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
|||
import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
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
|
||||
|
|
@ -41,7 +40,6 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class TokenActionsUiBuilder @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
private val walletIconUMConverter: WalletIconUMConverter,
|
||||
|
|
@ -55,51 +53,12 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
|||
isBalanceHidden: Boolean,
|
||||
bottomAction: BottomAction,
|
||||
): TokenActionsUM {
|
||||
return if (designFeatureToggles.isRedesignEnabled || params.isRedesignForced) {
|
||||
buildV2(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
bottomAction = bottomAction,
|
||||
)
|
||||
} else {
|
||||
buildV1(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
bottomAction = bottomAction,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildV1(
|
||||
cryptoCurrencyData: CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
bottomAction: BottomAction,
|
||||
): 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 = null,
|
||||
subtitle2State = null,
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(status.currency.symbol)),
|
||||
onItemClick = null,
|
||||
onItemLongClick = null,
|
||||
)
|
||||
return TokenActionsUM(
|
||||
token = tokenUM,
|
||||
quickActions = quickActions(
|
||||
cryptoData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
isRedesignEnabled = false,
|
||||
context = params.context,
|
||||
),
|
||||
bottomActionText = bottomActionText(bottomAction),
|
||||
onBottomActionClick = {
|
||||
params.callbacks.onBottomActionClick(bottomAction)
|
||||
},
|
||||
return buildV2(
|
||||
cryptoCurrencyData = cryptoCurrencyData,
|
||||
tokenActionsHandler = tokenActionsHandler,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
bottomAction = bottomAction,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent.Params
|
||||
import com.tangem.features.markets.token.block.impl.model.TokenMarketBlockModel
|
||||
import com.tangem.features.markets.token.block.impl.ui.TokenMarketBlock
|
||||
import com.tangem.features.markets.token.block.impl.ui.TokenMarketBlockLegacy
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -29,17 +27,10 @@ internal class DefaultTokenMarketBlockComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenMarketBlock(
|
||||
tokenMarketBlockUM = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
TokenMarketBlockLegacy(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
TokenMarketBlock(
|
||||
tokenMarketBlockUM = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -1,229 +0,0 @@
|
|||
package com.tangem.features.markets.token.block.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
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.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.common.ui.charts.MarketChartMini
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.common.ui.tokens.TokenPriceText
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerW8
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeInPercent
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
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
|
||||
import com.tangem.features.markets.token.block.impl.model.formatter.toChartType
|
||||
import com.tangem.features.markets.token.block.impl.ui.state.TokenMarketBlockUM
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.BigDecimal
|
||||
import kotlin.random.Random
|
||||
|
||||
@Composable
|
||||
internal fun TokenMarketBlockLegacy(state: TokenMarketBlockUM, modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
enabled = state.currentPrice != null,
|
||||
onClick = state.onClick,
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
LeftSide(
|
||||
modifier = Modifier.weight(1f),
|
||||
symbol = state.currencySymbol,
|
||||
priceText = state.currentPrice,
|
||||
priceValue = state.currentPriceValue,
|
||||
priceAnnotated = state.priceAnnotated,
|
||||
percentText = state.h24Percent,
|
||||
type = state.priceChangeType,
|
||||
)
|
||||
SpacerW8()
|
||||
RightSide(
|
||||
modifier = Modifier,
|
||||
priceChangeType = state.priceChangeType,
|
||||
chartRawData = state.chartData,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun LeftSide(
|
||||
symbol: String,
|
||||
priceText: String?,
|
||||
priceValue: BigDecimal?,
|
||||
priceAnnotated: TextReference?,
|
||||
percentText: String?,
|
||||
type: PriceChangeType,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.wallet_marketplace_block_title, symbol),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
|
||||
if (priceText != null && percentText != null) {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
TokenPriceText(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
price = priceText,
|
||||
priceChangeType = type,
|
||||
priceValue = priceValue ?: BigDecimal.ZERO,
|
||||
priceAnnotated = priceAnnotated ?: TextReference.EMPTY,
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
PriceChangeInPercent(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
valueInPercent = percentText,
|
||||
type = type,
|
||||
textStyle = TangemTheme.typography.body2,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
text = stringResourceSafe(id = R.string.wallet_marketprice_block_update_time),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TextShimmer(
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.6f),
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RightSide(
|
||||
priceChangeType: PriceChangeType?,
|
||||
chartRawData: MarketChartRawData?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.padding(vertical = TangemTheme.dimens.spacing10),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (chartRawData != null && priceChangeType != null) {
|
||||
MarketChartMini(
|
||||
rawData = chartRawData,
|
||||
type = priceChangeType.toChartType(),
|
||||
modifier = Modifier
|
||||
.requiredSize(
|
||||
width = TangemTheme.dimens.size56,
|
||||
height = TangemTheme.dimens.size24,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.padding(vertical = TangemTheme.dimens.spacing2)
|
||||
.requiredSize(
|
||||
width = TangemTheme.dimens.size56,
|
||||
height = TangemTheme.dimens.size20,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (priceChangeType != null) {
|
||||
Icon(
|
||||
modifier = Modifier.requiredSize(TangemTheme.dimens.size20),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_chevron_right_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.requiredSize(
|
||||
width = TangemTheme.dimens.size20,
|
||||
height = TangemTheme.dimens.size20,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 360)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
val data = MarketChartRawData(
|
||||
x = List(20) { Random.nextFloat().toDouble() }.toImmutableList(),
|
||||
y = List(20) { Random.nextFloat().toDouble() }.toImmutableList(),
|
||||
)
|
||||
|
||||
val state = TokenMarketBlockUM(
|
||||
currencySymbol = "XRP",
|
||||
currentPrice = "0,5$",
|
||||
h24Percent = "0,5%",
|
||||
priceChangeType = PriceChangeType.UP,
|
||||
chartData = data,
|
||||
onClick = {},
|
||||
currentPriceValue = BigDecimal(1234),
|
||||
priceAnnotated = stringReference("0,5$"),
|
||||
)
|
||||
|
||||
TangemThemePreview {
|
||||
Column(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.tertiary),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
TokenMarketBlockLegacy(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state,
|
||||
)
|
||||
TokenMarketBlockLegacy(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.copy(
|
||||
currentPrice = "0,0000000000012356786789$",
|
||||
),
|
||||
)
|
||||
TokenMarketBlockLegacy(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.copy(
|
||||
currentPrice = null,
|
||||
chartData = null,
|
||||
),
|
||||
)
|
||||
TokenMarketBlockLegacy(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.copy(
|
||||
chartData = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,12 +20,10 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.lerp
|
||||
import com.tangem.core.ui.components.SpacerH8
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.components.pager.PagerIndicator
|
||||
import com.tangem.core.ui.ds.message.TangemMessage
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
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
|
||||
|
|
@ -67,41 +65,23 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, horizontalItemPadding
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun bannerContainerColor(placeholder: Placeholder): Color = if (LocalRedesignEnabled.current) {
|
||||
when (placeholder) {
|
||||
Placeholder.MAIN -> TangemTheme.colors2.surface.level1
|
||||
Placeholder.FEED -> TangemTheme.colors2.surface.level3
|
||||
Placeholder.PAYMENT_ACCOUNT_MAIN -> TangemTheme.colors3.bg.opaque.primary
|
||||
}
|
||||
} else {
|
||||
when (placeholder) {
|
||||
Placeholder.MAIN,
|
||||
Placeholder.PAYMENT_ACCOUNT_MAIN,
|
||||
-> TangemTheme.colors.background.primary
|
||||
Placeholder.FEED -> TangemTheme.colors.background.action
|
||||
}
|
||||
private fun bannerContainerColor(placeholder: Placeholder): Color = when (placeholder) {
|
||||
Placeholder.MAIN -> TangemTheme.colors2.surface.level1
|
||||
Placeholder.FEED -> TangemTheme.colors2.surface.level3
|
||||
Placeholder.PAYMENT_ACCOUNT_MAIN -> TangemTheme.colors3.bg.opaque.primary
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a banner either with the redesigned [TangemMessage] component or the legacy [Notification],
|
||||
* depending on [LocalRedesignEnabled]. Both accept the same [NotificationConfig], so the banner model
|
||||
* and converters stay untouched.
|
||||
* Renders a banner with the [TangemMessage] component. Uses the same [NotificationConfig] as the banner
|
||||
* model and converters, so they stay untouched.
|
||||
*/
|
||||
@Composable
|
||||
private fun BannerNotification(config: NotificationConfig, containerColor: Color, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TangemMessage(
|
||||
config = config,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
contentColor = containerColor,
|
||||
)
|
||||
} else {
|
||||
Notification(
|
||||
config = config,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
containerColor = containerColor,
|
||||
)
|
||||
}
|
||||
TangemMessage(
|
||||
config = config,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
contentColor = containerColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.common.ui.account.AccountIcon
|
||||
import com.tangem.core.res.getStringSafe
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconStart
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerW12
|
||||
|
|
@ -38,7 +37,6 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -56,7 +54,6 @@ internal fun ParticipateBottomBlock(
|
|||
code: String,
|
||||
shareLink: String,
|
||||
expectedAwards: ExpectedAwards?,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onAgreementClick: () -> Unit,
|
||||
onCopyClick: () -> Unit,
|
||||
onShareClick: (String) -> Unit,
|
||||
|
|
@ -75,7 +72,6 @@ internal fun ParticipateBottomBlock(
|
|||
AdditionalButtons(
|
||||
code = code,
|
||||
shareLink = shareLink,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onCopyClick = onCopyClick,
|
||||
onShareClick = onShareClick,
|
||||
)
|
||||
|
|
@ -350,7 +346,6 @@ private fun AwardAccount(accountAward: ReferralStateHolder.AccountAward) {
|
|||
private fun AdditionalButtons(
|
||||
code: String,
|
||||
shareLink: String,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onCopyClick: () -> Unit,
|
||||
onShareClick: (String) -> Unit,
|
||||
) {
|
||||
|
|
@ -358,8 +353,6 @@ private fun AdditionalButtons(
|
|||
val hapticFeedback = LocalHapticFeedback.current
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val resources = LocalContext.current.resources
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
||||
|
||||
Row(
|
||||
|
|
@ -375,19 +368,12 @@ private fun AdditionalButtons(
|
|||
clipboardManager.setText(AnnotatedString(code))
|
||||
|
||||
coroutineScope.launch {
|
||||
if (isRedesignEnabled) {
|
||||
tangemTopSnackbarHostState.showSnackbar(
|
||||
SnackbarMessage(
|
||||
startIconId = R.drawable.ic_check_24,
|
||||
message = resourceReference(R.string.referral_promo_code_copied),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = resources.getStringSafe(R.string.referral_promo_code_copied),
|
||||
duration = SnackbarDuration.Short,
|
||||
)
|
||||
}
|
||||
tangemTopSnackbarHostState.showSnackbar(
|
||||
SnackbarMessage(
|
||||
startIconId = R.drawable.ic_check_24,
|
||||
message = resourceReference(R.string.referral_promo_code_copied),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.weight(1f),
|
||||
|
|
@ -435,7 +421,6 @@ private fun ParticipateBottomBlockPreview(
|
|||
code = data.code,
|
||||
shareLink = data.shareLink,
|
||||
expectedAwards = data.expectedAwards,
|
||||
snackbarHostState = SnackbarHostState(),
|
||||
onAgreementClick = data.onAgreementClick,
|
||||
onCopyClick = data.onCopyClick,
|
||||
onShareClick = data.onShareClick,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -38,15 +37,12 @@ import com.tangem.core.ui.components.SpacerH24
|
|||
import com.tangem.core.ui.components.SpacerH32
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.snackbar.CopiedTextSnackbar
|
||||
import com.tangem.core.ui.components.snackbar.TangemSnackbar
|
||||
import com.tangem.core.ui.components.token.TokenItem
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -69,8 +65,6 @@ import java.util.UUID
|
|||
*/
|
||||
@Composable
|
||||
internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||
val snackbarHostState = remember(::SnackbarHostState)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
|
|
@ -79,61 +73,30 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
|||
onBackClick = stateHolder.headerState.onBackClicked,
|
||||
)
|
||||
},
|
||||
snackbarHost = {
|
||||
SnackbarHost(
|
||||
hostState = snackbarHostState,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.padding(bottom = TangemTheme.dimens.spacing108),
|
||||
) {
|
||||
// TODO: use StateEvent
|
||||
if (stateHolder.errorSnackbar != null) {
|
||||
TangemSnackbar(data = it, actionOnNewLine = true)
|
||||
} else {
|
||||
CopiedTextSnackbar(it)
|
||||
}
|
||||
}
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) {
|
||||
) { paddingValues ->
|
||||
ReferralContent(
|
||||
stateHolder = stateHolder,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onAgreementClick = stateHolder.analytics.onAgreementClicked,
|
||||
modifier = Modifier.padding(it),
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
)
|
||||
}
|
||||
|
||||
val errorSnackbar = stateHolder.errorSnackbar
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val resources = LocalContext.current.resources
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||
|
||||
SideEffect {
|
||||
if (errorSnackbar != null) {
|
||||
coroutineScope.launch {
|
||||
if (isRedesignEnabled) {
|
||||
topSnackbarHostState.showSnackbar(
|
||||
message = resources.getMessageForErrorSnackbar(errorSnackbar.throwable),
|
||||
actionLabel = resources.getStringSafe(R.string.warning_button_ok),
|
||||
duration = SnackbarMessage.Duration.Indefinite,
|
||||
)
|
||||
|
||||
errorSnackbar.onOkClicked()
|
||||
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = snackbarHostState.showSnackbar(
|
||||
topSnackbarHostState.showSnackbar(
|
||||
message = resources.getMessageForErrorSnackbar(errorSnackbar.throwable),
|
||||
actionLabel = resources.getStringSafe(R.string.warning_button_ok),
|
||||
duration = SnackbarDuration.Indefinite,
|
||||
duration = SnackbarMessage.Duration.Indefinite,
|
||||
)
|
||||
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
errorSnackbar.onOkClicked()
|
||||
}
|
||||
errorSnackbar.onOkClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +105,6 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
|||
@Composable
|
||||
private fun ReferralContent(
|
||||
stateHolder: ReferralStateHolder,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onAgreementClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -155,7 +117,6 @@ private fun ReferralContent(
|
|||
item {
|
||||
ReferralInfo(
|
||||
stateHolder = stateHolder,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onAgreementClick = onAgreementClick,
|
||||
)
|
||||
}
|
||||
|
|
@ -189,11 +150,7 @@ private fun Header() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ReferralInfo(
|
||||
stateHolder: ReferralStateHolder,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onAgreementClick: () -> Unit,
|
||||
) {
|
||||
private fun ReferralInfo(stateHolder: ReferralStateHolder, onAgreementClick: () -> Unit) {
|
||||
when (val state = stateHolder.referralInfoState) {
|
||||
is ReferralInfoState.ParticipantContent -> {
|
||||
Conditions(state = state)
|
||||
|
|
@ -203,7 +160,6 @@ private fun ReferralInfo(
|
|||
shareLink = state.shareLink,
|
||||
expectedAwards = state.expectedAwards,
|
||||
accountAward = state.accountAward,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onAgreementClick = onAgreementClick,
|
||||
onCopyClick = stateHolder.analytics.onCopyClicked,
|
||||
onShareClick = stateHolder.analytics.onShareClicked,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,10 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveModel
|
||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheet
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheetLegacy
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -45,21 +43,12 @@ internal class DefaultTokenReceiveComponent @AssistedInject constructor(
|
|||
override fun BottomSheet() {
|
||||
val content by contentStack.subscribeAsState()
|
||||
val currentRoute = content.active.configuration
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenReceiveContentSheet(
|
||||
route = currentRoute,
|
||||
onCloseClick = ::dismiss,
|
||||
onBackClick = ::onChildBack,
|
||||
contentStack = content,
|
||||
)
|
||||
} else {
|
||||
TokenReceiveContentSheetLegacy(
|
||||
route = currentRoute,
|
||||
onCloseClick = ::dismiss,
|
||||
onBackClick = ::onChildBack,
|
||||
contentStack = content,
|
||||
)
|
||||
}
|
||||
TokenReceiveContentSheet(
|
||||
route = currentRoute,
|
||||
onCloseClick = ::dismiss,
|
||||
onBackClick = ::onChildBack,
|
||||
contentStack = content,
|
||||
)
|
||||
}
|
||||
|
||||
override fun dismiss() = model.params.onDismiss()
|
||||
|
|
|
|||
|
|
@ -9,12 +9,10 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContent
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContentLegacy
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
internal class TokenReceiveAssetsComponent(
|
||||
|
|
@ -27,11 +25,7 @@ internal class TokenReceiveAssetsComponent(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenReceiveAssetsContent(assetsUM = state)
|
||||
} else {
|
||||
TokenReceiveAssetsContentLegacy(assetsUM = state)
|
||||
}
|
||||
TokenReceiveAssetsContent(assetsUM = state)
|
||||
}
|
||||
|
||||
internal interface TokenReceiveAssetsModelCallback {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
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.TokenReceiveType
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContent
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContentLegacy
|
||||
|
||||
internal class TokenReceiveQrCodeComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
|
|
@ -26,11 +24,7 @@ internal class TokenReceiveQrCodeComponent(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenReceiveQrCodeContent(qrCodeUM = state)
|
||||
} else {
|
||||
TokenReceiveQrCodeContentLegacy(qrCodeUM = state)
|
||||
}
|
||||
TokenReceiveQrCodeContent(qrCodeUM = state)
|
||||
}
|
||||
|
||||
internal interface TokenReceiveQrCodeModelCallback {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContent
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContentLegacy
|
||||
|
||||
internal class TokenReceiveWarningComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
|
|
@ -24,11 +22,7 @@ internal class TokenReceiveWarningComponent(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenReceiveWarningContent(warningUM = state)
|
||||
} else {
|
||||
TokenReceiveWarningContentLegacy(warningUM = state)
|
||||
}
|
||||
TokenReceiveWarningContent(warningUM = state)
|
||||
}
|
||||
|
||||
internal interface TokenReceiveWarningModelCallback {
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
package com.tangem.features.tokenreceive.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.snackbar.CopiedTextSnackbarHost
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
|
||||
@Deprecated(
|
||||
"Use TangemTopSnackbarHost instead. Will be removed with redesign",
|
||||
)
|
||||
@Composable
|
||||
internal fun ContainerWithSnackbarHost(snackbarHostState: SnackbarHostState, content: @Composable () -> Unit) {
|
||||
Box {
|
||||
content()
|
||||
|
||||
if (LocalRedesignEnabled.current.not()) {
|
||||
CopiedTextSnackbarHost(
|
||||
hostState = snackbarHostState,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 80.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,672 +0,0 @@
|
|||
package com.tangem.features.tokenreceive.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
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.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.util.fastFilter
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.res.getStringSafe
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionBaseButton
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonContent
|
||||
import com.tangem.core.ui.components.buttons.small.TangemIconButton
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.ui.state.ReceiveAssetsUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
internal fun TokenReceiveAssetsContentLegacy(assetsUM: ReceiveAssetsUM) {
|
||||
val snackbarHostState = remember(::SnackbarHostState)
|
||||
|
||||
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = TangemTheme.colors.background.tertiary)
|
||||
.padding(bottom = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AddressBlock(
|
||||
assetsUM = assetsUM,
|
||||
snackbarHostState = snackbarHostState,
|
||||
)
|
||||
|
||||
if (assetsUM.isEnsResultLoading) {
|
||||
SpacerH8()
|
||||
LoadingBlock(modifier = Modifier.padding(horizontal = 16.dp))
|
||||
}
|
||||
|
||||
SpacerH12()
|
||||
|
||||
Info(
|
||||
showMemoDisclaimer = assetsUM.showMemoDisclaimer,
|
||||
notificationConfigs = assetsUM.notificationConfigs,
|
||||
currencyIconState = assetsUM.currencyIconState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Info(
|
||||
currencyIconState: CurrencyIconState,
|
||||
notificationConfigs: ImmutableList<NotificationUM>,
|
||||
showMemoDisclaimer: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
if (showMemoDisclaimer) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 18.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.receive_bottom_sheet_no_memo_required_message),
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
|
||||
notificationConfigs.fastForEach { notificationConfig ->
|
||||
key(notificationConfig.hashCode()) {
|
||||
if (notificationConfig is NotificationUM.Warning.YieldSupplyIsActive) {
|
||||
YieldSupplyDepositedWarning(
|
||||
currencyIconState = currencyIconState,
|
||||
title = stringResourceSafe(
|
||||
R.string.yield_module_balance_info_sheet_title,
|
||||
notificationConfig.tokenName,
|
||||
),
|
||||
subtitle = stringResourceSafe(R.string.yield_module_balance_info_sheet_subtitle),
|
||||
)
|
||||
} else {
|
||||
Notification(config = notificationConfig.config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun YieldSupplyDepositedWarning(
|
||||
currencyIconState: CurrencyIconState,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier
|
||||
.defaultMinSize(minHeight = TangemTheme.dimens.size44)
|
||||
.fillMaxWidth(),
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
color = TangemTheme.colors.button.disabled,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(all = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(22.dp)
|
||||
.width(22.dp),
|
||||
contentAlignment = Alignment.TopStart,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.size(13.dp),
|
||||
state = currencyIconState,
|
||||
shouldDisplayNetwork = false,
|
||||
iconSize = 13.dp,
|
||||
)
|
||||
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.background.tertiary, RoundedCornerShape(15.dp))
|
||||
.padding(1.dp)
|
||||
.size(15.dp)
|
||||
.align(Alignment.BottomEnd),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.img_aave_22),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerW(width = TangemTheme.dimens.spacing8)
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = title,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.button,
|
||||
)
|
||||
|
||||
SpacerH(height = TangemTheme.dimens.spacing2)
|
||||
|
||||
Text(
|
||||
text = subtitle,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddressBlock(assetsUM: ReceiveAssetsUM, snackbarHostState: SnackbarHostState) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||
|
||||
assetsUM.addresses
|
||||
.fastFilter { it.type is ReceiveAddress.Type.Ens }
|
||||
.fastForEach { address ->
|
||||
key(address.value) {
|
||||
EnsItem(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
onCopyClick = {
|
||||
assetsUM.onCopyClick(address)
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
coroutineScope.launch {
|
||||
if (isRedesignEnabled) {
|
||||
topSnackbarHostState.showSnackbar(
|
||||
SnackbarMessage(
|
||||
startIconId = R.drawable.ic_check_24,
|
||||
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = resources.getStringSafe(
|
||||
R.string.wallet_notification_address_copied,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
address = address.value,
|
||||
)
|
||||
SpacerH8()
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryAddressesItems(
|
||||
addresses = assetsUM.addresses.fastFilter { it.type is ReceiveAddress.Type.Primary }.toImmutableList(),
|
||||
currencyIconState = assetsUM.currencyIconState,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onShareClick = { address ->
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
assetsUM.onShareClick(address)
|
||||
},
|
||||
onCopyClick = { address ->
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
coroutineScope.launch {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = resources.getStringSafe(
|
||||
R.string.wallet_notification_address_copied,
|
||||
),
|
||||
)
|
||||
}
|
||||
assetsUM.onCopyClick(address)
|
||||
},
|
||||
onOpenQrCodeClick = { address ->
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
assetsUM.onOpenQrCodeClick(address)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun PrimaryAddressesItems(
|
||||
addresses: ImmutableList<ReceiveAddress>,
|
||||
currencyIconState: CurrencyIconState,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onShareClick: (String) -> Unit,
|
||||
onCopyClick: (ReceiveAddress) -> Unit,
|
||||
onOpenQrCodeClick: (String) -> Unit,
|
||||
) {
|
||||
if (addresses.isEmpty()) return
|
||||
var selectedAddress by remember { mutableStateOf(addresses.first()) }
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = 0,
|
||||
initialPageOffsetFraction = 0f,
|
||||
pageCount = addresses::count,
|
||||
)
|
||||
LaunchedEffect(key1 = pagerState.currentPage) {
|
||||
selectedAddress = addresses[pagerState.currentPage]
|
||||
}
|
||||
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
pageSpacing = 16.dp,
|
||||
) {
|
||||
AddressItem(
|
||||
currencyIconState = currencyIconState,
|
||||
onOpenQrCodeClick = { onOpenQrCodeClick(selectedAddress.value) },
|
||||
onCopyClick = { onCopyClick(selectedAddress) },
|
||||
onShareClick = { onShareClick(selectedAddress.value) },
|
||||
primaryType = selectedAddress.type as ReceiveAddress.Type.Primary,
|
||||
address = selectedAddress.value,
|
||||
isDynamicAddress = selectedAddress.type is ReceiveAddress.Type.Primary.Dynamic,
|
||||
snackbarHostState = snackbarHostState,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(4.dp)
|
||||
|
||||
if (pagerState.pageCount > 1) {
|
||||
val indicatorState = rememberLazyListState()
|
||||
val selectedColor = TangemTheme.colors.icon.primary1
|
||||
val unselectedColor = TangemTheme.colors.icon.informative
|
||||
|
||||
LazyRow(
|
||||
modifier = Modifier.height(20.dp),
|
||||
state = indicatorState,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
repeat(pagerState.pageCount) { iteration ->
|
||||
item(key = iteration) {
|
||||
val color by animateColorAsState(
|
||||
targetValue = if (pagerState.currentPage == iteration) selectedColor else unselectedColor,
|
||||
label = "",
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp, vertical = 6.dp)
|
||||
.background(color = color, shape = CircleShape)
|
||||
.size(7.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun AddressItem(
|
||||
currencyIconState: CurrencyIconState,
|
||||
onOpenQrCodeClick: () -> Unit,
|
||||
onCopyClick: () -> Unit,
|
||||
onShareClick: () -> Unit,
|
||||
primaryType: ReceiveAddress.Type.Primary,
|
||||
address: String,
|
||||
isDynamicAddress: Boolean,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
||||
onClick = onOpenQrCodeClick,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 12.dp, vertical = 32.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
modifier = Modifier.size(56.dp),
|
||||
state = currencyIconState,
|
||||
shouldDisplayNetwork = true,
|
||||
iconSize = 56.dp,
|
||||
)
|
||||
|
||||
SpacerH(12.dp)
|
||||
|
||||
if (isDynamicAddress) {
|
||||
DynamicAddressBadge()
|
||||
SpacerH(8.dp)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = primaryType.displayName.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.heightIn(min = 40.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
text = address,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.body2,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
SpacerH8()
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.clickable(onClick = onOpenQrCodeClick)
|
||||
.padding(vertical = 6.dp, horizontal = 12.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(16.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_qrcode_new_24),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerW(4.dp)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.token_receive_show_qr_code_title),
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
||||
ButtonsBlock(
|
||||
snackbarHostState = snackbarHostState,
|
||||
onCopyClick = onCopyClick,
|
||||
onShareClick = onShareClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ButtonsBlock(snackbarHostState: SnackbarHostState, onCopyClick: () -> Unit, onShareClick: () -> Unit) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||
|
||||
Row(
|
||||
modifier = Modifier.width(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
ActionButtonWithResizableText(
|
||||
modifier = Modifier.weight(1f),
|
||||
config = ActionButtonConfig(
|
||||
text = TextReference.Res(id = R.string.common_copy),
|
||||
iconResId = R.drawable.ic_copy_new_24,
|
||||
onClick = {
|
||||
onCopyClick()
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
coroutineScope.launch {
|
||||
if (isRedesignEnabled) {
|
||||
topSnackbarHostState.showSnackbar(
|
||||
SnackbarMessage(
|
||||
startIconId = R.drawable.ic_check_24,
|
||||
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
ActionButtonWithResizableText(
|
||||
modifier = Modifier.weight(1f),
|
||||
config = ActionButtonConfig(
|
||||
text = TextReference.Res(id = R.string.common_share),
|
||||
iconResId = R.drawable.ic_share_24,
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
onShareClick()
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EnsItem(onCopyClick: () -> Unit, address: String, modifier: Modifier = Modifier) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 14.dp, horizontal = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.size(36.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_ens_36),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerW12()
|
||||
|
||||
EllipsisText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = address,
|
||||
ellipsis = TextEllipsis.Middle,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
)
|
||||
|
||||
TangemIconButton(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size28),
|
||||
iconRes = R.drawable.ic_share_24,
|
||||
innerPadding = 6.dp,
|
||||
onClick = onCopyClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadingBlock(modifier: Modifier = Modifier) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 64.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
color = TangemTheme.colors.icon.informative,
|
||||
modifier = Modifier.padding(TangemTheme.dimens.spacing8),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionButtonWithResizableText(config: ActionButtonConfig, modifier: Modifier = Modifier) {
|
||||
ActionBaseButton(
|
||||
config = config,
|
||||
shape = RoundedCornerShape(size = TangemTheme.dimens.radius24),
|
||||
content = { contentModifier ->
|
||||
ActionButtonContent(
|
||||
config = config,
|
||||
text = { color ->
|
||||
Text(
|
||||
text = config.text.resolveReference(),
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
minFontSize = 10.sp,
|
||||
maxFontSize = TangemTheme.typography.button.fontSize,
|
||||
),
|
||||
color = color,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.button,
|
||||
)
|
||||
},
|
||||
modifier = contentModifier.padding(horizontal = 16.dp),
|
||||
paddingBetweenIconAndText = 4.dp,
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DynamicAddressBadge(modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.text.accent.copy(alpha = 0.1f),
|
||||
shape = RoundedCornerShape(percent = 50),
|
||||
)
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
id = R.drawable.ic_dynamic_addresses_badge_16,
|
||||
),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.dynamic_addresses_receive_badge),
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_TokenReceiveAssetsContent(
|
||||
@PreviewParameter(TokenReceiveAssetsContentProvider::class) params: ReceiveAssetsUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenReceiveAssetsContentLegacy(assetsUM = params)
|
||||
}
|
||||
}
|
||||
|
||||
internal class TokenReceiveAssetsContentProvider : PreviewParameterProvider<ReceiveAssetsUM> {
|
||||
val address = ReceiveAddress(
|
||||
value = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||
type = ReceiveAddress.Type.Primary.Default(
|
||||
displayName = stringReference("Etherium address"),
|
||||
),
|
||||
)
|
||||
private val dynamicAddress = ReceiveAddress(
|
||||
value = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
||||
type = ReceiveAddress.Type.Primary.Dynamic(
|
||||
displayName = stringReference("Ethereum address"),
|
||||
),
|
||||
)
|
||||
private val tokenIconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = null,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
)
|
||||
private val config = ReceiveAssetsUM(
|
||||
notificationConfigs =
|
||||
persistentListOf(
|
||||
NotificationUM.Warning(
|
||||
title = stringReference("Send only XLM on the Ethereum network"),
|
||||
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
||||
),
|
||||
),
|
||||
addresses = persistentListOf(
|
||||
address,
|
||||
address,
|
||||
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
||||
),
|
||||
showMemoDisclaimer = false,
|
||||
onCopyClick = {},
|
||||
onOpenQrCodeClick = {},
|
||||
isEnsResultLoading = true,
|
||||
network = "USDT",
|
||||
currencyIconState = CurrencyIconState.Locked,
|
||||
onShareClick = {},
|
||||
)
|
||||
private val yieldSupplyIsActiveConfig = config.copy(
|
||||
notificationConfigs = persistentListOf(
|
||||
NotificationUM.Warning.YieldSupplyIsActive(tokenName = "USDT"),
|
||||
),
|
||||
isEnsResultLoading = false,
|
||||
currencyIconState = tokenIconState,
|
||||
)
|
||||
private val dynamicAddressConfig = config.copy(
|
||||
addresses = persistentListOf(
|
||||
dynamicAddress,
|
||||
address,
|
||||
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
||||
),
|
||||
isEnsResultLoading = false,
|
||||
notificationConfigs = persistentListOf(),
|
||||
currencyIconState = tokenIconState,
|
||||
)
|
||||
|
||||
override val values: Sequence<ReceiveAssetsUM>
|
||||
get() = sequenceOf(config, yieldSupplyIsActiveConfig, dynamicAddressConfig)
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
package com.tangem.features.tokenreceive.ui
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.tangem.core.ui.R
|
||||
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.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||
|
||||
@Composable
|
||||
internal fun TokenReceiveContentSheetLegacy(
|
||||
route: TokenReceiveRoutes,
|
||||
onCloseClick: () -> Unit,
|
||||
onBackClick: () -> Unit,
|
||||
contentStack: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||
) {
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onCloseClick,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onBack = onBackClick,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
title = {
|
||||
Title(
|
||||
route = route,
|
||||
onBackClick = onBackClick,
|
||||
onCloseClick = onCloseClick,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
TokenReceiveContent(
|
||||
stackState = contentStack,
|
||||
modifier = Modifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Title(route: TokenReceiveRoutes, onBackClick: () -> Unit, onCloseClick: () -> Unit) {
|
||||
when (route) {
|
||||
is TokenReceiveRoutes.QrCode -> {
|
||||
TangemModalBottomSheetTitle(
|
||||
startIconRes = R.drawable.ic_back_24,
|
||||
onStartClick = onBackClick,
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onCloseClick,
|
||||
)
|
||||
}
|
||||
TokenReceiveRoutes.ReceiveAssets -> {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = resourceReference(R.string.domain_receive_assets_navigation_title),
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onCloseClick,
|
||||
)
|
||||
}
|
||||
TokenReceiveRoutes.Warning -> {
|
||||
TangemModalBottomSheetTitle(
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onCloseClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenReceiveContent(
|
||||
stackState: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Children(
|
||||
stack = stackState,
|
||||
animation = stackAnimation(fade(animationSpec = tween(durationMillis = 100))),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.animateContentSize(),
|
||||
) {
|
||||
it.instance.Content(Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.tangem.features.tokenreceive.ui
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
||||
import com.tangem.features.tokenreceive.ui.state.ReceiveAssetsUM
|
||||
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class TokenReceiveAssetsContentProvider : PreviewParameterProvider<ReceiveAssetsUM> {
|
||||
val address = ReceiveAddress(
|
||||
value = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||
type = ReceiveAddress.Type.Primary.Default(
|
||||
displayName = stringReference("Ethereum address"),
|
||||
),
|
||||
)
|
||||
private val dynamicAddress = ReceiveAddress(
|
||||
value = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
||||
type = ReceiveAddress.Type.Primary.Dynamic(
|
||||
displayName = stringReference("Ethereum address"),
|
||||
),
|
||||
)
|
||||
private val tokenIconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = null,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
)
|
||||
private val config = ReceiveAssetsUM(
|
||||
notificationConfigs =
|
||||
persistentListOf(
|
||||
NotificationUM.Warning(
|
||||
title = stringReference("Send only XLM on the Ethereum network"),
|
||||
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
||||
),
|
||||
),
|
||||
addresses = persistentListOf(
|
||||
address,
|
||||
address,
|
||||
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
||||
),
|
||||
showMemoDisclaimer = false,
|
||||
onCopyClick = {},
|
||||
onOpenQrCodeClick = {},
|
||||
isEnsResultLoading = true,
|
||||
network = "USDT",
|
||||
currencyIconState = CurrencyIconState.Locked,
|
||||
onShareClick = {},
|
||||
)
|
||||
private val yieldSupplyIsActiveConfig = config.copy(
|
||||
notificationConfigs = persistentListOf(
|
||||
NotificationUM.Warning.YieldSupplyIsActive(tokenName = "USDT"),
|
||||
),
|
||||
isEnsResultLoading = false,
|
||||
currencyIconState = tokenIconState,
|
||||
)
|
||||
private val dynamicAddressConfig = config.copy(
|
||||
addresses = persistentListOf(
|
||||
dynamicAddress,
|
||||
address,
|
||||
address.copy(type = ReceiveAddress.Type.Ens, value = "papasha.eth"),
|
||||
),
|
||||
isEnsResultLoading = false,
|
||||
notificationConfigs = persistentListOf(),
|
||||
currencyIconState = tokenIconState,
|
||||
)
|
||||
|
||||
override val values: Sequence<ReceiveAssetsUM>
|
||||
get() = sequenceOf(config, yieldSupplyIsActiveConfig, dynamicAddressConfig)
|
||||
}
|
||||
|
||||
internal class TokenReceiveQrCodeContentPreviewProvider : PreviewParameterProvider<QrCodeUM> {
|
||||
private val config = QrCodeUM(
|
||||
network = "Ethereum",
|
||||
addressName = stringReference("Ethereum"),
|
||||
addressValue = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||
onCopyClick = {},
|
||||
onShareClick = {},
|
||||
)
|
||||
|
||||
override val values: Sequence<QrCodeUM>
|
||||
get() = sequenceOf(config)
|
||||
}
|
||||
|
||||
internal class TokenReceiveWarningContentProvider : PreviewParameterProvider<WarningUM> {
|
||||
val iconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = null,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
)
|
||||
|
||||
override val values: Sequence<WarningUM>
|
||||
get() = sequenceOf(
|
||||
WarningUM(
|
||||
iconState = iconState,
|
||||
onWarningAcknowledged = {},
|
||||
network = "Ethereum",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,231 +0,0 @@
|
|||
package com.tangem.features.tokenreceive.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.unit.dp
|
||||
import com.tangem.core.res.getStringSafe
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.LocalTopSnackbarHostState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenReceiveQrCodeBottomSheetTestTags
|
||||
import com.tangem.features.tokenreceive.impl.R
|
||||
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
internal fun TokenReceiveQrCodeContentLegacy(qrCodeUM: QrCodeUM) {
|
||||
val snackbarHostState = remember(::SnackbarHostState)
|
||||
val qrCodePainter = rememberQrPainter(content = qrCodeUM.addressValue)
|
||||
|
||||
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = TangemTheme.colors.background.tertiary)
|
||||
.padding(bottom = 16.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SpacerH8()
|
||||
|
||||
QrCodePage(
|
||||
addressFullName = qrCodeUM.addressName,
|
||||
addressValue = qrCodeUM.addressValue,
|
||||
network = qrCodeUM.network,
|
||||
qrCodePainter = qrCodePainter,
|
||||
)
|
||||
SpacerH24()
|
||||
|
||||
Buttons(
|
||||
onShareClick = { qrCodeUM.onShareClick(qrCodeUM.addressValue) },
|
||||
onCopyClick = qrCodeUM.onCopyClick,
|
||||
snackbarHostState = snackbarHostState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QrCodePage(addressFullName: TextReference, addressValue: String, network: String, qrCodePainter: Painter) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.size36),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(
|
||||
R.string.receive_bottom_sheet_warning_message_compact,
|
||||
addressFullName.resolveReference(),
|
||||
network,
|
||||
),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.h3,
|
||||
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.TITLE),
|
||||
)
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.border(
|
||||
width = 8.dp,
|
||||
color = TangemTheme.colors.icon.constant,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
)
|
||||
.padding(8.dp)
|
||||
.testTag(TokenReceiveQrCodeBottomSheetTestTags.QR_CODE),
|
||||
|
||||
) {
|
||||
Image(
|
||||
painter = qrCodePainter,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Fit,
|
||||
modifier = Modifier.sizeIn(minWidth = 148.dp),
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH24()
|
||||
}
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.wc_common_address),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
|
||||
SpacerH2()
|
||||
|
||||
Text(
|
||||
text = addressValue,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.ADDRESS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Buttons(
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onShareClick: () -> Unit,
|
||||
onCopyClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
SecondaryButtonIconStart(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResourceSafe(id = R.string.common_copy),
|
||||
iconResId = R.drawable.ic_copy_24,
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
onCopyClick()
|
||||
coroutineScope.launch {
|
||||
if (isRedesignEnabled) {
|
||||
tangemTopSnackbarHostState.showSnackbar(
|
||||
SnackbarMessage(
|
||||
startIconId = R.drawable.ic_check_24,
|
||||
message = resourceReference(R.string.wallet_notification_address_copied),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
SecondaryButtonIconStart(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResourceSafe(id = R.string.common_share),
|
||||
iconResId = R.drawable.ic_share_24,
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
onShareClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberQrPainter(content: String, size: Dp = 248.dp, padding: Dp = 0.dp): BitmapPainter {
|
||||
val density = LocalDensity.current
|
||||
return remember(content) {
|
||||
BitmapPainter(
|
||||
content.toQrCode(
|
||||
sizePx = with(density) { size.roundToPx() },
|
||||
paddingPx = with(density) { padding.roundToPx() },
|
||||
).asImageBitmap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_TokenReceiveQrCodeContent(
|
||||
@PreviewParameter(TokenReceiveQrCodeContentPreviewProvider::class) qrCodeUM: QrCodeUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenReceiveQrCodeContentLegacy(qrCodeUM = qrCodeUM)
|
||||
}
|
||||
}
|
||||
|
||||
internal class TokenReceiveQrCodeContentPreviewProvider : PreviewParameterProvider<QrCodeUM> {
|
||||
private val config = QrCodeUM(
|
||||
network = "Ethereum",
|
||||
addressName = stringReference("Etherium"),
|
||||
addressValue = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||
onCopyClick = {},
|
||||
onShareClick = {},
|
||||
)
|
||||
|
||||
override val values: Sequence<QrCodeUM>
|
||||
get() = sequenceOf(config)
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
package com.tangem.features.tokenreceive.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
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.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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 com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenReceiveWarningBottomSheetTestTags
|
||||
import com.tangem.features.tokenreceive.impl.R
|
||||
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
||||
|
||||
@Composable
|
||||
internal fun TokenReceiveWarningContentLegacy(warningUM: WarningUM) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = TangemTheme.colors.background.tertiary)
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
bottom = 16.dp,
|
||||
)
|
||||
.testTag(TokenReceiveWarningBottomSheetTestTags.BOTTOM_SHEET),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.size(size = 64.dp),
|
||||
state = warningUM.iconState,
|
||||
shouldDisplayNetwork = true,
|
||||
iconSize = 56.dp,
|
||||
)
|
||||
|
||||
SpacerH24()
|
||||
|
||||
WarningBlock(networkName = warningUM.network)
|
||||
|
||||
SpacerH12()
|
||||
|
||||
Text(
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_description),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
|
||||
SpacerH(48.dp)
|
||||
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.common_got_it),
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
warningUM.onWarningAcknowledged()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WarningBlock(networkName: String, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_title),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
SpacerH(6.dp)
|
||||
|
||||
Text(
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResourceSafe(R.string.domain_receive_assets_onboarding_network_name, networkName),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_TokenReceiveWarningContent(
|
||||
@PreviewParameter(TokenReceiveWarningContentProvider::class) warningUM: WarningUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenReceiveWarningContentLegacy(warningUM = warningUM)
|
||||
}
|
||||
}
|
||||
|
||||
internal class TokenReceiveWarningContentProvider : PreviewParameterProvider<WarningUM> {
|
||||
val iconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = null,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
)
|
||||
|
||||
override val values: Sequence<WarningUM>
|
||||
get() = sequenceOf(
|
||||
WarningUM(
|
||||
iconState = iconState,
|
||||
onWarningAcknowledged = {},
|
||||
network = "Etherium",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -15,13 +15,11 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.route.TokenDetailsBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreenLegacy
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.ChooseAddressBottomSheetComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
||||
|
|
@ -154,31 +152,18 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
val txHistoryDetails by txHistoryDetailsSlot.subscribeAsState()
|
||||
NavigationBar3ButtonsScrim()
|
||||
|
||||
if (LocalRedesignEnabled.current) {
|
||||
val tokenDetailsUM by model.redesignUiState.collectAsStateWithLifecycle()
|
||||
val tokenDetailsUM by model.redesignUiState.collectAsStateWithLifecycle()
|
||||
|
||||
TokenDetailsScreen(
|
||||
tokenDetailsUM = tokenDetailsUM,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
expressTransactionsComponent = expressTransactionsComponent,
|
||||
ratingComponent = ratingSlotState.child?.instance,
|
||||
marketingBannerComponent = marketingBannerComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
TokenDetailsScreenLegacy(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
expressTransactionsComponent = expressTransactionsComponent,
|
||||
ratingComponent = ratingSlotState.child?.instance,
|
||||
marketingBannerComponent = marketingBannerComponent,
|
||||
)
|
||||
}
|
||||
TokenDetailsScreen(
|
||||
tokenDetailsUM = tokenDetailsUM,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
expressTransactionsComponent = expressTransactionsComponent,
|
||||
ratingComponent = ratingSlotState.child?.instance,
|
||||
marketingBannerComponent = marketingBannerComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
txHistoryDetails.child?.instance?.BottomSheet()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -184,7 +183,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||
private val walletIconUMConverter: WalletIconUMConverter,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val redesignStateController: TokenDetailsStateController,
|
||||
private val swapFeedbackUseCase: SwapFeedbackUseCase,
|
||||
private val quickTopUpBlockFactory: QuickTopUpBlockFactory,
|
||||
|
|
@ -346,10 +344,8 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
uiState.value = stateFactory.getStateWithUpdatedHidden(
|
||||
isBalanceHidden = settings.isBalanceHidden,
|
||||
)
|
||||
if (designFeatureToggles.isRedesignEnabled) {
|
||||
redesignStateController.update { state ->
|
||||
state.copy(isBalanceHidden = settings.isBalanceHidden)
|
||||
}
|
||||
redesignStateController.update { state ->
|
||||
state.copy(isBalanceHidden = settings.isBalanceHidden)
|
||||
}
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
|
|
@ -366,38 +362,36 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
latestTokenActions = state.states
|
||||
sendButtonsEvents(state.states)
|
||||
uiState.value = stateFactory.getManageButtonsState(actions = state.states)
|
||||
if (designFeatureToggles.isRedesignEnabled) {
|
||||
val networkSource = currencyStatus.value.sources.networkSource
|
||||
redesignStateController.update(
|
||||
UpdateActionButtonsTransformer(
|
||||
actions = state.states,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateAddFundsTransformer(
|
||||
actions = state.states,
|
||||
networkSource = networkSource,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
onActionDispatched = bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateTransferTransformer(
|
||||
actions = state.states,
|
||||
networkSource = networkSource,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
analyticsEventHandler = analyticsEventsHandler,
|
||||
onActionDispatched = bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateZeroBalanceActionsTransformer(
|
||||
actions = state.states,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
}
|
||||
val networkSource = currencyStatus.value.sources.networkSource
|
||||
redesignStateController.update(
|
||||
UpdateActionButtonsTransformer(
|
||||
actions = state.states,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateAddFundsTransformer(
|
||||
actions = state.states,
|
||||
networkSource = networkSource,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
onActionDispatched = bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateTransferTransformer(
|
||||
actions = state.states,
|
||||
networkSource = networkSource,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
analyticsEventHandler = analyticsEventsHandler,
|
||||
onActionDispatched = bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateZeroBalanceActionsTransformer(
|
||||
actions = state.states,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
|
|
@ -1502,7 +1496,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun initRedesign() {
|
||||
if (!designFeatureToggles.isRedesignEnabled) return
|
||||
initRedesignState()
|
||||
observeRedesignBalance()
|
||||
updateRedesignTopBarMenu()
|
||||
|
|
|
|||
|
|
@ -1,261 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.*
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
|
||||
import com.tangem.features.rating.RatingComponent
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemeRedesign
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlockLegacy
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsTopAppBar
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenInfoBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlockLegacy
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.marketing.api.MarketingBannerComponent
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import com.tangem.features.txhistory.entity.TxHistoryItemsUM
|
||||
import com.tangem.features.txhistory.entity.TxHistoryUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
// TODO: Split to blocks [REDACTED_JIRA]
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod", "LongParameterList")
|
||||
@Composable
|
||||
internal fun TokenDetailsScreenLegacy(
|
||||
state: TokenDetailsState,
|
||||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
txHistoryComponent: TxHistoryComponent,
|
||||
yieldSupplyComponent: YieldSupplyComponent,
|
||||
expressTransactionsComponent: ExpressTransactionsComponent,
|
||||
ratingComponent: RatingComponent?,
|
||||
marketingBannerComponent: MarketingBannerComponent,
|
||||
) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
Scaffold(
|
||||
topBar = { TokenDetailsTopAppBar(config = state.topAppBarConfig) },
|
||||
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(WindowInsets.navigationBars),
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) { scaffoldPaddings ->
|
||||
val listState = rememberLazyListState()
|
||||
val txHistoryComponentState by txHistoryComponent.legacyTxHistoryState.collectAsStateWithLifecycle()
|
||||
val expressState by expressTransactionsComponent.state.collectAsStateWithLifecycle()
|
||||
val betweenItemsPadding = TangemTheme.dimens.spacing12
|
||||
val horizontalPadding = TangemTheme.dimens.spacing16
|
||||
val itemModifier = Modifier
|
||||
.padding(top = betweenItemsPadding)
|
||||
.padding(horizontal = horizontalPadding)
|
||||
|
||||
TangemPullToRefreshContainer(
|
||||
config = state.pullToRefreshConfig,
|
||||
modifier = Modifier.padding(scaffoldPaddings),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TokenDetailsScreenTestTags.SCREEN_CONTAINER),
|
||||
state = listState,
|
||||
contentPadding = PaddingValues(
|
||||
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
|
||||
),
|
||||
) {
|
||||
item {
|
||||
TokenInfoBlock(
|
||||
modifier = Modifier.padding(horizontal = horizontalPadding),
|
||||
state = state.tokenInfoBlockState,
|
||||
)
|
||||
}
|
||||
item {
|
||||
TokenDetailsBalanceBlockLegacy(
|
||||
modifier = itemModifier,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
state = state.tokenBalanceBlockState,
|
||||
)
|
||||
}
|
||||
items(
|
||||
items = state.notifications,
|
||||
key = { it::class.java },
|
||||
contentType = { it.config::class.java },
|
||||
itemContent = { notification ->
|
||||
Notification(
|
||||
modifier = itemModifier.animateItem(),
|
||||
config = notification.config,
|
||||
iconTint = when (notification) {
|
||||
is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is TokenDetailsNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
when {
|
||||
tokenMarketBlockComponent != null -> {
|
||||
item(
|
||||
key = TokenMarketBlockComponent::class.java,
|
||||
contentType = TokenMarketBlockComponent::class.java,
|
||||
content = { tokenMarketBlockComponent.Content(modifier = itemModifier) },
|
||||
)
|
||||
}
|
||||
state.isMarketPriceAvailable -> {
|
||||
item(
|
||||
key = MarketPriceBlockState::class.java,
|
||||
contentType = MarketPriceBlockState::class.java,
|
||||
content = {
|
||||
MarketPriceBlock(
|
||||
modifier = itemModifier,
|
||||
state = state.marketPriceBlockState,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.stakingBlocksState != null) {
|
||||
item(
|
||||
key = StakingBlockUM::class.java,
|
||||
contentType = StakingBlockUM::class.java,
|
||||
content = {
|
||||
TokenStakingBlockLegacy(
|
||||
state = state.stakingBlocksState,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
yieldSupplyComponent.Content(modifier = itemModifier)
|
||||
}
|
||||
|
||||
item(key = "marketing_banner_block") {
|
||||
TangemThemeRedesign {
|
||||
marketingBannerComponent.Content(modifier = itemModifier)
|
||||
}
|
||||
}
|
||||
|
||||
with(expressTransactionsComponent) {
|
||||
expressTransactionsContentLegacy(
|
||||
state = expressState.transactionsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
}
|
||||
|
||||
state.quickTopUpBlock?.let { quickTopUpBlock ->
|
||||
item(key = "quick_top_up_block") {
|
||||
TangemThemeRedesign {
|
||||
QuickTopUpBlock(
|
||||
state = quickTopUpBlock,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with(txHistoryComponent) {
|
||||
txHistoryContentLegacy(listState = listState, state = txHistoryComponentState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expressState.bottomSheetSlot?.content(
|
||||
ratingComponent?.let { comp -> { comp.Content(modifier = Modifier.fillMaxWidth()) } },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TokenDetailsScreenPreview(
|
||||
@PreviewParameter(TokenDetailsScreenParameterProvider::class) state: TokenDetailsState,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenDetailsScreenLegacy(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = null,
|
||||
txHistoryComponent = object : TxHistoryComponent {
|
||||
override val legacyTxHistoryState: StateFlow<TxHistoryUM> = MutableStateFlow(
|
||||
value = TxHistoryUM.Empty(isBalanceHidden = false, onExploreClick = {}),
|
||||
)
|
||||
|
||||
override val txHistoryState: StateFlow<TxHistoryItemsUM> = MutableStateFlow(
|
||||
value = TxHistoryItemsUM.Empty(isBalanceHidden = false, onExploreClick = {}),
|
||||
)
|
||||
|
||||
override fun LazyListScope.txHistoryContentLegacy(listState: LazyListState, state: TxHistoryUM) = Unit
|
||||
|
||||
override fun LazyListScope.txHistoryContent(listState: LazyListState, state: TxHistoryItemsUM) = Unit
|
||||
},
|
||||
yieldSupplyComponent = object : YieldSupplyComponent {
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
}
|
||||
},
|
||||
expressTransactionsComponent = PreviewExpressTransactionsComponent,
|
||||
ratingComponent = null,
|
||||
marketingBannerComponent = object : MarketingBannerComponent {
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) = Unit
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val PreviewExpressTransactionsComponent = object : ExpressTransactionsComponent {
|
||||
override val state: StateFlow<ExpressTransactionsBlockState> = MutableStateFlow(
|
||||
ExpressTransactionsBlockState(
|
||||
transactions = persistentListOf(),
|
||||
transactionsToDisplay = persistentListOf(),
|
||||
bottomSheetSlot = null,
|
||||
),
|
||||
)
|
||||
|
||||
override fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) = Unit
|
||||
|
||||
override fun LazyListScope.expressTransactionsContent(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) = Unit
|
||||
}
|
||||
|
||||
private class TokenDetailsScreenParameterProvider : CollectionPreviewParameterProvider<TokenDetailsState>(
|
||||
collection = listOf(
|
||||
TokenDetailsPreviewData.tokenDetailsState_1,
|
||||
TokenDetailsPreviewData.tokenDetailsState_2,
|
||||
TokenDetailsPreviewData.tokenDetailsState_3,
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -1,281 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
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.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.buttons.HorizontalActionChips
|
||||
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
|
||||
import com.tangem.core.ui.components.text.TextAnimatedCounter
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsYieldSupplyState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Suppress("DestructuringDeclarationWithTooManyEntries")
|
||||
@Composable
|
||||
internal fun TokenDetailsBalanceBlockLegacy(
|
||||
state: TokenDetailsBalanceBlockState,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
color = TangemTheme.colors.background.primary,
|
||||
) {
|
||||
val spacing4 = TangemTheme.dimens.spacing4
|
||||
val spacing10 = TangemTheme.dimens.spacing10
|
||||
val spacing12 = TangemTheme.dimens.spacing12
|
||||
|
||||
ConstraintLayout(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
val (balanceTitle, toggleButtons, fiatBalance, cryptoBalance, actionChips) = createRefs()
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.common_balance_title),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
modifier = Modifier.constrainAs(balanceTitle) {
|
||||
top.linkTo(anchor = parent.top, margin = spacing12)
|
||||
start.linkTo(anchor = parent.start, margin = spacing12)
|
||||
},
|
||||
)
|
||||
|
||||
BalanceButtons(
|
||||
state = state,
|
||||
modifier = Modifier.constrainAs(toggleButtons) {
|
||||
top.linkTo(anchor = parent.top)
|
||||
end.linkTo(anchor = parent.end, margin = spacing10)
|
||||
},
|
||||
)
|
||||
|
||||
FiatBalance(
|
||||
state = state,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = Modifier.constrainAs(fiatBalance) {
|
||||
top.linkTo(anchor = balanceTitle.bottom, margin = spacing4)
|
||||
start.linkTo(anchor = parent.start, margin = spacing12)
|
||||
},
|
||||
)
|
||||
|
||||
CryptoBalance(
|
||||
state = state,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = Modifier.constrainAs(cryptoBalance) {
|
||||
top.linkTo(anchor = fiatBalance.bottom, margin = spacing4)
|
||||
start.linkTo(anchor = parent.start, margin = spacing12)
|
||||
},
|
||||
)
|
||||
|
||||
HorizontalActionChips(
|
||||
buttons = state.actionButtons.map(TokenDetailsActionButton::config).toImmutableList(),
|
||||
modifier = Modifier.constrainAs(actionChips) {
|
||||
top.linkTo(anchor = cryptoBalance.bottom, margin = spacing12)
|
||||
start.linkTo(anchor = parent.start)
|
||||
end.linkTo(anchor = parent.end)
|
||||
bottom.linkTo(anchor = parent.bottom, margin = spacing12)
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.primary,
|
||||
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FiatBalance(
|
||||
state: TokenDetailsBalanceBlockState,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when (state) {
|
||||
is TokenDetailsBalanceBlockState.Loading -> RectangleShimmer(
|
||||
modifier = modifier.size(
|
||||
width = TangemTheme.dimens.size102,
|
||||
height = TangemTheme.dimens.size32,
|
||||
),
|
||||
)
|
||||
is TokenDetailsBalanceBlockState.Content -> if (state.displayYieldSupplyFiatBalance != null &&
|
||||
!isBalanceHidden
|
||||
) {
|
||||
TextAnimatedCounter(
|
||||
modifier = modifier,
|
||||
text = state.displayYieldSupplyFiatBalance,
|
||||
style = TangemTheme.typography.h2.applyBladeBrush(
|
||||
isEnabled = state.isBalanceFlickering,
|
||||
textColor = TangemTheme.colors.text.primary1,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = (state.displayYieldSupplyFiatBalance ?: state.displayFiatBalance).orMaskWithStars(
|
||||
isBalanceHidden,
|
||||
),
|
||||
style = TangemTheme.typography.h2.applyBladeBrush(
|
||||
isEnabled = state.isBalanceFlickering,
|
||||
textColor = TangemTheme.colors.text.primary1,
|
||||
),
|
||||
)
|
||||
}
|
||||
is TokenDetailsBalanceBlockState.Error -> Text(
|
||||
modifier = modifier,
|
||||
text = DASH_SIGN.orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CryptoBalance(
|
||||
state: TokenDetailsBalanceBlockState,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when (state) {
|
||||
is TokenDetailsBalanceBlockState.Loading -> RectangleShimmer(
|
||||
modifier = modifier.size(
|
||||
width = TangemTheme.dimens.size70,
|
||||
height = TangemTheme.dimens.size16,
|
||||
),
|
||||
)
|
||||
is TokenDetailsBalanceBlockState.Content -> {
|
||||
Crossfade(
|
||||
modifier = modifier,
|
||||
targetState = state.yieldSupplyState,
|
||||
) { yieldSupplyState ->
|
||||
when (yieldSupplyState) {
|
||||
is TokenDetailsYieldSupplyState.Active -> {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size16),
|
||||
painter = painterResource(id = R.drawable.ic_exchange_horizontal_24),
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
contentDescription = null,
|
||||
)
|
||||
TextAnimatedCounter(
|
||||
text = (state.displayYieldSupplyCryptoBalance ?: state.displayCryptoBalance)
|
||||
.orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography.caption2.applyBladeBrush(
|
||||
isEnabled = state.isBalanceFlickering,
|
||||
textColor = TangemTheme.colors.text.tertiary,
|
||||
),
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size16)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(bounded = false),
|
||||
onClick = { yieldSupplyState.yieldInfoClick() },
|
||||
),
|
||||
painter = painterResource(id = R.drawable.ic_information_24),
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
is TokenDetailsYieldSupplyState.Empty -> Text(
|
||||
text = state.displayCryptoBalance.orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography.caption2.applyBladeBrush(
|
||||
isEnabled = state.isBalanceFlickering,
|
||||
textColor = TangemTheme.colors.text.tertiary,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is TokenDetailsBalanceBlockState.Error -> Text(
|
||||
modifier = modifier,
|
||||
text = DASH_SIGN.orMaskWithStars(isBalanceHidden),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BalanceButtons(state: TokenDetailsBalanceBlockState, modifier: Modifier = Modifier) {
|
||||
if (state !is TokenDetailsBalanceBlockState.Content || !state.isBalanceSelectorEnabled) return
|
||||
|
||||
SegmentedButtons(
|
||||
config = state.balanceSegmentedButtonConfig,
|
||||
onClick = state.onBalanceSelect,
|
||||
showIndication = false,
|
||||
modifier = modifier
|
||||
.padding(top = TangemTheme.dimens.spacing11)
|
||||
.width(IntrinsicSize.Min),
|
||||
) { config ->
|
||||
val style = if (state.selectedBalanceType == config.type) {
|
||||
TangemTheme.typography.caption1
|
||||
} else {
|
||||
TangemTheme.typography.caption2
|
||||
}
|
||||
Text(
|
||||
text = config.title.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = style,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing6,
|
||||
vertical = TangemTheme.dimens.spacing4,
|
||||
)
|
||||
.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 328, heightDp = 152)
|
||||
@Preview(widthDp = 328, heightDp = 152, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TokenDetailsBalanceBlock(
|
||||
@PreviewParameter(TokenDetailsBalanceBlockStateProvider::class) state: TokenDetailsBalanceBlockState,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenDetailsBalanceBlockLegacy(state = state, isBalanceHidden = false)
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenDetailsBalanceBlockStateProvider : CollectionPreviewParameterProvider<TokenDetailsBalanceBlockState>(
|
||||
collection = listOf(
|
||||
TokenDetailsPreviewData.balanceLoading,
|
||||
TokenDetailsPreviewData.balanceContent,
|
||||
TokenDetailsPreviewData.balanceContent.copy(isBalanceFlickering = true),
|
||||
TokenDetailsPreviewData.balanceContent.copy(
|
||||
yieldSupplyState = TokenDetailsYieldSupplyState.Active({}),
|
||||
),
|
||||
TokenDetailsPreviewData.balanceError,
|
||||
),
|
||||
)
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.SpacerW8
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||
import com.tangem.core.ui.utils.getGreyScaleColorFilter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingAvailableBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingBalanceBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingLoadingBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData.stakingTemporaryUnavailableBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.CurrencyIcon
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.StringsSigns
|
||||
|
||||
/**
|
||||
* Token staking block
|
||||
*
|
||||
* @param state component state
|
||||
* @param isBalanceHidden whether to hide balance
|
||||
* @param modifier modifier
|
||||
*/
|
||||
@Composable
|
||||
internal fun TokenStakingBlockLegacy(state: StakingBlockUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.clickable(
|
||||
enabled = state is StakingBlockUM.Staked,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(),
|
||||
onClick = { (state as? StakingBlockUM.Staked)?.onStakeClicked?.invoke() },
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.padding(all = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = state,
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
label = "Staking block animation",
|
||||
) { stakingBlock ->
|
||||
when (stakingBlock) {
|
||||
is StakingBlockUM.TemporaryUnavailable -> StakingTemporaryUnavailableBlock()
|
||||
is StakingBlockUM.Loading -> StakingLoading()
|
||||
is StakingBlockUM.Staked -> StakingBalanceBlock(
|
||||
state = stakingBlock,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
is StakingBlockUM.StakeAvailable -> StakingAvailableContent(
|
||||
state = stakingBlock,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StakingAvailableContent(state: StakingBlockUM.StakeAvailable, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TokenDetailsScreenTestTags.STAKING_AVAILABLE_BLOCK),
|
||||
) {
|
||||
Row {
|
||||
val (alpha, colorFilter) = remember(state.iconState.isGrayscale) {
|
||||
getGreyScaleColorFilter(state.iconState.isGrayscale)
|
||||
}
|
||||
CurrencyIcon(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.clip(TangemTheme.shapes.roundedCorners8)
|
||||
.align(Alignment.CenterVertically)
|
||||
.testTag(TokenDetailsScreenTestTags.STAKING_CURRENCY_ICON),
|
||||
icon = state.iconState,
|
||||
alpha = alpha,
|
||||
colorFilter = colorFilter,
|
||||
)
|
||||
SpacerW8()
|
||||
Column {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4)) {
|
||||
Text(
|
||||
text = state.titleText.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
modifier = Modifier.testTag(TokenDetailsScreenTestTags.STAKING_SERVICE_TITLE),
|
||||
)
|
||||
if (state.isBetaMode) {
|
||||
Text(
|
||||
text = StringsSigns.DOT,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.beta_mode_warning_title),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size4))
|
||||
|
||||
Text(
|
||||
text = state.subtitleText.resolveReference(),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.body2,
|
||||
modifier = Modifier.testTag(TokenDetailsScreenTestTags.STAKING_SERVICE_TEXT),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size8))
|
||||
}
|
||||
}
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(id = R.string.common_stake),
|
||||
enabled = state.isEnabled,
|
||||
onClick = state.onStakeClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StakingLoading(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
Row {
|
||||
Column {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size20),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size8))
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size36),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.size8))
|
||||
}
|
||||
}
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size48),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TokenStakingBlock(
|
||||
@PreviewParameter(StakingBlockStateProvider::class)
|
||||
state: StakingBlockUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenStakingBlockLegacy(
|
||||
state = state,
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class StakingBlockStateProvider : CollectionPreviewParameterProvider<StakingBlockUM>(
|
||||
collection = listOf(
|
||||
stakingLoadingBlock,
|
||||
stakingAvailableBlock,
|
||||
stakingTemporaryUnavailableBlock,
|
||||
stakingBalanceBlock,
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -9,11 +9,9 @@ import com.tangem.common.ui.earn.EarnBlock
|
|||
import com.tangem.common.ui.earn.EarnBlockUM
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import com.tangem.features.yield.supply.impl.main.model.YieldSupplyModel
|
||||
import com.tangem.features.yield.supply.impl.main.ui.YieldSupplyBlockContentLegacy
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -27,21 +25,16 @@ internal class DefaultYieldSupplyComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
val earnBlockUM by model.uiState.collectAsStateWithLifecycle()
|
||||
earnBlockUM?.let { blockUM ->
|
||||
val tag = if (blockUM is EarnBlockUM.Content &&
|
||||
blockUM.backgroundUM is EarnBlockUM.BackgroundUM.AccentSoft
|
||||
) {
|
||||
TokenDetailsScreenTestTags.YIELD_SUPPLY_AVAILABLE_BLOCK
|
||||
} else {
|
||||
TokenDetailsScreenTestTags.YIELD_SUPPLY_BLOCK
|
||||
}
|
||||
EarnBlock(state = blockUM, modifier = modifier.testTag(tag))
|
||||
val earnBlockUM by model.uiState.collectAsStateWithLifecycle()
|
||||
earnBlockUM?.let { blockUM ->
|
||||
val tag = if (blockUM is EarnBlockUM.Content &&
|
||||
blockUM.backgroundUM is EarnBlockUM.BackgroundUM.AccentSoft
|
||||
) {
|
||||
TokenDetailsScreenTestTags.YIELD_SUPPLY_AVAILABLE_BLOCK
|
||||
} else {
|
||||
TokenDetailsScreenTestTags.YIELD_SUPPLY_BLOCK
|
||||
}
|
||||
} else {
|
||||
val yieldSupplyUM by model.uiStateLegacy.collectAsStateWithLifecycle()
|
||||
YieldSupplyBlockContentLegacy(yieldSupplyUM = yieldSupplyUM, modifier = modifier)
|
||||
EarnBlock(state = blockUM, modifier = modifier.testTag(tag))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,453 +0,0 @@
|
|||
package com.tangem.features.yield.supply.impl.main.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
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.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
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.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.SpacerW12
|
||||
import com.tangem.core.ui.components.SpacerW8
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
|
||||
@Composable
|
||||
internal fun YieldSupplyBlockContentLegacy(yieldSupplyUM: YieldSupplyUM, modifier: Modifier = Modifier) {
|
||||
AnimatedContent(
|
||||
targetState = yieldSupplyUM,
|
||||
contentKey = { it::class },
|
||||
) { supplyUM ->
|
||||
when (supplyUM) {
|
||||
is YieldSupplyUM.Available -> SupplyAvailable(supplyUM, modifier)
|
||||
YieldSupplyUM.Loading -> SupplyLoading(modifier)
|
||||
is YieldSupplyUM.Content -> SupplyContent(supplyUM, modifier)
|
||||
YieldSupplyUM.Processing.Enter -> SupplyProcessing(
|
||||
resourceReference(R.string.yield_module_token_details_earn_notification_processing),
|
||||
modifier,
|
||||
)
|
||||
YieldSupplyUM.Processing.Exit -> SupplyProcessing(
|
||||
resourceReference(R.string.yield_module_stop_earning),
|
||||
modifier,
|
||||
)
|
||||
YieldSupplyUM.Unavailable,
|
||||
YieldSupplyUM.Initial,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SupplyAvailable(supplyUM: YieldSupplyUM.Available, modifier: Modifier = Modifier) {
|
||||
if (supplyUM.isBoostAvailable) {
|
||||
SupplyAvailableBoosted(supplyUM = supplyUM, modifier = modifier)
|
||||
} else {
|
||||
SupplyInfo(
|
||||
title = resourceReference(
|
||||
R.string.yield_module_token_details_earn_notification_earning_on_your_balance_title,
|
||||
),
|
||||
subtitle = resourceReference(R.string.yield_module_token_details_earn_notification_description),
|
||||
rewardsApy = supplyUM.apyText,
|
||||
iconTint = TangemTheme.colors.icon.accent,
|
||||
modifier = modifier,
|
||||
button = {
|
||||
SecondaryButton(
|
||||
text = stringResourceSafe(R.string.common_learn_more),
|
||||
onClick = supplyUM.onClick,
|
||||
size = TangemButtonSize.WideAction,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SupplyAvailableBoosted(supplyUM: YieldSupplyUM.Available, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_analytics_up_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.icon.accent.copy(alpha = 0.1f), CircleShape)
|
||||
.padding(6.dp)
|
||||
.size(24.dp),
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Text(
|
||||
text = supplyUM.title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = supplyUM.apyText.resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.yield_apy_boost_banner_subtitle),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
SecondaryButton(
|
||||
text = stringResourceSafe(R.string.common_learn_more),
|
||||
onClick = supplyUM.onLearnMoreClick,
|
||||
size = TangemButtonSize.WideAction,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
PrimaryButton(
|
||||
text = stringResourceSafe(R.string.common_activate),
|
||||
onClick = supplyUM.onClick,
|
||||
size = TangemButtonSize.WideAction,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SupplyContent(supplyUM: YieldSupplyUM.Content, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.clickable(onClick = supplyUM.onClick)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.img_aave_22),
|
||||
modifier = Modifier.size(36.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
SpacerW12()
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1.0f, fill = false),
|
||||
text = supplyUM.title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
AnimatedVisibility(supplyUM.rewardsApy != TextReference.EMPTY) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = StringsSigns.DOT,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
Text(
|
||||
text = supplyUM.rewardsApy.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = supplyUM.subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
SpacerW8()
|
||||
AnimatedContent(
|
||||
targetState = supplyUM,
|
||||
) { currentState ->
|
||||
when {
|
||||
currentState.shouldShowWarningIcon -> Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_alert_triangle_20),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.attention,
|
||||
)
|
||||
currentState.shouldShowInfoIcon -> Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_alert_circle_red_20),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
)
|
||||
}
|
||||
}
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_right_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SupplyProcessing(text: TextReference, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.img_aave_22),
|
||||
modifier = Modifier.size(36.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
SpacerW12()
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(
|
||||
R.string.yield_module_token_details_earn_notification_earning_on_your_balance_title,
|
||||
),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
Text(
|
||||
text = text.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
SpacerW8()
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(20.dp),
|
||||
color = TangemTheme.colors.icon.accent,
|
||||
strokeWidth = 2.dp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SupplyLoading(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_analytics_up_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.icon.inactive.copy(alpha = 0.1f), CircleShape)
|
||||
.padding(6.dp)
|
||||
.size(24.dp),
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
TextShimmer(
|
||||
text = stringResourceSafe(R.string.yield_module_unavailable_title),
|
||||
style = TangemTheme.typography.button,
|
||||
)
|
||||
TextShimmer(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.yield_module_unavailable_subtitle),
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
TextShimmer(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = stringResourceSafe(R.string.yield_module_unavailable_subtitle),
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
SecondaryButton(
|
||||
text = stringResourceSafe(R.string.common_learn_more),
|
||||
onClick = { },
|
||||
showProgress = true,
|
||||
enabled = false,
|
||||
size = TangemButtonSize.WideAction,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SupplyInfo(
|
||||
title: TextReference,
|
||||
subtitle: TextReference,
|
||||
rewardsApy: TextReference?,
|
||||
iconTint: Color,
|
||||
modifier: Modifier = Modifier,
|
||||
button: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_analytics_up_24),
|
||||
contentDescription = null,
|
||||
tint = iconTint,
|
||||
modifier = Modifier
|
||||
.background(iconTint.copy(alpha = 0.1f), CircleShape)
|
||||
.padding(6.dp)
|
||||
.size(24.dp),
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
if (rewardsApy != null) {
|
||||
Text(
|
||||
text = StringsSigns.DOT,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
Text(
|
||||
text = rewardsApy.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
button?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun YieldSupplyBlockContent_Preview(@PreviewParameter(PreviewProvider::class) params: YieldSupplyUM) {
|
||||
TangemThemePreview {
|
||||
YieldSupplyBlockContentLegacy(yieldSupplyUM = params, modifier = Modifier)
|
||||
}
|
||||
}
|
||||
|
||||
private class PreviewProvider : PreviewParameterProvider<YieldSupplyUM> {
|
||||
override val values: Sequence<YieldSupplyUM>
|
||||
get() = sequenceOf(
|
||||
YieldSupplyUM.Available(
|
||||
title = TextReference.Res(
|
||||
R.string.yield_module_token_details_earn_notification_title,
|
||||
wrappedList("5.1"),
|
||||
),
|
||||
apy = "5.1",
|
||||
apyText = stringReference("5.1 % APY"),
|
||||
onClick = {},
|
||||
onLearnMoreClick = {},
|
||||
),
|
||||
YieldSupplyUM.Available(
|
||||
title = TextReference.Res(R.string.yield_apy_boost_banner_title),
|
||||
apy = "5.1",
|
||||
apyText = stringReference("APY 5.1% x3 → 15.3%"),
|
||||
onClick = {},
|
||||
onLearnMoreClick = {},
|
||||
isBoostAvailable = true,
|
||||
),
|
||||
YieldSupplyUM.Content(
|
||||
title = stringReference("Aave l"),
|
||||
subtitle = stringReference("Interest accrues automatically"),
|
||||
rewardsApy = stringReference("APY 5.1%"),
|
||||
onClick = {},
|
||||
apy = "5.1",
|
||||
shouldShowWarningIcon = false,
|
||||
shouldShowInfoIcon = true,
|
||||
),
|
||||
YieldSupplyUM.Content(
|
||||
title = stringReference("Aave lending is active "),
|
||||
subtitle = stringReference("Interest accrues automatically"),
|
||||
rewardsApy = stringReference("APY 5.1%"),
|
||||
onClick = {},
|
||||
apy = "5.1",
|
||||
shouldShowWarningIcon = true,
|
||||
shouldShowInfoIcon = false,
|
||||
),
|
||||
YieldSupplyUM.Loading,
|
||||
YieldSupplyUM.Processing.Enter,
|
||||
YieldSupplyUM.Processing.Exit,
|
||||
YieldSupplyUM.Unavailable,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
Loading…
Add table
Add a link
Reference in a new issue