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 {
|
) : DesignFeatureToggles {
|
||||||
|
|
||||||
override val isRedesignEnabled: Boolean
|
override val isRedesignEnabled: Boolean
|
||||||
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.APP_REDESIGN_ENABLED)
|
get() = true
|
||||||
|
|
||||||
override val isWarningsRefactoringEnabled: Boolean
|
override val isWarningsRefactoringEnabled: Boolean
|
||||||
get() = isRedesignEnabled &&
|
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.AND_14829_WARNINGS_REFACTORING_ENABLED)
|
||||||
featureTogglesManager.isFeatureEnabled(FeatureToggles.AND_14829_WARNINGS_REFACTORING_ENABLED)
|
|
||||||
}
|
}
|
||||||
|
|
@ -98,15 +98,13 @@ internal fun RootContent(
|
||||||
hostState = snackbarHostState,
|
hostState = snackbarHostState,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (LocalRedesignEnabled.current) {
|
TangemTopSnackbarHost(
|
||||||
TangemTopSnackbarHost(
|
modifier = Modifier
|
||||||
modifier = Modifier
|
.align(Alignment.TopCenter)
|
||||||
.align(Alignment.TopCenter)
|
.statusBarsPadding()
|
||||||
.statusBarsPadding()
|
.padding(all = 16.dp),
|
||||||
.padding(all = 16.dp),
|
hostState = LocalTopSnackbarHostState.current,
|
||||||
hostState = LocalTopSnackbarHostState.current,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventMessageEffect()
|
EventMessageEffect()
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ import com.tangem.common.ui.charts.state.*
|
||||||
import com.tangem.core.ui.components.SpacerH16
|
import com.tangem.core.ui.components.SpacerH16
|
||||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||||
import com.tangem.core.ui.res.LocalHapticManager
|
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.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||||
|
|
@ -317,19 +316,9 @@ private fun rememberMarketChartBottomAxis(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun rememberChartAxisGuidelineComponent(color: Color, isWithPadding: Boolean = true): LineComponent {
|
private fun rememberChartAxisGuidelineComponent(color: Color, isWithPadding: Boolean = true): LineComponent {
|
||||||
val isRedesign = LocalRedesignEnabled.current
|
val startPadding = TangemTheme.dimens2.x2_5
|
||||||
|
|
||||||
val startPadding = if (isRedesign) {
|
val endPadding = TangemTheme.dimens2.x2
|
||||||
TangemTheme.dimens2.x2_5
|
|
||||||
} else {
|
|
||||||
TangemTheme.dimens.spacing4
|
|
||||||
}
|
|
||||||
|
|
||||||
val endPadding = if (isRedesign) {
|
|
||||||
TangemTheme.dimens2.x2
|
|
||||||
} else {
|
|
||||||
TangemTheme.dimens.spacing4
|
|
||||||
}
|
|
||||||
|
|
||||||
return rememberAxisGuidelineComponent(
|
return rememberAxisGuidelineComponent(
|
||||||
color = color,
|
color = color,
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,6 @@ fun MarketListItemContentV2(model: MarketsListItemUM, modifier: Modifier = Modif
|
||||||
.layoutId(layoutId = TangemRowLayoutId.END_TOP)
|
.layoutId(layoutId = TangemRowLayoutId.END_TOP)
|
||||||
.padding(start = TangemTheme.dimens2.x3)
|
.padding(start = TangemTheme.dimens2.x3)
|
||||||
.testTag(tag = TokenElementsTestTags.TOKEN_FIAT_AMOUNT),
|
.testTag(tag = TokenElementsTestTags.TOKEN_FIAT_AMOUNT),
|
||||||
price = model.price.text,
|
|
||||||
priceChangeType = model.price.changeType,
|
priceChangeType = model.price.changeType,
|
||||||
priceAnnotated = model.price.annotated,
|
priceAnnotated = model.price.annotated,
|
||||||
priceValue = model.price.fiatPrice,
|
priceValue = model.price.fiatPrice,
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,12 @@ package com.tangem.common.ui.markets
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MarketsListItem(model: MarketsListItemUM, modifier: Modifier = Modifier, onClick: () -> Unit = {}) {
|
fun MarketsListItem(model: MarketsListItemUM, modifier: Modifier = Modifier, onClick: () -> Unit = {}) {
|
||||||
if (LocalRedesignEnabled.current) {
|
MarketsListItemV2(
|
||||||
MarketsListItemV2(
|
model = model,
|
||||||
model = model,
|
modifier = modifier,
|
||||||
modifier = modifier,
|
onClick = onClick,
|
||||||
onClick = onClick,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
MarketsListItemV1(
|
|
||||||
model = model,
|
|
||||||
modifier = modifier,
|
|
||||||
onClick = onClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,92 +7,15 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import com.tangem.core.ui.components.*
|
import com.tangem.core.ui.components.*
|
||||||
import com.tangem.core.ui.res.*
|
import com.tangem.core.ui.res.*
|
||||||
import com.tangem.core.ui.windowsize.WindowSizeType
|
import com.tangem.core.ui.windowsize.WindowSizeType
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun MarketsListItemPlaceholder() {
|
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
|
val windowSize = LocalWindowSize.current
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(
|
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.components.marketprice.PriceChangeType
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text view for token price.
|
* Text view for token price.
|
||||||
*
|
*
|
||||||
* @param price Plain price string (used by V1 and as fallback for V2 when [priceAnnotated] is null).
|
* @param priceValue Numeric price; drives the change animation (used as the LaunchedEffect key).
|
||||||
* @param priceAnnotated Optional styled price (locale-aware decimal separator + secondary fractional color).
|
* @param priceAnnotated Styled price (locale-aware decimal separator + secondary fractional color).
|
||||||
* @param priceChangeType Type of the price change.
|
* @param priceChangeType Type of the price change.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun TokenPriceText(
|
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,
|
priceValue: BigDecimal,
|
||||||
priceAnnotated: TextReference,
|
priceAnnotated: TextReference,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import com.arkivanov.decompose.router.stack.ChildStack
|
import com.arkivanov.decompose.router.stack.ChildStack
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
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.addtoportfolio.model.AddToPortfolioRoutes
|
||||||
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
|
||||||
|
|
||||||
|
|
@ -16,19 +15,11 @@ internal fun AddToPortfolioBottomSheetSwitch(
|
||||||
userPortfolioState: State<UserPortfolioUM?>? = null,
|
userPortfolioState: State<UserPortfolioUM?>? = null,
|
||||||
onAddFromUserPortfolioClick: (() -> Unit)? = null,
|
onAddFromUserPortfolioClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
if (LocalRedesignEnabled.current) {
|
AddToPortfolioBottomSheetV2(
|
||||||
AddToPortfolioBottomSheetV2(
|
childStack = childStack,
|
||||||
childStack = childStack,
|
onBack = onBack,
|
||||||
onBack = onBack,
|
onDismiss = onDismiss,
|
||||||
onDismiss = onDismiss,
|
userPortfolioState = userPortfolioState,
|
||||||
userPortfolioState = userPortfolioState,
|
onAddFromUserPortfolioClick = onAddFromUserPortfolioClick,
|
||||||
onAddFromUserPortfolioClick = onAddFromUserPortfolioClick,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
AddToPortfolioBottomSheet(
|
|
||||||
childStack = childStack,
|
|
||||||
onBack = onBack,
|
|
||||||
onDismiss = onDismiss,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -3,13 +3,11 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.common.ui.addtoken.AddTokenContent
|
|
||||||
import com.tangem.common.ui.addtoken.AddTokenContentV2
|
import com.tangem.common.ui.addtoken.AddTokenContentV2
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedNetwork
|
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedNetwork
|
||||||
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedPortfolio
|
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedPortfolio
|
||||||
|
|
@ -31,17 +29,10 @@ internal class AddTokenComponent @AssistedInject constructor(
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state = model.uiState.collectAsStateWithLifecycle()
|
val state = model.uiState.collectAsStateWithLifecycle()
|
||||||
val um = state.value ?: return
|
val um = state.value ?: return
|
||||||
if (LocalRedesignEnabled.current) {
|
AddTokenContentV2(
|
||||||
AddTokenContentV2(
|
modifier = modifier,
|
||||||
modifier = modifier,
|
state = um,
|
||||||
state = um,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
AddTokenContent(
|
|
||||||
modifier = modifier,
|
|
||||||
state = um,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Params(
|
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.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
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.extensions.resourceReference
|
||||||
import com.tangem.core.ui.message.ToastMessage
|
import com.tangem.core.ui.message.ToastMessage
|
||||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||||
|
|
@ -56,7 +55,6 @@ internal class AddToPortfolioModel @Inject constructor(
|
||||||
paramsContainer: ParamsContainer,
|
paramsContainer: ParamsContainer,
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
val portfolioSelectorController: PortfolioSelectorController,
|
val portfolioSelectorController: PortfolioSelectorController,
|
||||||
private val designFeatureToggles: DesignFeatureToggles,
|
|
||||||
private val callbackDelegate: AddToPortfolioCallbackDelegate,
|
private val callbackDelegate: AddToPortfolioCallbackDelegate,
|
||||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
|
||||||
private val getTokenMarketCryptoCurrency: GetTokenMarketCryptoCurrency,
|
private val getTokenMarketCryptoCurrency: GetTokenMarketCryptoCurrency,
|
||||||
|
|
@ -182,9 +180,9 @@ internal class AddToPortfolioModel @Inject constructor(
|
||||||
|
|
||||||
setupPortfolioSelector(initialData, launchMode)
|
setupPortfolioSelector(initialData, launchMode)
|
||||||
|
|
||||||
val shouldShowUserPortfolio = designFeatureToggles.isRedesignEnabled &&
|
val shouldShowUserPortfolio =
|
||||||
launchMode is AddToPortfolioManager.LaunchMode.ViaUserPortfolio &&
|
launchMode is AddToPortfolioManager.LaunchMode.ViaUserPortfolio &&
|
||||||
initialData.hasAnyAddedCurrency(tokenMarketParams.id)
|
initialData.hasAnyAddedCurrency(tokenMarketParams.id)
|
||||||
|
|
||||||
if (shouldShowUserPortfolio) {
|
if (shouldShowUserPortfolio) {
|
||||||
// suspend, must prepare UM before navigate to UserPortfolio
|
// suspend, must prepare UM before navigate to UserPortfolio
|
||||||
|
|
@ -200,11 +198,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
||||||
AddToPortfolioManager.LaunchMode.Preselected -> null
|
AddToPortfolioManager.LaunchMode.Preselected -> null
|
||||||
is AddToPortfolioManager.LaunchMode.ViaUserPortfolio,
|
is AddToPortfolioManager.LaunchMode.ViaUserPortfolio,
|
||||||
AddToPortfolioManager.LaunchMode.DirectAdd,
|
AddToPortfolioManager.LaunchMode.DirectAdd,
|
||||||
-> if (designFeatureToggles.isRedesignEnabled) {
|
-> getInitialSelection(initialData)
|
||||||
getInitialSelection(initialData)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val firstSelectedPortfolioFlow: Flow<SelectedPortfolio> =
|
val firstSelectedPortfolioFlow: Flow<SelectedPortfolio> =
|
||||||
|
|
@ -272,15 +266,11 @@ internal class AddToPortfolioModel @Inject constructor(
|
||||||
callbackDelegate.onChangePortfolioClick.receiveAsFlow()
|
callbackDelegate.onChangePortfolioClick.receiveAsFlow()
|
||||||
.onEach {
|
.onEach {
|
||||||
middleNavigationJob?.cancel()
|
middleNavigationJob?.cancel()
|
||||||
middleNavigationJob = if (designFeatureToggles.isRedesignEnabled) {
|
middleNavigationJob = changePortfolioNavigationNewFlow(
|
||||||
changePortfolioNavigationNewFlow(
|
data = initialData,
|
||||||
data = initialData,
|
orderedNetworks = paramsSnapshot.networks,
|
||||||
orderedNetworks = paramsSnapshot.networks,
|
tokenParams = tokenMarketParams,
|
||||||
tokenParams = tokenMarketParams,
|
).launchIn(this)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
changePortfolioNavigationFlow(initialData)
|
|
||||||
}.launchIn(this)
|
|
||||||
logAccountSelector(isAccountMode)
|
logAccountSelector(isAccountMode)
|
||||||
navigation.pushNew(AddToPortfolioRoutes.PortfolioSelector)
|
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(
|
private fun changePortfolioNavigationNewFlow(
|
||||||
data: AvailableToAddData,
|
data: AvailableToAddData,
|
||||||
orderedNetworks: List<TokenMarketInfo.Network>,
|
orderedNetworks: List<TokenMarketInfo.Network>,
|
||||||
|
|
@ -432,7 +395,7 @@ internal class AddToPortfolioModel @Inject constructor(
|
||||||
currency = addedToken.currency,
|
currency = addedToken.currency,
|
||||||
accountId = selectedPortfolio.account.account.account.accountId,
|
accountId = selectedPortfolio.account.account.account.accountId,
|
||||||
).onEach { state ->
|
).onEach { state ->
|
||||||
val requestedQuickActions = toQuickActions(state.states, designFeatureToggles.isRedesignEnabled)
|
val requestedQuickActions = toQuickActions(state.states, isRedesignEnabled = true)
|
||||||
when {
|
when {
|
||||||
requestedQuickActions.isNotEmpty() -> {
|
requestedQuickActions.isNotEmpty() -> {
|
||||||
timerJob.cancel()
|
timerJob.cancel()
|
||||||
|
|
|
||||||
|
|
@ -49,17 +49,10 @@ private const val DISABLED_ALPHA = 0.4f
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
|
||||||
if (LocalRedesignEnabled.current) {
|
ChooseNetworkContentV2(
|
||||||
ChooseNetworkContentV2(
|
state = state,
|
||||||
state = state,
|
modifier = modifier,
|
||||||
modifier = modifier,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
ChooseNetworkContentV1(
|
|
||||||
state = state,
|
|
||||||
modifier = modifier,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@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.TangemTokenRowUM
|
||||||
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
|
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
|
||||||
import com.tangem.core.ui.extensions.*
|
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.TangemColorPalette
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
|
@ -136,13 +135,7 @@ private val ChooseTokenFullUM.isEmptyState: Boolean
|
||||||
internal fun ChooseTokenScreen(state: ChooseTokenFullUM, modifier: Modifier = Modifier) {
|
internal fun ChooseTokenScreen(state: ChooseTokenFullUM, modifier: Modifier = Modifier) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(
|
.background(color = TangemTheme.colors2.surface.level2)
|
||||||
color = if (LocalRedesignEnabled.current) {
|
|
||||||
TangemTheme.colors2.surface.level2
|
|
||||||
} else {
|
|
||||||
TangemTheme.colors.background.secondary
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.imePadding(),
|
.imePadding(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
|
@ -747,11 +740,7 @@ private fun LazyListScope.predefinedTokensListItems(state: PredefinedTokensUM) {
|
||||||
.roundedShapeItemDecoration(
|
.roundedShapeItemDecoration(
|
||||||
currentIndex = index,
|
currentIndex = index,
|
||||||
lastIndex = state.items.lastIndex,
|
lastIndex = state.items.lastIndex,
|
||||||
backgroundColor = if (LocalRedesignEnabled.current) {
|
backgroundColor = TangemTheme.colors2.surface.level1,
|
||||||
TangemTheme.colors2.surface.level1
|
|
||||||
} else {
|
|
||||||
TangemTheme.colors.background.primary
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
.testTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
|
.testTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
|
||||||
.semantics { lazyListItemPosition = index },
|
.semantics { lazyListItemPosition = index },
|
||||||
|
|
@ -811,13 +800,7 @@ private fun LazyListScope.emptyTokensList(modifier: Modifier = Modifier) {
|
||||||
item("EmptyTokensList") {
|
item("EmptyTokensList") {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(
|
.background(color = TangemTheme.colors2.surface.level2)
|
||||||
color = if (LocalRedesignEnabled.current) {
|
|
||||||
TangemTheme.colors2.surface.level2
|
|
||||||
} else {
|
|
||||||
TangemTheme.colors.background.secondary
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.fillParentMaxSize(),
|
.fillParentMaxSize(),
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.align(Alignment.Center)) {
|
Column(modifier = Modifier.align(Alignment.Center)) {
|
||||||
|
|
@ -848,13 +831,7 @@ private fun LazyListScope.tokensNotFound(modifier: Modifier = Modifier) {
|
||||||
item("TokensNotFound") {
|
item("TokensNotFound") {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(
|
.background(color = TangemTheme.colors2.surface.level2)
|
||||||
color = if (LocalRedesignEnabled.current) {
|
|
||||||
TangemTheme.colors2.surface.level2
|
|
||||||
} else {
|
|
||||||
TangemTheme.colors.background.secondary
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.fillParentMaxSize(),
|
.fillParentMaxSize(),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,8 @@ import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
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.api.portfolioselector.PortfolioSelectorComponent
|
||||||
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorBS
|
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 com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContentV2
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
|
@ -48,19 +46,11 @@ internal class DefaultPortfolioSelectorComponent @AssistedInject constructor(
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
val listBottomPadding = PaddingValues(bottom = LocalTangemBottomSheetContentBottomInset.current)
|
val listBottomPadding = PaddingValues(bottom = LocalTangemBottomSheetContentBottomInset.current)
|
||||||
if (LocalRedesignEnabled.current) {
|
PortfolioSelectorContentV2(
|
||||||
PortfolioSelectorContentV2(
|
state = state,
|
||||||
state = state,
|
modifier = modifier,
|
||||||
modifier = modifier,
|
contentPadding = listBottomPadding,
|
||||||
contentPadding = listBottomPadding,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
PortfolioSelectorContent(
|
|
||||||
state = state,
|
|
||||||
modifier = modifier,
|
|
||||||
contentPadding = listBottomPadding,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
|
|
|
||||||
|
|
@ -45,19 +45,11 @@ internal fun PortfolioSelectorBS(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
if (LocalRedesignEnabled.current) {
|
PortfolioSelectorContentV2(
|
||||||
PortfolioSelectorContentV2(
|
state = state,
|
||||||
state = state,
|
contentPadding = PaddingValues(bottom = 16.dp),
|
||||||
contentPadding = PaddingValues(bottom = 16.dp),
|
modifier = modifier.padding(horizontal = 16.dp),
|
||||||
modifier = modifier.padding(horizontal = 16.dp),
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
PortfolioSelectorContent(
|
|
||||||
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.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.domain.models.TokenReceiveConfig
|
import com.tangem.domain.models.TokenReceiveConfig
|
||||||
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
|
||||||
import com.tangem.features.commonfeatures.impl.tokenactions.model.TokenActionsModel
|
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.commonfeatures.impl.tokenactions.ui.TokenActionsContentV2
|
||||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
|
|
@ -49,17 +47,10 @@ internal class TokenActionsComponent @AssistedInject constructor(
|
||||||
val state = model.uiState.collectAsStateWithLifecycle()
|
val state = model.uiState.collectAsStateWithLifecycle()
|
||||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||||
val tokenActionsUM = state.value ?: return
|
val tokenActionsUM = state.value ?: return
|
||||||
if (LocalRedesignEnabled.current || params.isRedesignForced) {
|
TokenActionsContentV2(
|
||||||
TokenActionsContentV2(
|
modifier = modifier,
|
||||||
modifier = modifier,
|
state = tokenActionsUM,
|
||||||
state = tokenActionsUM,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
TokenActionsContent(
|
|
||||||
modifier = modifier,
|
|
||||||
state = tokenActionsUM,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
bottomSheet.child?.instance?.BottomSheet()
|
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.common.ui.userwallet.converter.WalletIconUMConverter
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
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.components.token.state.TokenItemState
|
||||||
import com.tangem.core.ui.ds.badge.TangemBadgeIconPosition
|
import com.tangem.core.ui.ds.badge.TangemBadgeIconPosition
|
||||||
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
import com.tangem.core.ui.ds.badge.TangemBadgeShape
|
||||||
|
|
@ -41,7 +40,6 @@ import javax.inject.Inject
|
||||||
@ModelScoped
|
@ModelScoped
|
||||||
internal class TokenActionsUiBuilder @Inject constructor(
|
internal class TokenActionsUiBuilder @Inject constructor(
|
||||||
paramsContainer: ParamsContainer,
|
paramsContainer: ParamsContainer,
|
||||||
private val designFeatureToggles: DesignFeatureToggles,
|
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val getWalletsUseCase: GetWalletsUseCase,
|
private val getWalletsUseCase: GetWalletsUseCase,
|
||||||
private val walletIconUMConverter: WalletIconUMConverter,
|
private val walletIconUMConverter: WalletIconUMConverter,
|
||||||
|
|
@ -55,51 +53,12 @@ internal class TokenActionsUiBuilder @Inject constructor(
|
||||||
isBalanceHidden: Boolean,
|
isBalanceHidden: Boolean,
|
||||||
bottomAction: BottomAction,
|
bottomAction: BottomAction,
|
||||||
): TokenActionsUM {
|
): TokenActionsUM {
|
||||||
return if (designFeatureToggles.isRedesignEnabled || params.isRedesignForced) {
|
return buildV2(
|
||||||
buildV2(
|
cryptoCurrencyData = cryptoCurrencyData,
|
||||||
cryptoCurrencyData = cryptoCurrencyData,
|
tokenActionsHandler = tokenActionsHandler,
|
||||||
tokenActionsHandler = tokenActionsHandler,
|
appCurrency = appCurrency,
|
||||||
appCurrency = appCurrency,
|
isBalanceHidden = isBalanceHidden,
|
||||||
isBalanceHidden = isBalanceHidden,
|
bottomAction = bottomAction,
|
||||||
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)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,10 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
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
|
||||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent.Params
|
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.model.TokenMarketBlockModel
|
||||||
import com.tangem.features.markets.token.block.impl.ui.TokenMarketBlock
|
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.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
|
@ -29,17 +27,10 @@ internal class DefaultTokenMarketBlockComponent @AssistedInject constructor(
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
if (LocalRedesignEnabled.current) {
|
TokenMarketBlock(
|
||||||
TokenMarketBlock(
|
tokenMarketBlockUM = state,
|
||||||
tokenMarketBlockUM = state,
|
modifier = modifier,
|
||||||
modifier = modifier,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
TokenMarketBlockLegacy(
|
|
||||||
state = state,
|
|
||||||
modifier = modifier,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AssistedFactory
|
@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.unit.dp
|
||||||
import androidx.compose.ui.util.lerp
|
import androidx.compose.ui.util.lerp
|
||||||
import com.tangem.core.ui.components.SpacerH8
|
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.notifications.NotificationConfig
|
||||||
import com.tangem.core.ui.components.pager.PagerIndicator
|
import com.tangem.core.ui.components.pager.PagerIndicator
|
||||||
import com.tangem.core.ui.ds.message.TangemMessage
|
import com.tangem.core.ui.ds.message.TangemMessage
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
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.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
|
|
@ -67,41 +65,23 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, horizontalItemPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun bannerContainerColor(placeholder: Placeholder): Color = if (LocalRedesignEnabled.current) {
|
private fun bannerContainerColor(placeholder: Placeholder): Color = when (placeholder) {
|
||||||
when (placeholder) {
|
Placeholder.MAIN -> TangemTheme.colors2.surface.level1
|
||||||
Placeholder.MAIN -> TangemTheme.colors2.surface.level1
|
Placeholder.FEED -> TangemTheme.colors2.surface.level3
|
||||||
Placeholder.FEED -> TangemTheme.colors2.surface.level3
|
Placeholder.PAYMENT_ACCOUNT_MAIN -> TangemTheme.colors3.bg.opaque.primary
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a banner either with the redesigned [TangemMessage] component or the legacy [Notification],
|
* Renders a banner with the [TangemMessage] component. Uses the same [NotificationConfig] as the banner
|
||||||
* depending on [LocalRedesignEnabled]. Both accept the same [NotificationConfig], so the banner model
|
* model and converters, so they stay untouched.
|
||||||
* and converters stay untouched.
|
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
private fun BannerNotification(config: NotificationConfig, containerColor: Color, modifier: Modifier = Modifier) {
|
private fun BannerNotification(config: NotificationConfig, containerColor: Color, modifier: Modifier = Modifier) {
|
||||||
if (LocalRedesignEnabled.current) {
|
TangemMessage(
|
||||||
TangemMessage(
|
config = config,
|
||||||
config = config,
|
modifier = modifier.fillMaxWidth(),
|
||||||
modifier = modifier.fillMaxWidth(),
|
contentColor = containerColor,
|
||||||
contentColor = containerColor,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Notification(
|
|
||||||
config = config,
|
|
||||||
modifier = modifier.fillMaxWidth(),
|
|
||||||
containerColor = containerColor,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.tangem.common.ui.account.AccountIcon
|
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.PrimaryButtonIconStart
|
||||||
import com.tangem.core.ui.components.SpacerH12
|
import com.tangem.core.ui.components.SpacerH12
|
||||||
import com.tangem.core.ui.components.SpacerW12
|
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.stringReference
|
||||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
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.LocalTopSnackbarHostState
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
|
@ -56,7 +54,6 @@ internal fun ParticipateBottomBlock(
|
||||||
code: String,
|
code: String,
|
||||||
shareLink: String,
|
shareLink: String,
|
||||||
expectedAwards: ExpectedAwards?,
|
expectedAwards: ExpectedAwards?,
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
onAgreementClick: () -> Unit,
|
onAgreementClick: () -> Unit,
|
||||||
onCopyClick: () -> Unit,
|
onCopyClick: () -> Unit,
|
||||||
onShareClick: (String) -> Unit,
|
onShareClick: (String) -> Unit,
|
||||||
|
|
@ -75,7 +72,6 @@ internal fun ParticipateBottomBlock(
|
||||||
AdditionalButtons(
|
AdditionalButtons(
|
||||||
code = code,
|
code = code,
|
||||||
shareLink = shareLink,
|
shareLink = shareLink,
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
onCopyClick = onCopyClick,
|
onCopyClick = onCopyClick,
|
||||||
onShareClick = onShareClick,
|
onShareClick = onShareClick,
|
||||||
)
|
)
|
||||||
|
|
@ -350,7 +346,6 @@ private fun AwardAccount(accountAward: ReferralStateHolder.AccountAward) {
|
||||||
private fun AdditionalButtons(
|
private fun AdditionalButtons(
|
||||||
code: String,
|
code: String,
|
||||||
shareLink: String,
|
shareLink: String,
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
onCopyClick: () -> Unit,
|
onCopyClick: () -> Unit,
|
||||||
onShareClick: (String) -> Unit,
|
onShareClick: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
|
@ -358,8 +353,6 @@ private fun AdditionalButtons(
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val resources = LocalContext.current.resources
|
|
||||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
|
||||||
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
val tangemTopSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -375,19 +368,12 @@ private fun AdditionalButtons(
|
||||||
clipboardManager.setText(AnnotatedString(code))
|
clipboardManager.setText(AnnotatedString(code))
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
if (isRedesignEnabled) {
|
tangemTopSnackbarHostState.showSnackbar(
|
||||||
tangemTopSnackbarHostState.showSnackbar(
|
SnackbarMessage(
|
||||||
SnackbarMessage(
|
startIconId = R.drawable.ic_check_24,
|
||||||
startIconId = R.drawable.ic_check_24,
|
message = resourceReference(R.string.referral_promo_code_copied),
|
||||||
message = resourceReference(R.string.referral_promo_code_copied),
|
),
|
||||||
),
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
snackbarHostState.showSnackbar(
|
|
||||||
message = resources.getStringSafe(R.string.referral_promo_code_copied),
|
|
||||||
duration = SnackbarDuration.Short,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
|
|
@ -435,7 +421,6 @@ private fun ParticipateBottomBlockPreview(
|
||||||
code = data.code,
|
code = data.code,
|
||||||
shareLink = data.shareLink,
|
shareLink = data.shareLink,
|
||||||
expectedAwards = data.expectedAwards,
|
expectedAwards = data.expectedAwards,
|
||||||
snackbarHostState = SnackbarHostState(),
|
|
||||||
onAgreementClick = data.onAgreementClick,
|
onAgreementClick = data.onAgreementClick,
|
||||||
onCopyClick = data.onCopyClick,
|
onCopyClick = data.onCopyClick,
|
||||||
onShareClick = data.onShareClick,
|
onShareClick = data.onShareClick,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
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.SpacerH32
|
||||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
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.TokenItem
|
||||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
|
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
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.LocalTopSnackbarHostState
|
||||||
import com.tangem.core.ui.res.TangemColorPalette
|
import com.tangem.core.ui.res.TangemColorPalette
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
@ -69,8 +65,6 @@ import java.util.UUID
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||||
val snackbarHostState = remember(::SnackbarHostState)
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
AppBarWithBackButton(
|
AppBarWithBackButton(
|
||||||
|
|
@ -79,61 +73,30 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||||
onBackClick = stateHolder.headerState.onBackClicked,
|
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,
|
containerColor = TangemTheme.colors.background.secondary,
|
||||||
) {
|
) { paddingValues ->
|
||||||
ReferralContent(
|
ReferralContent(
|
||||||
stateHolder = stateHolder,
|
stateHolder = stateHolder,
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
onAgreementClick = stateHolder.analytics.onAgreementClicked,
|
onAgreementClick = stateHolder.analytics.onAgreementClicked,
|
||||||
modifier = Modifier.padding(it),
|
modifier = Modifier.padding(paddingValues),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val errorSnackbar = stateHolder.errorSnackbar
|
val errorSnackbar = stateHolder.errorSnackbar
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val resources = LocalContext.current.resources
|
val resources = LocalContext.current.resources
|
||||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
|
||||||
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
val topSnackbarHostState = LocalTopSnackbarHostState.current
|
||||||
|
|
||||||
SideEffect {
|
SideEffect {
|
||||||
if (errorSnackbar != null) {
|
if (errorSnackbar != null) {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
if (isRedesignEnabled) {
|
topSnackbarHostState.showSnackbar(
|
||||||
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(
|
|
||||||
message = resources.getMessageForErrorSnackbar(errorSnackbar.throwable),
|
message = resources.getMessageForErrorSnackbar(errorSnackbar.throwable),
|
||||||
actionLabel = resources.getStringSafe(R.string.warning_button_ok),
|
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
|
@Composable
|
||||||
private fun ReferralContent(
|
private fun ReferralContent(
|
||||||
stateHolder: ReferralStateHolder,
|
stateHolder: ReferralStateHolder,
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
onAgreementClick: () -> Unit,
|
onAgreementClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
@ -155,7 +117,6 @@ private fun ReferralContent(
|
||||||
item {
|
item {
|
||||||
ReferralInfo(
|
ReferralInfo(
|
||||||
stateHolder = stateHolder,
|
stateHolder = stateHolder,
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
onAgreementClick = onAgreementClick,
|
onAgreementClick = onAgreementClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -189,11 +150,7 @@ private fun Header() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReferralInfo(
|
private fun ReferralInfo(stateHolder: ReferralStateHolder, onAgreementClick: () -> Unit) {
|
||||||
stateHolder: ReferralStateHolder,
|
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
onAgreementClick: () -> Unit,
|
|
||||||
) {
|
|
||||||
when (val state = stateHolder.referralInfoState) {
|
when (val state = stateHolder.referralInfoState) {
|
||||||
is ReferralInfoState.ParticipantContent -> {
|
is ReferralInfoState.ParticipantContent -> {
|
||||||
Conditions(state = state)
|
Conditions(state = state)
|
||||||
|
|
@ -203,7 +160,6 @@ private fun ReferralInfo(
|
||||||
shareLink = state.shareLink,
|
shareLink = state.shareLink,
|
||||||
expectedAwards = state.expectedAwards,
|
expectedAwards = state.expectedAwards,
|
||||||
accountAward = state.accountAward,
|
accountAward = state.accountAward,
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
onAgreementClick = onAgreementClick,
|
onAgreementClick = onAgreementClick,
|
||||||
onCopyClick = stateHolder.analytics.onCopyClicked,
|
onCopyClick = stateHolder.analytics.onCopyClicked,
|
||||||
onShareClick = stateHolder.analytics.onShareClicked,
|
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.model.getOrCreateModel
|
||||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
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.TokenReceiveComponent
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveModel
|
||||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheet
|
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheet
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveContentSheetLegacy
|
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
|
@ -45,21 +43,12 @@ internal class DefaultTokenReceiveComponent @AssistedInject constructor(
|
||||||
override fun BottomSheet() {
|
override fun BottomSheet() {
|
||||||
val content by contentStack.subscribeAsState()
|
val content by contentStack.subscribeAsState()
|
||||||
val currentRoute = content.active.configuration
|
val currentRoute = content.active.configuration
|
||||||
if (LocalRedesignEnabled.current) {
|
TokenReceiveContentSheet(
|
||||||
TokenReceiveContentSheet(
|
route = currentRoute,
|
||||||
route = currentRoute,
|
onCloseClick = ::dismiss,
|
||||||
onCloseClick = ::dismiss,
|
onBackClick = ::onChildBack,
|
||||||
onBackClick = ::onChildBack,
|
contentStack = content,
|
||||||
contentStack = content,
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
TokenReceiveContentSheetLegacy(
|
|
||||||
route = currentRoute,
|
|
||||||
onCloseClick = ::dismiss,
|
|
||||||
onBackClick = ::onChildBack,
|
|
||||||
contentStack = content,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dismiss() = model.params.onDismiss()
|
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.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
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.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
||||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContent
|
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContent
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContentLegacy
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
internal class TokenReceiveAssetsComponent(
|
internal class TokenReceiveAssetsComponent(
|
||||||
|
|
@ -27,11 +25,7 @@ internal class TokenReceiveAssetsComponent(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
if (LocalRedesignEnabled.current) {
|
TokenReceiveAssetsContent(assetsUM = state)
|
||||||
TokenReceiveAssetsContent(assetsUM = state)
|
|
||||||
} else {
|
|
||||||
TokenReceiveAssetsContentLegacy(assetsUM = state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TokenReceiveAssetsModelCallback {
|
internal interface TokenReceiveAssetsModelCallback {
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
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.TokenReceiveType
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
|
||||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContent
|
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContent
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContentLegacy
|
|
||||||
|
|
||||||
internal class TokenReceiveQrCodeComponent(
|
internal class TokenReceiveQrCodeComponent(
|
||||||
appComponentContext: AppComponentContext,
|
appComponentContext: AppComponentContext,
|
||||||
|
|
@ -26,11 +24,7 @@ internal class TokenReceiveQrCodeComponent(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
if (LocalRedesignEnabled.current) {
|
TokenReceiveQrCodeContent(qrCodeUM = state)
|
||||||
TokenReceiveQrCodeContent(qrCodeUM = state)
|
|
||||||
} else {
|
|
||||||
TokenReceiveQrCodeContentLegacy(qrCodeUM = state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TokenReceiveQrCodeModelCallback {
|
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.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
|
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContent
|
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContent
|
||||||
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContentLegacy
|
|
||||||
|
|
||||||
internal class TokenReceiveWarningComponent(
|
internal class TokenReceiveWarningComponent(
|
||||||
appComponentContext: AppComponentContext,
|
appComponentContext: AppComponentContext,
|
||||||
|
|
@ -24,11 +22,7 @@ internal class TokenReceiveWarningComponent(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val state by model.state.collectAsStateWithLifecycle()
|
val state by model.state.collectAsStateWithLifecycle()
|
||||||
if (LocalRedesignEnabled.current) {
|
TokenReceiveWarningContent(warningUM = state)
|
||||||
TokenReceiveWarningContent(warningUM = state)
|
|
||||||
} else {
|
|
||||||
TokenReceiveWarningContentLegacy(warningUM = state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TokenReceiveWarningModelCallback {
|
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.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
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.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel
|
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.route.TokenDetailsBottomSheetConfig
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
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.ChooseAddressBottomSheetComponent
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
||||||
|
|
@ -154,31 +152,18 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
||||||
val txHistoryDetails by txHistoryDetailsSlot.subscribeAsState()
|
val txHistoryDetails by txHistoryDetailsSlot.subscribeAsState()
|
||||||
NavigationBar3ButtonsScrim()
|
NavigationBar3ButtonsScrim()
|
||||||
|
|
||||||
if (LocalRedesignEnabled.current) {
|
val tokenDetailsUM by model.redesignUiState.collectAsStateWithLifecycle()
|
||||||
val tokenDetailsUM by model.redesignUiState.collectAsStateWithLifecycle()
|
|
||||||
|
|
||||||
TokenDetailsScreen(
|
TokenDetailsScreen(
|
||||||
tokenDetailsUM = tokenDetailsUM,
|
tokenDetailsUM = tokenDetailsUM,
|
||||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||||
yieldSupplyComponent = yieldSupplyComponent,
|
yieldSupplyComponent = yieldSupplyComponent,
|
||||||
txHistoryComponent = txHistoryComponent,
|
txHistoryComponent = txHistoryComponent,
|
||||||
expressTransactionsComponent = expressTransactionsComponent,
|
expressTransactionsComponent = expressTransactionsComponent,
|
||||||
ratingComponent = ratingSlotState.child?.instance,
|
ratingComponent = ratingSlotState.child?.instance,
|
||||||
marketingBannerComponent = marketingBannerComponent,
|
marketingBannerComponent = marketingBannerComponent,
|
||||||
modifier = modifier,
|
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
bottomSheet.child?.instance?.BottomSheet()
|
bottomSheet.child?.instance?.BottomSheet()
|
||||||
txHistoryDetails.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.model.ParamsContainer
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
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.clipboard.ClipboardManager
|
||||||
import com.tangem.core.ui.ds.image.DeviceIconUM
|
import com.tangem.core.ui.ds.image.DeviceIconUM
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
|
@ -184,7 +183,6 @@ internal class TokenDetailsModel @Inject constructor(
|
||||||
private val getWalletIconUseCase: GetWalletIconUseCase,
|
private val getWalletIconUseCase: GetWalletIconUseCase,
|
||||||
private val walletIconUMConverter: WalletIconUMConverter,
|
private val walletIconUMConverter: WalletIconUMConverter,
|
||||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||||
private val designFeatureToggles: DesignFeatureToggles,
|
|
||||||
private val redesignStateController: TokenDetailsStateController,
|
private val redesignStateController: TokenDetailsStateController,
|
||||||
private val swapFeedbackUseCase: SwapFeedbackUseCase,
|
private val swapFeedbackUseCase: SwapFeedbackUseCase,
|
||||||
private val quickTopUpBlockFactory: QuickTopUpBlockFactory,
|
private val quickTopUpBlockFactory: QuickTopUpBlockFactory,
|
||||||
|
|
@ -346,10 +344,8 @@ internal class TokenDetailsModel @Inject constructor(
|
||||||
uiState.value = stateFactory.getStateWithUpdatedHidden(
|
uiState.value = stateFactory.getStateWithUpdatedHidden(
|
||||||
isBalanceHidden = settings.isBalanceHidden,
|
isBalanceHidden = settings.isBalanceHidden,
|
||||||
)
|
)
|
||||||
if (designFeatureToggles.isRedesignEnabled) {
|
redesignStateController.update { state ->
|
||||||
redesignStateController.update { state ->
|
state.copy(isBalanceHidden = settings.isBalanceHidden)
|
||||||
state.copy(isBalanceHidden = settings.isBalanceHidden)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
|
|
@ -366,38 +362,36 @@ internal class TokenDetailsModel @Inject constructor(
|
||||||
latestTokenActions = state.states
|
latestTokenActions = state.states
|
||||||
sendButtonsEvents(state.states)
|
sendButtonsEvents(state.states)
|
||||||
uiState.value = stateFactory.getManageButtonsState(actions = state.states)
|
uiState.value = stateFactory.getManageButtonsState(actions = state.states)
|
||||||
if (designFeatureToggles.isRedesignEnabled) {
|
val networkSource = currencyStatus.value.sources.networkSource
|
||||||
val networkSource = currencyStatus.value.sources.networkSource
|
redesignStateController.update(
|
||||||
redesignStateController.update(
|
UpdateActionButtonsTransformer(
|
||||||
UpdateActionButtonsTransformer(
|
actions = state.states,
|
||||||
actions = state.states,
|
clickIntents = this@TokenDetailsModel,
|
||||||
clickIntents = this@TokenDetailsModel,
|
),
|
||||||
),
|
)
|
||||||
)
|
redesignStateController.update(
|
||||||
redesignStateController.update(
|
UpdateAddFundsTransformer(
|
||||||
UpdateAddFundsTransformer(
|
actions = state.states,
|
||||||
actions = state.states,
|
networkSource = networkSource,
|
||||||
networkSource = networkSource,
|
clickIntents = this@TokenDetailsModel,
|
||||||
clickIntents = this@TokenDetailsModel,
|
onActionDispatched = bottomSheetNavigation::dismiss,
|
||||||
onActionDispatched = bottomSheetNavigation::dismiss,
|
),
|
||||||
),
|
)
|
||||||
)
|
redesignStateController.update(
|
||||||
redesignStateController.update(
|
UpdateTransferTransformer(
|
||||||
UpdateTransferTransformer(
|
actions = state.states,
|
||||||
actions = state.states,
|
networkSource = networkSource,
|
||||||
networkSource = networkSource,
|
clickIntents = this@TokenDetailsModel,
|
||||||
clickIntents = this@TokenDetailsModel,
|
analyticsEventHandler = analyticsEventsHandler,
|
||||||
analyticsEventHandler = analyticsEventsHandler,
|
onActionDispatched = bottomSheetNavigation::dismiss,
|
||||||
onActionDispatched = bottomSheetNavigation::dismiss,
|
),
|
||||||
),
|
)
|
||||||
)
|
redesignStateController.update(
|
||||||
redesignStateController.update(
|
UpdateZeroBalanceActionsTransformer(
|
||||||
UpdateZeroBalanceActionsTransformer(
|
actions = state.states,
|
||||||
actions = state.states,
|
clickIntents = this@TokenDetailsModel,
|
||||||
clickIntents = this@TokenDetailsModel,
|
),
|
||||||
),
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.flowOn(dispatchers.main)
|
.flowOn(dispatchers.main)
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
|
|
@ -1502,7 +1496,6 @@ internal class TokenDetailsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initRedesign() {
|
private fun initRedesign() {
|
||||||
if (!designFeatureToggles.isRedesignEnabled) return
|
|
||||||
initRedesignState()
|
initRedesignState()
|
||||||
observeRedesignBalance()
|
observeRedesignBalance()
|
||||||
updateRedesignTopBarMenu()
|
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.common.ui.earn.EarnBlockUM
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
|
||||||
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
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.model.YieldSupplyModel
|
||||||
import com.tangem.features.yield.supply.impl.main.ui.YieldSupplyBlockContentLegacy
|
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
|
@ -27,21 +25,16 @@ internal class DefaultYieldSupplyComponent @AssistedInject constructor(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
if (LocalRedesignEnabled.current) {
|
val earnBlockUM by model.uiState.collectAsStateWithLifecycle()
|
||||||
val earnBlockUM by model.uiState.collectAsStateWithLifecycle()
|
earnBlockUM?.let { blockUM ->
|
||||||
earnBlockUM?.let { blockUM ->
|
val tag = if (blockUM is EarnBlockUM.Content &&
|
||||||
val tag = if (blockUM is EarnBlockUM.Content &&
|
blockUM.backgroundUM is EarnBlockUM.BackgroundUM.AccentSoft
|
||||||
blockUM.backgroundUM is EarnBlockUM.BackgroundUM.AccentSoft
|
) {
|
||||||
) {
|
TokenDetailsScreenTestTags.YIELD_SUPPLY_AVAILABLE_BLOCK
|
||||||
TokenDetailsScreenTestTags.YIELD_SUPPLY_AVAILABLE_BLOCK
|
} else {
|
||||||
} else {
|
TokenDetailsScreenTestTags.YIELD_SUPPLY_BLOCK
|
||||||
TokenDetailsScreenTestTags.YIELD_SUPPLY_BLOCK
|
|
||||||
}
|
|
||||||
EarnBlock(state = blockUM, modifier = modifier.testTag(tag))
|
|
||||||
}
|
}
|
||||||
} else {
|
EarnBlock(state = blockUM, modifier = modifier.testTag(tag))
|
||||||
val yieldSupplyUM by model.uiStateLegacy.collectAsStateWithLifecycle()
|
|
||||||
YieldSupplyBlockContentLegacy(yieldSupplyUM = yieldSupplyUM, modifier = modifier)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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