Updated on 2026-08-14
This commit is contained in:
parent
e23c6cf3e2
commit
ab6832b5e9
10 changed files with 619 additions and 419 deletions
|
|
@ -7,10 +7,12 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent.Params
|
||||
import com.tangem.features.markets.token.block.impl.model.TokenMarketBlockModel
|
||||
import com.tangem.features.markets.token.block.impl.ui.TokenMarketBlock
|
||||
import com.tangem.features.markets.token.block.impl.ui.TokenMarketBlockLegacy
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -27,10 +29,17 @@ internal class DefaultTokenMarketBlockComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
TokenMarketBlock(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TokenMarketBlock(
|
||||
tokenMarketBlockUM = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
TokenMarketBlockLegacy(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -1,216 +1,25 @@
|
|||
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.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
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.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 kotlin.random.Random
|
||||
|
||||
@Suppress("UnusedParameter")
|
||||
@Composable
|
||||
internal fun TokenMarketBlock(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,
|
||||
percentText = state.h24Percent,
|
||||
type = state.priceChangeType,
|
||||
)
|
||||
SpacerW8()
|
||||
RightSide(
|
||||
modifier = Modifier,
|
||||
priceChangeType = state.priceChangeType,
|
||||
chartRawData = state.chartData,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun LeftSide(
|
||||
symbol: String,
|
||||
priceText: String?,
|
||||
percentText: String?,
|
||||
type: PriceChangeType,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
internal fun TokenMarketBlock(tokenMarketBlockUM: TokenMarketBlockUM, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.wallet_marketplace_block_title, symbol),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
text = "Market Block Redesign",
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
if (priceText != null && percentText != null) {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
TokenPriceText(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
price = priceText,
|
||||
priceChangeType = type,
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
PriceChangeInPercent(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
valueInPercent = percentText,
|
||||
type = type,
|
||||
)
|
||||
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 = {},
|
||||
)
|
||||
|
||||
TangemThemePreview {
|
||||
Column(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.tertiary),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
TokenMarketBlock(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state,
|
||||
)
|
||||
TokenMarketBlock(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.copy(
|
||||
currentPrice = "0,0000000000012356786789$",
|
||||
),
|
||||
)
|
||||
TokenMarketBlock(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.copy(
|
||||
currentPrice = null,
|
||||
chartData = null,
|
||||
),
|
||||
)
|
||||
TokenMarketBlock(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = state.copy(
|
||||
chartData = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
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.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 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,
|
||||
percentText = state.h24Percent,
|
||||
type = state.priceChangeType,
|
||||
)
|
||||
SpacerW8()
|
||||
RightSide(
|
||||
modifier = Modifier,
|
||||
priceChangeType = state.priceChangeType,
|
||||
chartRawData = state.chartData,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun LeftSide(
|
||||
symbol: String,
|
||||
priceText: String?,
|
||||
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,
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
PriceChangeInPercent(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
valueInPercent = percentText,
|
||||
type = type,
|
||||
)
|
||||
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 = {},
|
||||
)
|
||||
|
||||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,11 +15,13 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.route.TokenDetailsBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreenLegacy
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
|
|
@ -84,15 +86,27 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
NavigationBar3ButtonsScrim()
|
||||
TokenDetailsScreen(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
)
|
||||
|
||||
if (LocalRedesignEnabled.current) {
|
||||
val tokenDetailsUM by model.redesignUiState.collectAsStateWithLifecycle()
|
||||
|
||||
TokenDetailsScreen(
|
||||
tokenDetailsUM = tokenDetailsUM,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
TokenDetailsScreenLegacy(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
)
|
||||
}
|
||||
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -87,7 +90,11 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.Token
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsNotificationsAnalyticsSender
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.route.TokenDetailsBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceTypeUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsTopAppBarUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.TokenDetailsExpressStatusFactory
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
|
|
@ -99,6 +106,7 @@ import com.tangem.utils.Provider
|
|||
import com.tangem.utils.coroutines.*
|
||||
import com.tangem.utils.extensions.isZero
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
|
@ -197,6 +205,9 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val internalUiState = MutableStateFlow(stateFactory.getInitialState(cryptoCurrency))
|
||||
val uiState: StateFlow<TokenDetailsState> = internalUiState
|
||||
|
||||
private val internalRedesignUiState = MutableStateFlow(createInitialRedesignState())
|
||||
val redesignUiState: StateFlow<TokenDetailsUM> = internalRedesignUiState
|
||||
|
||||
// region Clore migration
|
||||
// TODO: Remove after Clore migration ends ([REDACTED_TASK_KEY])
|
||||
private val cloreMigrationModel by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
|
|
@ -1275,6 +1286,29 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
|
||||
// endregion Clore migration
|
||||
|
||||
private fun createInitialRedesignState(): TokenDetailsUM {
|
||||
return TokenDetailsUM(
|
||||
topAppBarUM = TokenDetailsTopAppBarUM(
|
||||
title = stringReference(cryptoCurrency.name),
|
||||
subtitle = stringReference(cryptoCurrency.symbol),
|
||||
menuItems = persistentListOf(),
|
||||
),
|
||||
balanceBlockUM = TokenDetailsBalanceBlockUM.Loading(
|
||||
actionButtons = persistentListOf(),
|
||||
tokenBalanceTypeUM = TokenBalanceTypeUM.Single,
|
||||
currencyIconState = CurrencyIconState.Loading,
|
||||
),
|
||||
marketPriceBlockState = MarketPriceBlockState.Loading(currencySymbol = cryptoCurrency.symbol),
|
||||
stakingBlocksState = null,
|
||||
pullToRefreshConfig = PullToRefreshConfig(
|
||||
isRefreshing = false,
|
||||
onRefresh = {},
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
isMarketPriceAvailable = false,
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EXPRESS_STATUS_UPDATE_DELAY = 10_000L
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal sealed class TokenDetailsBalanceBlockUM {
|
||||
|
||||
abstract val actionButtons: ImmutableList<TangemButtonUM>
|
||||
abstract val tokenBalanceTypeUM: TokenBalanceTypeUM
|
||||
abstract val currencyIconState: CurrencyIconState
|
||||
|
||||
data class Loading(
|
||||
override val actionButtons: ImmutableList<TangemButtonUM>,
|
||||
override val tokenBalanceTypeUM: TokenBalanceTypeUM,
|
||||
override val currencyIconState: CurrencyIconState,
|
||||
) : TokenDetailsBalanceBlockUM()
|
||||
|
||||
data class Content(
|
||||
override val actionButtons: ImmutableList<TangemButtonUM>,
|
||||
override val tokenBalanceTypeUM: TokenBalanceTypeUM,
|
||||
override val currencyIconState: CurrencyIconState,
|
||||
val displayCryptoBalance: TextReference,
|
||||
val displayFiatBalance: TextReference,
|
||||
val isBalanceFlickering: Boolean,
|
||||
) : TokenDetailsBalanceBlockUM()
|
||||
|
||||
data class Error(
|
||||
override val actionButtons: ImmutableList<TangemButtonUM>,
|
||||
override val tokenBalanceTypeUM: TokenBalanceTypeUM,
|
||||
override val currencyIconState: CurrencyIconState,
|
||||
) : TokenDetailsBalanceBlockUM()
|
||||
|
||||
fun copyActionButtons(buttons: ImmutableList<TangemButtonUM>): TokenDetailsBalanceBlockUM {
|
||||
return when (this) {
|
||||
is Content -> this.copy(actionButtons = buttons)
|
||||
is Error -> this.copy(actionButtons = buttons)
|
||||
is Loading -> this.copy(actionButtons = buttons)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TokenBalanceTypeUM {
|
||||
|
||||
abstract val type: Type
|
||||
|
||||
data object Single : TokenBalanceTypeUM() {
|
||||
override val type = Type.ALL
|
||||
}
|
||||
|
||||
data class Multiple(
|
||||
override val type: Type,
|
||||
val availableTypes: ImmutableList<Type>,
|
||||
val onSelect: (Type) -> Unit,
|
||||
) : TokenBalanceTypeUM()
|
||||
|
||||
enum class Type {
|
||||
ALL,
|
||||
AVAILABLE,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Stable
|
||||
internal data class TokenDetailsUM(
|
||||
val topAppBarUM: TokenDetailsTopAppBarUM,
|
||||
val balanceBlockUM: TokenDetailsBalanceBlockUM,
|
||||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
val stakingBlocksState: StakingBlockUM?,
|
||||
val pullToRefreshConfig: PullToRefreshConfig,
|
||||
val isBalanceHidden: Boolean,
|
||||
val isMarketPriceAvailable: Boolean,
|
||||
)
|
||||
|
||||
internal data class TokenDetailsTopAppBarUM(
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference,
|
||||
val menuItems: ImmutableList<TextReference>,
|
||||
)
|
||||
|
|
@ -1,218 +1,30 @@
|
|||
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.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.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.bottomsheet.chooseaddress.ChooseAddressBottomSheet
|
||||
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
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.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.TokenDetailsBalanceBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs
|
||||
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.clore.CloreMigrationBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.clore.CloreMigrationBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import com.tangem.features.txhistory.entity.TxHistoryUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
// TODO: Split to blocks [REDACTED_JIRA]
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@Suppress("UnusedParameter")
|
||||
@Composable
|
||||
internal fun TokenDetailsScreen(
|
||||
state: TokenDetailsState,
|
||||
tokenDetailsUM: TokenDetailsUM,
|
||||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
txHistoryComponent: TxHistoryComponent,
|
||||
yieldSupplyComponent: YieldSupplyComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
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.txHistoryState.collectAsStateWithLifecycle()
|
||||
val dialogConfig = state.dialogConfig
|
||||
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 {
|
||||
TokenDetailsBalanceBlock(
|
||||
modifier = itemModifier,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
state = state.tokenBalanceBlockState,
|
||||
)
|
||||
}
|
||||
items(
|
||||
items = state.notifications,
|
||||
key = { it::class.java },
|
||||
contentType = { it.config::class.java },
|
||||
itemContent = {
|
||||
Notification(
|
||||
modifier = itemModifier.animateItem(),
|
||||
config = it.config,
|
||||
iconTint = when (it) {
|
||||
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 = {
|
||||
TokenStakingBlock(
|
||||
state = state.stakingBlocksState,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
yieldSupplyComponent.Content(modifier = itemModifier)
|
||||
}
|
||||
|
||||
expressTransactionsItems(
|
||||
expressTxs = state.expressTxsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryComponentState) }
|
||||
}
|
||||
}
|
||||
|
||||
if (dialogConfig != null) {
|
||||
TokenDetailsDialogs(dialogConfig = dialogConfig)
|
||||
}
|
||||
|
||||
state.bottomSheetConfig?.let { config ->
|
||||
when (config.content) {
|
||||
is ChooseAddressBottomSheetConfig -> {
|
||||
ChooseAddressBottomSheet(config = config)
|
||||
}
|
||||
is ExpressStatusBottomSheetConfig -> {
|
||||
ExpressStatusBottomSheet(config = config)
|
||||
}
|
||||
is CloreMigrationBottomSheetConfig -> {
|
||||
CloreMigrationBottomSheet(config = config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
TokenDetailsScreen(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = null,
|
||||
txHistoryComponent = object : TxHistoryComponent {
|
||||
override val txHistoryState: StateFlow<TxHistoryUM> = MutableStateFlow(
|
||||
value = TxHistoryUM.Empty(isBalanceHidden = false, onExploreClick = {}),
|
||||
)
|
||||
|
||||
override fun LazyListScope.txHistoryContent(listState: LazyListState, state: TxHistoryUM) = Unit
|
||||
},
|
||||
yieldSupplyComponent = object : YieldSupplyComponent {
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
}
|
||||
},
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = "Token Details Redesign",
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenDetailsScreenParameterProvider : CollectionPreviewParameterProvider<TokenDetailsState>(
|
||||
collection = listOf(
|
||||
TokenDetailsPreviewData.tokenDetailsState_1,
|
||||
TokenDetailsPreviewData.tokenDetailsState_2,
|
||||
TokenDetailsPreviewData.tokenDetailsState_3,
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
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.bottomsheet.chooseaddress.ChooseAddressBottomSheet
|
||||
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
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.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.TokenDetailsDialogs
|
||||
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.clore.CloreMigrationBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.clore.CloreMigrationBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlock
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import com.tangem.features.txhistory.entity.TxHistoryUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
// TODO: Split to blocks [REDACTED_JIRA]
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@Composable
|
||||
internal fun TokenDetailsScreenLegacy(
|
||||
state: TokenDetailsState,
|
||||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
txHistoryComponent: TxHistoryComponent,
|
||||
yieldSupplyComponent: YieldSupplyComponent,
|
||||
) {
|
||||
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.txHistoryState.collectAsStateWithLifecycle()
|
||||
val dialogConfig = state.dialogConfig
|
||||
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 = {
|
||||
TokenStakingBlock(
|
||||
state = state.stakingBlocksState,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
yieldSupplyComponent.Content(modifier = itemModifier)
|
||||
}
|
||||
|
||||
expressTransactionsItems(
|
||||
expressTxs = state.expressTxsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryComponentState) }
|
||||
}
|
||||
}
|
||||
|
||||
if (dialogConfig != null) {
|
||||
TokenDetailsDialogs(dialogConfig = dialogConfig)
|
||||
}
|
||||
|
||||
state.bottomSheetConfig?.let { config ->
|
||||
when (config.content) {
|
||||
is ChooseAddressBottomSheetConfig -> {
|
||||
ChooseAddressBottomSheet(config = config)
|
||||
}
|
||||
is ExpressStatusBottomSheetConfig -> {
|
||||
ExpressStatusBottomSheet(config = config)
|
||||
}
|
||||
is CloreMigrationBottomSheetConfig -> {
|
||||
CloreMigrationBottomSheet(config = config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 txHistoryState: StateFlow<TxHistoryUM> = MutableStateFlow(
|
||||
value = TxHistoryUM.Empty(isBalanceHidden = false, onExploreClick = {}),
|
||||
)
|
||||
|
||||
override fun LazyListScope.txHistoryContent(listState: LazyListState, state: TxHistoryUM) = Unit
|
||||
},
|
||||
yieldSupplyComponent = object : YieldSupplyComponent {
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenDetailsScreenParameterProvider : CollectionPreviewParameterProvider<TokenDetailsState>(
|
||||
collection = listOf(
|
||||
TokenDetailsPreviewData.tokenDetailsState_1,
|
||||
TokenDetailsPreviewData.tokenDetailsState_2,
|
||||
TokenDetailsPreviewData.tokenDetailsState_3,
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -39,7 +39,7 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
|
||||
@Suppress("DestructuringDeclarationWithTooManyEntries")
|
||||
@Composable
|
||||
internal fun TokenDetailsBalanceBlock(
|
||||
internal fun TokenDetailsBalanceBlockLegacy(
|
||||
state: TokenDetailsBalanceBlockState,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -264,7 +264,7 @@ private fun Preview_TokenDetailsBalanceBlock(
|
|||
@PreviewParameter(TokenDetailsBalanceBlockStateProvider::class) state: TokenDetailsBalanceBlockState,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenDetailsBalanceBlock(state = state, isBalanceHidden = false)
|
||||
TokenDetailsBalanceBlockLegacy(state = state, isBalanceHidden = false)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue