Updated on 2026-08-14
This commit is contained in:
parent
1006477fd7
commit
2d753e14af
30 changed files with 189 additions and 55 deletions
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.tokens.*
|
|||
import com.tangem.domain.tokens.repository.*
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.features.markets.MarketsFeatureToggles
|
||||
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
|
|
@ -230,6 +231,7 @@ internal object TokensDomainModule {
|
|||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
stakingFeatureToggles: StakingFeatureToggles,
|
||||
marketsFeatureToggles: MarketsFeatureToggles,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetCryptoCurrencyActionsUseCase {
|
||||
return GetCryptoCurrencyActionsUseCase(
|
||||
|
|
@ -241,6 +243,7 @@ internal object TokensDomainModule {
|
|||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
stakingFeatureToggles = stakingFeatureToggles,
|
||||
marketsFeatureToggles = marketsFeatureToggles,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ internal class ChildFactory @Inject constructor(
|
|||
params = MarketsTokenDetailsComponent.Params(
|
||||
token = route.token,
|
||||
appCurrency = route.appCurrency,
|
||||
showPortfolio = route.showPortfolio,
|
||||
),
|
||||
componentFactory = marketsTokenDetailsComponentFactory,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -271,5 +271,6 @@ sealed class AppRoute(val path: String) : Route {
|
|||
data class MarketsTokenDetails(
|
||||
val token: TokenMarketParams,
|
||||
val appCurrency: AppCurrency,
|
||||
) : AppRoute(path = "/markets_token_details/${token.id}")
|
||||
val showPortfolio: Boolean,
|
||||
) : AppRoute(path = "/markets_token_details/${token.id}/$showPortfolio")
|
||||
}
|
||||
|
|
@ -125,6 +125,8 @@ fun MarketChart(
|
|||
// Sometimes the chart is not drawn correctly (ex. in LazyLayout), so we need to force the redraw
|
||||
.drawBehind {
|
||||
state.markerFraction
|
||||
state.chartColor
|
||||
state.markerHighlightRightSide
|
||||
},
|
||||
chart = chart,
|
||||
modelProducer = state.modelProducer,
|
||||
|
|
|
|||
|
|
@ -22,10 +22,13 @@ import androidx.compose.ui.platform.LocalDensity
|
|||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.PrimarySmallButton
|
||||
import com.tangem.core.ui.components.buttons.SmallButtonConfig
|
||||
import com.tangem.core.ui.components.buttons.chip.Chip
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.valentinilk.shimmer.*
|
||||
|
|
@ -123,6 +126,22 @@ fun SmallButtonShimmer(
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shimmer for Chip
|
||||
* Height and min width will be set automatically
|
||||
*/
|
||||
@Composable
|
||||
fun ChipShimmer(modifier: Modifier = Modifier) {
|
||||
Chip(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(size = 100.dp))
|
||||
.shimmer(LocalTangemShimmer.current),
|
||||
text = TextReference.EMPTY,
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
internal val TangemShimmer: Shimmer
|
||||
@Composable
|
||||
get() = rememberShimmer(
|
||||
|
|
@ -195,6 +214,7 @@ private fun ShimmersPreview() {
|
|||
)
|
||||
SmallButtonShimmer(withIcon = true)
|
||||
SmallButtonShimmer(withIcon = false)
|
||||
ChipShimmer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
core/ui/src/main/res/drawable/ic_analytics_24.xml
Normal file
18
core/ui/src/main/res/drawable/ic_analytics_24.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M3,3V19C3,19.53 3.211,20.039 3.586,20.414C3.961,20.789 4.47,21 5,21H21"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#1E1E1E"/>
|
||||
<path
|
||||
android:pathData="M19,9L14,14L10,10L7,13"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#1E1E1E"/>
|
||||
</vector>
|
||||
|
|
@ -143,7 +143,6 @@ internal class DefaultQuotesRepository(
|
|||
block = { acc.add(rawCurrencyId) },
|
||||
)
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ data class TokenMarketParams(
|
|||
@Serializable
|
||||
data class Quotes(
|
||||
val currentPrice: SerializedBigDecimal,
|
||||
val h24Percent: SerializedBigDecimal,
|
||||
val h24Percent: SerializedBigDecimal?,
|
||||
val weekPercent: SerializedBigDecimal?,
|
||||
val monthPercent: SerializedBigDecimal?,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ dependencies {
|
|||
/** Project - Api */
|
||||
implementation(projects.features.send.api)
|
||||
implementation(projects.features.staking.api)
|
||||
implementation(projects.features.markets.api)
|
||||
|
||||
/** Project - Other */
|
||||
implementation(projects.core.utils)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.tokens.repository.NetworksRepository
|
|||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.markets.MarketsFeatureToggles
|
||||
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.isNullOrZero
|
||||
|
|
@ -33,6 +34,7 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val stakingFeatureToggles: StakingFeatureToggles,
|
||||
private val marketsFeatureToggles: MarketsFeatureToggles,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
|
|
@ -112,6 +114,12 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
val activeList = mutableListOf<TokenActionsState.ActionState>()
|
||||
val disabledList = mutableListOf<TokenActionsState.ActionState>()
|
||||
|
||||
// markets
|
||||
// not a custom token
|
||||
if (marketsFeatureToggles.isFeatureEnabled && cryptoCurrencyStatus.currency.id.rawCurrencyId != null) {
|
||||
activeList.add(TokenActionsState.ActionState.Analytics(ScenarioUnavailabilityReason.None))
|
||||
}
|
||||
|
||||
// copy address
|
||||
if (isAddressAvailable(cryptoCurrencyStatus.value.networkAddress)) {
|
||||
activeList.add(TokenActionsState.ActionState.CopyAddress(ScenarioUnavailabilityReason.None))
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ data class TokenActionsState(
|
|||
|
||||
data class Send(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
|
||||
data class Analytics(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
|
||||
data class HideToken(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,8 @@ import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
|
|||
import com.tangem.core.ui.event.EventEffect
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import com.tangem.core.ui.res.LocalSnackbarHostState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -369,6 +371,8 @@ private fun NetworksList(
|
|||
isEditable: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
|
||||
AnimatedVisibility(
|
||||
modifier = modifier,
|
||||
visible = networks is NetworksUM.Expanded,
|
||||
|
|
@ -403,7 +407,14 @@ private fun NetworksList(
|
|||
if (isEditable) {
|
||||
TangemSwitch(
|
||||
checked = network.isSelected,
|
||||
onCheckedChange = network.onSelectedStateChange,
|
||||
onCheckedChange = { checked ->
|
||||
if (checked) {
|
||||
hapticManager.perform(TangemHapticEffect.View.ToggleOn)
|
||||
} else {
|
||||
hapticManager.perform(TangemHapticEffect.View.ToggleOff)
|
||||
}
|
||||
network.onSelectedStateChange(checked)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ interface MarketsTokenDetailsComponent : ComposableContentComponent {
|
|||
data class Params(
|
||||
val token: TokenMarketParams,
|
||||
val appCurrency: AppCurrency,
|
||||
val showPortfolio: Boolean,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ dependencies {
|
|||
implementation(deps.compose.ui.utils)
|
||||
implementation(deps.lifecycle.compose)
|
||||
implementation(deps.androidx.activity.compose)
|
||||
implementation(deps.markdown.composeview)
|
||||
|
||||
/* DI */
|
||||
implementation(deps.hilt.android)
|
||||
|
|
|
|||
|
|
@ -33,17 +33,21 @@ internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
|
|||
|
||||
private val model: MarketsTokenDetailsModel = getOrCreateModel(params)
|
||||
|
||||
private val portfolioComponent = portfolioComponentFactory.create(
|
||||
context = child("my_portfolio"),
|
||||
params = MarketsPortfolioComponent.Params(params.token),
|
||||
)
|
||||
private val portfolioComponent: MarketsPortfolioComponent? = if (params.showPortfolio) {
|
||||
portfolioComponentFactory.create(
|
||||
context = child("my_portfolio"),
|
||||
params = MarketsPortfolioComponent.Params(params.token),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
init {
|
||||
componentScope.launch {
|
||||
model.networksState.collectLatest {
|
||||
when (it) {
|
||||
is TokenNetworksState.NetworksAvailable -> portfolioComponent.setTokenNetworks(it.networks)
|
||||
TokenNetworksState.NoNetworksAvailable -> portfolioComponent.setNoNetworksAvailable()
|
||||
is TokenNetworksState.NetworksAvailable -> portfolioComponent?.setTokenNetworks(it.networks)
|
||||
TokenNetworksState.NoNetworksAvailable -> portfolioComponent?.setNoNetworksAvailable()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
|
@ -79,10 +83,16 @@ internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
|
|||
backgroundColor = LocalMainBottomSheetColor.current.value,
|
||||
addTopBarStatusBarPadding = false,
|
||||
state = state,
|
||||
onBackClick = ::navigateBack,
|
||||
onBackClick = {
|
||||
if (bsState == BottomSheetState.EXPANDED) {
|
||||
navigateBack()
|
||||
}
|
||||
},
|
||||
onHeaderSizeChange = onHeaderSizeChange,
|
||||
portfolioBlock = { blockModifier ->
|
||||
portfolioComponent.Content(blockModifier)
|
||||
portfolioBlock = portfolioComponent?.let { component ->
|
||||
{ blockModifier ->
|
||||
component.Content(blockModifier)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -109,8 +119,10 @@ internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
|
|||
state = state,
|
||||
onBackClick = ::navigateBack,
|
||||
onHeaderSizeChange = {},
|
||||
portfolioBlock = { blockModifier ->
|
||||
portfolioComponent.Content(blockModifier)
|
||||
portfolioBlock = portfolioComponent?.let { component ->
|
||||
{ blockModifier ->
|
||||
component.Content(blockModifier)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import androidx.compose.runtime.Stable
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.common.ui.charts.state.MarketChartData
|
||||
import com.tangem.common.ui.charts.state.MarketChartDataProducer
|
||||
import com.tangem.common.ui.charts.state.MarketChartLook
|
||||
import com.tangem.common.ui.charts.state.sorted
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -135,15 +134,16 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
fiatCurrencySymbol = currentAppCurrency.value.symbol,
|
||||
),
|
||||
dateTimeText = resourceReference(R.string.common_today),
|
||||
priceChangePercentText = BigDecimalFormatter.formatPercent(
|
||||
percent = params.token.tokenQuotes.h24Percent,
|
||||
useAbsoluteValue = true,
|
||||
),
|
||||
priceChangePercentText = params.token.tokenQuotes.h24Percent?.let {
|
||||
BigDecimalFormatter.formatPercent(
|
||||
percent = it,
|
||||
useAbsoluteValue = true,
|
||||
)
|
||||
},
|
||||
priceChangeType = params.token.tokenQuotes.h24Percent.percentChangeType(),
|
||||
iconUrl = params.token.imageUrl,
|
||||
chartState = MarketsTokenDetailsUM.ChartState(
|
||||
dataProducer = chartDataProducer,
|
||||
chartLook = MarketChartLook(),
|
||||
onLoadRetryClick = ::onLoadRetryClicked,
|
||||
status = MarketsTokenDetailsUM.ChartState.Status.LOADING,
|
||||
onMarkerPointSelected = ::onMarkerPointSelected,
|
||||
|
|
@ -320,6 +320,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
currentQuotes.value = newInfo.quotes
|
||||
|
||||
val percent = newInfo.quotes.getPercentByInterval(interval = state.value.selectedInterval)
|
||||
|
||||
state.update {
|
||||
it.copy(
|
||||
priceText = newInfo.quotes.currentPrice.formatAsPrice(currentAppCurrency.value),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import androidx.compose.ui.platform.LocalDensity
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.tangem.common.ui.charts.state.MarketChartDataProducer
|
||||
import com.tangem.common.ui.charts.state.MarketChartLook
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||
|
|
@ -54,7 +53,7 @@ internal fun MarketsTokenDetailsContent(
|
|||
addTopBarStatusBarPadding: Boolean,
|
||||
onBackClick: () -> Unit,
|
||||
onHeaderSizeChange: (Dp) -> Unit,
|
||||
portfolioBlock: @Composable (Modifier) -> Unit,
|
||||
portfolioBlock: @Composable ((Modifier) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Content(
|
||||
|
|
@ -78,7 +77,7 @@ private fun Content(
|
|||
addTopBarStatusBarInsets: Boolean,
|
||||
onBackClick: () -> Unit,
|
||||
onHeaderSizeChange: (Dp) -> Unit,
|
||||
portfolioBlock: @Composable (Modifier) -> Unit,
|
||||
portfolioBlock: @Composable ((Modifier) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
|
|
@ -129,9 +128,7 @@ private fun Content(
|
|||
)
|
||||
}
|
||||
item { SpacerH32() }
|
||||
item(
|
||||
contentType = "chart",
|
||||
) {
|
||||
item("chart") {
|
||||
MarketTokenDetailsChart(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
backgroundColor = backgroundColor,
|
||||
|
|
@ -167,11 +164,13 @@ private fun Header(state: MarketsTokenDetailsUM, modifier: Modifier = Modifier)
|
|||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
PriceChangeInPercent(
|
||||
valueInPercent = state.priceChangePercentText,
|
||||
type = state.priceChangeType,
|
||||
textStyle = TangemTheme.typography.caption2,
|
||||
)
|
||||
if (state.priceChangePercentText != null) {
|
||||
PriceChangeInPercent(
|
||||
valueInPercent = state.priceChangePercentText,
|
||||
type = state.priceChangeType,
|
||||
textStyle = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
SpacerW4()
|
||||
|
|
@ -290,7 +289,6 @@ private fun Preview() {
|
|||
priceChangeType = PriceChangeType.UP,
|
||||
chartState = MarketsTokenDetailsUM.ChartState(
|
||||
dataProducer = MarketChartDataProducer.build { },
|
||||
chartLook = MarketChartLook(),
|
||||
onLoadRetryClick = {},
|
||||
status = MarketsTokenDetailsUM.ChartState.Status.LOADING,
|
||||
onMarkerPointSelected = { _, _ -> },
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
|
|
@ -17,6 +16,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetTitle
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.markets.details.impl.ui.state.InfoBottomSheetContent
|
||||
import dev.jeziellago.compose.markdowntext.MarkdownText
|
||||
|
||||
@Composable
|
||||
internal fun InfoBottomSheet(config: TangemBottomSheetConfig) {
|
||||
|
|
@ -35,10 +35,14 @@ internal fun InfoBottomSheet(config: TangemBottomSheetConfig) {
|
|||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = TangemTheme.dimens.spacing28),
|
||||
) {
|
||||
Text(
|
||||
text = it.body.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
MarkdownText(
|
||||
markdown = it.body.resolveReference(),
|
||||
disableLinkMovementMethod = true,
|
||||
linkifyMask = 0,
|
||||
syntaxHighlightColor = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body2.copy(
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
),
|
||||
)
|
||||
SpacerH(bottomBarHeight)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.components.SmallButtonShimmer
|
||||
import com.tangem.core.ui.components.ChipShimmer
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.block.information.InformationBlock
|
||||
import com.tangem.core.ui.components.buttons.chip.Chip
|
||||
|
|
@ -145,9 +145,8 @@ private fun SubBlockPlaceholder(modifier: Modifier = Modifier, lastBlock: Boolea
|
|||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
repeat(times = 3) {
|
||||
SmallButtonShimmer(
|
||||
ChipShimmer(
|
||||
modifier = Modifier.weight(1f),
|
||||
withIcon = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ internal fun PricePerformanceBlockPlaceholder(modifier: Modifier = Modifier) {
|
|||
},
|
||||
content = {
|
||||
Column(
|
||||
modifier = modifier.padding(vertical = TangemTheme.dimens.spacing8),
|
||||
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Row(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.features.markets.tokenlist.impl.ui.components.UnableToLoadData
|
|||
|
||||
internal fun LazyListScope.tokenMarketDetailsBody(
|
||||
state: MarketsTokenDetailsUM.Body,
|
||||
portfolioBlock: @Composable (Modifier) -> Unit,
|
||||
portfolioBlock: @Composable ((Modifier) -> Unit)?,
|
||||
) {
|
||||
when (state) {
|
||||
MarketsTokenDetailsUM.Body.Loading -> {
|
||||
|
|
@ -21,8 +21,10 @@ internal fun LazyListScope.tokenMarketDetailsBody(
|
|||
DescriptionPlaceholder(modifier = Modifier.blockPaddings())
|
||||
}
|
||||
|
||||
item(key = "portfolio") {
|
||||
portfolioBlock(Modifier.blockPaddings())
|
||||
if (portfolioBlock != null) {
|
||||
item(key = "portfolio") {
|
||||
portfolioBlock(Modifier.blockPaddings())
|
||||
}
|
||||
}
|
||||
|
||||
loadingInfoBlocks()
|
||||
|
|
@ -32,8 +34,10 @@ internal fun LazyListScope.tokenMarketDetailsBody(
|
|||
description(state.description)
|
||||
}
|
||||
|
||||
item(key = "portfolio") {
|
||||
portfolioBlock(Modifier.blockPaddings())
|
||||
if (portfolioBlock != null) {
|
||||
item(key = "portfolio") {
|
||||
portfolioBlock(Modifier.blockPaddings())
|
||||
}
|
||||
}
|
||||
|
||||
infoBlocksList(state.infoBlocks)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.features.markets.details.impl.ui.state
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.charts.state.MarketChartDataProducer
|
||||
import com.tangem.common.ui.charts.state.MarketChartLook
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
|
|
@ -15,7 +14,7 @@ internal data class MarketsTokenDetailsUM(
|
|||
val priceText: String,
|
||||
val iconUrl: String?,
|
||||
val dateTimeText: TextReference,
|
||||
val priceChangePercentText: String,
|
||||
val priceChangePercentText: String?,
|
||||
val priceChangeType: PriceChangeType,
|
||||
val selectedInterval: PriceChangeInterval,
|
||||
val markerSet: Boolean,
|
||||
|
|
@ -29,7 +28,6 @@ internal data class MarketsTokenDetailsUM(
|
|||
data class ChartState(
|
||||
val status: Status,
|
||||
val dataProducer: MarketChartDataProducer,
|
||||
val chartLook: MarketChartLook,
|
||||
val onLoadRetryClick: () -> Unit,
|
||||
val onMarkerPointSelected: (time: BigDecimal?, price: BigDecimal?) -> Unit,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
|
|||
params = MarketsTokenDetailsComponent.Params(
|
||||
token = token.toSerializableParam(),
|
||||
appCurrency = appCurrency,
|
||||
showPortfolio = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -182,13 +182,12 @@ internal class TokenActionsHandler @AssistedInject constructor(
|
|||
is TokenActionsState.ActionState.HideToken -> null
|
||||
is TokenActionsState.ActionState.Receive -> TokenActionsBSContentUM.Action.Receive
|
||||
is TokenActionsState.ActionState.Sell -> TokenActionsBSContentUM.Action.Sell
|
||||
is TokenActionsState.ActionState.Send -> {
|
||||
TokenActionsBSContentUM.Action.Send.takeIf {
|
||||
cryptoCurrencyData.status.value.amount.isNullOrZero().not()
|
||||
}
|
||||
is TokenActionsState.ActionState.Send -> TokenActionsBSContentUM.Action.Send.takeIf {
|
||||
cryptoCurrencyData.status.value.amount.isNullOrZero().not()
|
||||
}
|
||||
is TokenActionsState.ActionState.Stake -> TokenActionsBSContentUM.Action.Stake
|
||||
is TokenActionsState.ActionState.Swap -> TokenActionsBSContentUM.Action.Exchange
|
||||
is TokenActionsState.ActionState.Analytics -> null
|
||||
}
|
||||
.takeIf { this.unavailabilityReason == ScenarioUnavailabilityReason.None }
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import com.tangem.core.ui.components.currency.icon.CoinIcon
|
|||
import com.tangem.core.ui.components.rows.ArrowRow
|
||||
import com.tangem.core.ui.components.rows.BlockchainRow
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
|
@ -168,6 +170,8 @@ private fun ContinueButton(
|
|||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun NetworkSelection(state: SelectNetworkUM, modifier: Modifier = Modifier) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
|
||||
InformationBlock(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
|
|
@ -229,7 +233,15 @@ private fun NetworkSelection(state: SelectNetworkUM, modifier: Modifier = Modifi
|
|||
} else {
|
||||
TangemTheme.colors.icon.inactive
|
||||
},
|
||||
onCheckedChange = { state.onNetworkSwitchClick(network, it) },
|
||||
onCheckedChange = { checked ->
|
||||
if (checked) {
|
||||
hapticManager.perform(TangemHapticEffect.View.ToggleOn)
|
||||
} else {
|
||||
hapticManager.perform(TangemHapticEffect.View.ToggleOff)
|
||||
}
|
||||
|
||||
state.onNetworkSwitchClick(network, checked)
|
||||
},
|
||||
enabled = network.isEnabled,
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ internal class TokenMarketBlockModel @Inject constructor(
|
|||
AppRoute.MarketsTokenDetails(
|
||||
token = tokenParam,
|
||||
appCurrency = currentAppCurrency.value,
|
||||
showPortfolio = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ dependencies {
|
|||
implementation(projects.domain.analytics)
|
||||
implementation(projects.domain.visa)
|
||||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.markets.models)
|
||||
|
||||
//TODO: Create api/impl modules for onboarding [REDACTED_JIRA]
|
||||
implementation(projects.features.onboarding)
|
||||
|
|
|
|||
|
|
@ -95,6 +95,11 @@ internal class MultiWalletCurrencyActionsConverter(
|
|||
icon = R.drawable.ic_hide_24
|
||||
action = { clickIntents.onHideTokensClick(cryptoCurrencyStatus) }
|
||||
}
|
||||
is TokenActionsState.ActionState.Analytics -> {
|
||||
title = resourceReference(R.string.common_analytics)
|
||||
icon = R.drawable.ic_analytics_24
|
||||
action = { clickIntents.onAnalyticsClick(cryptoCurrencyStatus) }
|
||||
}
|
||||
}
|
||||
|
||||
return TokenActionButtonConfig(
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.extenstions.unwrap
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.tokens.*
|
||||
|
|
@ -48,6 +49,7 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
interface WalletCurrencyActionsClickIntents {
|
||||
|
|
@ -77,6 +79,8 @@ interface WalletCurrencyActionsClickIntents {
|
|||
fun onPerformHideToken(cryptoCurrencyStatus: CryptoCurrencyStatus)
|
||||
|
||||
fun onExploreClick()
|
||||
|
||||
fun onAnalyticsClick(cryptoCurrencyStatus: CryptoCurrencyStatus)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
|
|
@ -378,6 +382,31 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
showErrorIfDemoModeOrElse(action = ::openExplorer)
|
||||
}
|
||||
|
||||
override fun onAnalyticsClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
viewModelScope.launch {
|
||||
val rawId = cryptoCurrencyStatus.currency.id.rawCurrencyId ?: return@launch
|
||||
|
||||
appRouter.push(
|
||||
AppRoute.MarketsTokenDetails(
|
||||
TokenMarketParams(
|
||||
id = rawId,
|
||||
name = cryptoCurrencyStatus.currency.name,
|
||||
symbol = cryptoCurrencyStatus.currency.symbol,
|
||||
tokenQuotes = TokenMarketParams.Quotes(
|
||||
currentPrice = cryptoCurrencyStatus.value.fiatRate ?: BigDecimal.ZERO,
|
||||
h24Percent = cryptoCurrencyStatus.value.priceChange,
|
||||
weekPercent = null,
|
||||
monthPercent = null,
|
||||
),
|
||||
imageUrl = cryptoCurrencyStatus.currency.iconUrl,
|
||||
),
|
||||
appCurrency = getSelectedAppCurrencyUseCase.unwrap(),
|
||||
showPortfolio = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStakeClick(cryptoCurrencyStatus: CryptoCurrencyStatus, yield: Yield?) {
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWallet.walletId))
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ leakcanary = "2.13"
|
|||
decompose = "2.2.2"
|
||||
room = "2.6.1"
|
||||
markdown = "0.7.2"
|
||||
markdownComposeView = "0.5.4"
|
||||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
|
|
@ -270,4 +271,5 @@ room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
|
|||
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
|
||||
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
|
||||
markdown = { module = "org.jetbrains:markdown", version.ref = "markdown" }
|
||||
markdown-composeview = { module = "com.github.jeziellago:compose-markdown", version.ref = "markdownComposeView" }
|
||||
# endregion Other
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue