diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 2d1d56553e..eadaa40d6e 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -908,9 +908,11 @@
- %d asset
- %d assets
+ No amount
on tokens
No data
Total value
Can’t load data
+ You don’t have any tokens with amount
Top holding %s
About coin
To buy, exchange, or receive this asset, add it to your portfolio
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/DefaultForYouComponent.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/DefaultForYouComponent.kt
index 2c33e64590..9a244d74e3 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/DefaultForYouComponent.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/DefaultForYouComponent.kt
@@ -69,7 +69,14 @@ internal class DefaultForYouComponent @AssistedInject constructor(
childFactory = { config, componentContext ->
when (config) {
ForYouBottomSheetConfig.AddToPortfolio -> portfolioSelectorChild(componentContext)
- is ForYouBottomSheetConfig.ManageFunds -> manageFundsChild(config, componentContext)
+ is ForYouBottomSheetConfig.ManageFunds -> manageFundsChild(
+ componentContext = componentContext,
+ launchMode = ManageFundsComponent.LaunchMode.FilteredByRawId(config.rawCurrencyId),
+ )
+ is ForYouBottomSheetConfig.AddFunds -> manageFundsChild(
+ componentContext = componentContext,
+ launchMode = ManageFundsComponent.LaunchMode.ChooseToken(config.userWalletId),
+ )
}
},
)
@@ -129,12 +136,12 @@ internal class DefaultForYouComponent @AssistedInject constructor(
)
private fun manageFundsChild(
- config: ForYouBottomSheetConfig.ManageFunds,
+ launchMode: ManageFundsComponent.LaunchMode,
componentContext: ComponentContext,
): ComposableBottomSheetComponent = manageFundsComponentFactory.create(
context = childByContext(componentContext),
params = ManageFundsComponent.Params(
- launchMode = ManageFundsComponent.LaunchMode.FilteredByRawId(config.rawCurrencyId),
+ launchMode = launchMode,
onDismiss = { model.bottomSheetNavigation.dismiss() },
),
)
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/MarketChart.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/MarketChart.kt
index 793cb72e7b..27a7491559 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/MarketChart.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/MarketChart.kt
@@ -16,6 +16,7 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
+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
@@ -51,13 +52,16 @@ internal fun MarketChart(marketChart: MarketChartUM, modifier: Modifier = Modifi
Column(modifier = Modifier.fillMaxWidth()) {
DonutChartBlock(marketChart.donutChart, cardBoundsInWindow)
Spacer(modifier = Modifier.height(16.dp))
- if (marketChart is MarketChartUM.Loaded) {
- TopHoldingBlock(
- assetCount = marketChart.assetCount,
- topHoldingPercent = marketChart.topHoldingPercent,
- )
- } else {
- CantLoadDataBlock()
+ when (marketChart) {
+ is MarketChartUM.Loaded -> {
+ TopHoldingBlock(
+ assetCount = marketChart.assetCount,
+ topHoldingPercent = marketChart.topHoldingPercent,
+ )
+ }
+ is MarketChartUM.NoData -> {
+ CantLoadDataBlock(text = marketChart.title)
+ }
}
Spacer(modifier = Modifier.height(16.dp))
@@ -113,36 +117,40 @@ private fun ColumnScope.DonutChartBlock(donutChartUM: DonutChartUM, cardBoundsIn
},
segments = segments,
) {
- if (donutChartUM is DonutChartUM.Loaded) {
- Text(
- text = donutChartUM.totalAmount,
- color = TangemTheme.colors3.text.primary,
- style = TangemTheme.typography3.body.medium,
- maxLines = 1,
- autoSize = TextAutoSize.StepBased(
- minFontSize = 8.sp,
- maxFontSize = TangemTheme.typography3.body.medium.fontSize,
- ),
- )
- Text(
- text = stringResourceSafe(R.string.market_chart_bubble_total_value),
- color = TangemTheme.colors3.text.secondary,
- style = TangemTheme.typography3.caption.medium,
- maxLines = 1,
- autoSize = TextAutoSize.StepBased(
- maxFontSize = TangemTheme.typography3.caption.medium.fontSize,
- ),
- )
- } else {
- Text(
- text = stringResourceSafe(R.string.market_chart_bubble_no_data),
- color = TangemTheme.colors3.text.secondary,
- style = TangemTheme.typography3.body.medium,
- maxLines = 1,
- autoSize = TextAutoSize.StepBased(
- maxFontSize = TangemTheme.typography3.caption.medium.fontSize,
- ),
- )
+ when (donutChartUM) {
+ is DonutChartUM.Loaded -> {
+ Text(
+ text = donutChartUM.totalAmount,
+ color = TangemTheme.colors3.text.primary,
+ style = TangemTheme.typography3.body.medium,
+ maxLines = 1,
+ autoSize = TextAutoSize.StepBased(
+ minFontSize = 8.sp,
+ maxFontSize = TangemTheme.typography3.body.medium.fontSize,
+ ),
+ )
+ Text(
+ text = stringResourceSafe(R.string.market_chart_bubble_total_value),
+ color = TangemTheme.colors3.text.secondary,
+ style = TangemTheme.typography3.caption.medium,
+ maxLines = 1,
+ autoSize = TextAutoSize.StepBased(
+ maxFontSize = TangemTheme.typography3.caption.medium.fontSize,
+ ),
+ )
+ }
+ is DonutChartUM.NoData -> {
+ Text(
+ text = donutChartUM.title.resolveReference(),
+ color = TangemTheme.colors3.text.secondary,
+ style = TangemTheme.typography3.body.medium,
+ maxLines = 2,
+ textAlign = TextAlign.Center,
+ autoSize = TextAutoSize.StepBased(
+ maxFontSize = TangemTheme.typography3.caption.medium.fontSize,
+ ),
+ )
+ }
}
}
@@ -233,10 +241,10 @@ private fun ColumnScope.TopHoldingBlock(assetCount: Int, topHoldingPercent: Text
}
@Composable
-private fun ColumnScope.CantLoadDataBlock() {
+private fun ColumnScope.CantLoadDataBlock(text: TextReference) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
- text = stringResourceSafe(R.string.market_chart_can_not_load_data),
+ text = text.resolveReference(),
color = TangemTheme.colors3.text.secondary,
style = TangemTheme.typography3.heading.small,
)
@@ -306,7 +314,10 @@ private fun previewMarketChartState(scenario: MarketChartPreviewScenario): Marke
),
),
)
- MarketChartPreviewScenario.NO_DATA -> MarketChartUM.NoData
+ MarketChartPreviewScenario.NO_DATA -> MarketChartUM.NoData(
+ title = resourceReference(R.string.market_chart_can_not_load_data),
+ donutText = resourceReference(R.string.market_chart_bubble_no_data),
+ )
}
@Suppress("MagicNumber")
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/state/MarketChartUM.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/state/MarketChartUM.kt
index 7440dda859..e6f7d4367b 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/state/MarketChartUM.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/components/state/MarketChartUM.kt
@@ -21,8 +21,11 @@ internal sealed class MarketChartUM(
val assetCount: Int = donutChart.donutSegmentList.size
}
- data object NoData : MarketChartUM(
- donutChart = DonutChartUM.NoData,
+ data class NoData(
+ val title: TextReference,
+ private val donutText: TextReference,
+ ) : MarketChartUM(
+ donutChart = DonutChartUM.NoData(title = donutText),
aiInsight = AiInsightUM.Hide,
)
}
@@ -36,7 +39,9 @@ internal sealed class DonutChartUM(
override val donutSegmentList: ImmutableList,
) : DonutChartUM(donutSegmentList = donutSegmentList)
- data object NoData : DonutChartUM(donutSegmentList = persistentListOf())
+ data class NoData(
+ val title: TextReference,
+ ) : DonutChartUM(donutSegmentList = persistentListOf())
}
@Immutable
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouBottomSheetConfig.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouBottomSheetConfig.kt
index 1b798d9b26..d90245eba6 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouBottomSheetConfig.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouBottomSheetConfig.kt
@@ -1,6 +1,7 @@
package com.tangem.features.foryou.impl.entity
import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.wallet.UserWalletId
internal sealed interface ForYouBottomSheetConfig {
@@ -9,4 +10,8 @@ internal sealed interface ForYouBottomSheetConfig {
data class ManageFunds(
val rawCurrencyId: CryptoCurrency.RawID,
) : ForYouBottomSheetConfig
+
+ data class AddFunds(
+ val userWalletId: UserWalletId,
+ ) : ForYouBottomSheetConfig
}
\ No newline at end of file
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouUM.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouUM.kt
index de0075f610..ed743bdb3d 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouUM.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/entity/ForYouUM.kt
@@ -31,6 +31,7 @@ internal sealed interface PortfolioReviewUM {
data class Content(
override val tokenList: ImmutableList,
override val marketChartUM: MarketChartUM,
+ val onAddFundsClick: (() -> Unit)?,
) : PortfolioReviewUM
}
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/ForYouModel.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/ForYouModel.kt
index 9c920731d9..08132681be 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/ForYouModel.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/ForYouModel.kt
@@ -16,6 +16,7 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.ds.tabs.TangemSegmentUM
import com.tangem.core.ui.ds.tabs.TangemSegmentedPickerUM
+import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@@ -32,6 +33,7 @@ import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioManager
import com.tangem.features.foryou.ForYouComponent
+import com.tangem.features.foryou.impl.R
import com.tangem.features.foryou.impl.components.state.MarketChartUM
import com.tangem.features.foryou.impl.entity.*
import com.tangem.features.foryou.impl.model.converter.TOP_EARN_TOKENS_BATCH_SIZE
@@ -106,7 +108,10 @@ internal class ForYouModel @Inject constructor(
),
onPeriodClick = ::onPeriodClick,
portfolioReviewUM = PortfolioReviewUM.Loading(
- marketChartUM = MarketChartUM.NoData,
+ marketChartUM = MarketChartUM.NoData(
+ title = resourceReference(R.string.market_chart_can_not_load_data),
+ donutText = resourceReference(R.string.market_chart_bubble_no_data),
+ ),
tokenList = buildList {
repeat(4) { index ->
add(
@@ -154,6 +159,7 @@ internal class ForYouModel @Inject constructor(
expandedAssetIds = expandedPortfolioReview,
expandClick = ::onExpandPortfolioReviewClick,
onTokenClick = ::onPortfolioReviewTokenClick,
+ onAddFundsClick = ::onAddFundsClick,
).convert(accountStatusList)
val earnOpportunitiesUM = ForYouEarnOpportunitiesConverter(
@@ -363,4 +369,8 @@ internal class ForYouModel @Inject constructor(
},
)
}
+
+ private fun onAddFundsClick(userWalletId: UserWalletId) {
+ bottomSheetNavigation.activate(ForYouBottomSheetConfig.AddFunds(userWalletId))
+ }
}
\ No newline at end of file
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverter.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverter.kt
index 6fd651133f..514e95dcc3 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverter.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverter.kt
@@ -15,8 +15,10 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.features.foryou.impl.R
+import com.tangem.features.foryou.impl.components.state.MarketChartUM
import com.tangem.features.foryou.impl.entity.ForYouTokenListItemUM
import com.tangem.features.foryou.impl.entity.PortfolioReviewUM
+import com.tangem.features.foryou.impl.model.converter.FOR_YOU_TOP_EARN_TOKENS_COUNT
import com.tangem.features.foryou.impl.model.converter.forYouGroupKey
import com.tangem.features.foryou.impl.model.converter.forYouPlaceholderBadge
import com.tangem.features.foryou.impl.model.converter.toForYouPercent
@@ -42,6 +44,7 @@ internal class ForYouPortfolioReviewConverter(
private val expandedAssetIds: Set,
private val expandClick: (assetId: String) -> Unit,
private val onTokenClick: (UserWalletId, CryptoCurrency) -> Unit,
+ private val onAddFundsClick: (UserWalletId) -> Unit,
) : Converter {
private val iconConverter = CryptoCurrencyToIconStateConverter()
@@ -51,6 +54,26 @@ internal class ForYouPortfolioReviewConverter(
val loadedBalance = value?.totalFiatBalance as? TotalFiatBalance.Loaded
val totalFiatBalance = loadedBalance?.amount.orZero()
+ if (currencies.all { it.value.fiatAmount?.isZero() == true }) {
+ return PortfolioReviewUM.Content(
+ tokenList = currencies.take(FOR_YOU_TOP_EARN_TOKENS_COUNT)
+ .groupBy { it.forYouGroupKey() }
+ .map { (assetId, currencies) ->
+ createListItem(
+ userWalletId = value?.userWalletId,
+ assetId = assetId,
+ currencies = currencies,
+ totalFiatBalance = totalFiatBalance,
+ )
+ }.toPersistentList(),
+ marketChartUM = MarketChartUM.NoData(
+ title = resourceReference(R.string.market_chart_no_amount),
+ donutText = resourceReference(R.string.market_chart_bubble_no_amount),
+ ),
+ onAddFundsClick = { value?.userWalletId?.let(onAddFundsClick) },
+ )
+ }
+
// Drop only assets we positively know are empty — a resolved, priced zero fiat balance. Currencies
// whose fiat we couldn't determine (unreachable / no-address / no-quote / still-loading — i.e. any
// non-content status, which all carry a null fiatAmount) are kept so the converter can still render
@@ -95,6 +118,7 @@ internal class ForYouPortfolioReviewConverter(
return PortfolioReviewUM.Content(
tokenList = tokenList,
marketChartUM = marketChartUM,
+ onAddFundsClick = null,
)
}
@@ -127,7 +151,7 @@ internal class ForYouPortfolioReviewConverter(
networkCount = networkGroups.size,
totalFiatBalance = totalFiatBalance,
),
- tokenList = networkGroups.map(rowConverter::convertNetworkGroup).toPersistentList(),
+ tokenList = networkGroups.map(rowConverter::convert).toPersistentList(),
isExpanded = assetId in expandedAssetIds,
isExpandable = true,
)
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewMarketChartConverter.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewMarketChartConverter.kt
index c727d3de6e..b784871933 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewMarketChartConverter.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewMarketChartConverter.kt
@@ -1,5 +1,6 @@
package com.tangem.features.foryou.impl.model.converter.portfolioReview
+import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
@@ -7,6 +8,7 @@ import com.tangem.core.ui.format.bigdecimal.percent
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.currency.CryptoCurrencyStatus
+import com.tangem.features.foryou.impl.R
import com.tangem.features.foryou.impl.components.state.AiInsightUM
import com.tangem.features.foryou.impl.components.state.DonutChartUM
import com.tangem.features.foryou.impl.components.state.DonutSegmentColor
@@ -54,7 +56,10 @@ internal class ForYouPortfolioReviewMarketChartConverter(
TotalFiatBalance.Loading,
TotalFiatBalance.Failed,
null,
- -> MarketChartUM.NoData
+ -> MarketChartUM.NoData(
+ title = resourceReference(R.string.market_chart_can_not_load_data),
+ donutText = resourceReference(R.string.market_chart_bubble_no_data),
+ )
}
}
}
\ No newline at end of file
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverter.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverter.kt
index 41a34e5d3a..c1b705b473 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverter.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverter.kt
@@ -20,6 +20,7 @@ import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.features.foryou.impl.model.converter.forYouPlaceholderBadge
import com.tangem.features.foryou.impl.model.converter.toForYouPercent
import com.tangem.utils.StringsSigns
+import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.orZero
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@@ -47,21 +48,20 @@ internal class ForYouPortfolioReviewTokenRowConverter(
private val userWalletId: UserWalletId?,
private val totalFiatBalance: BigDecimal,
private val onTokenClick: (UserWalletId, CryptoCurrency) -> Unit,
-) {
+) : Converter, TangemTokenRowUM> {
private val iconConverter = CryptoCurrencyToIconStateConverter()
- /** Builds one row for all [statuses] of a single asset on the same network. */
- fun convertNetworkGroup(statuses: List): TangemTokenRowUM {
- val representative = statuses.first()
- if (statuses.all { it.value is CryptoCurrencyStatus.Loading }) {
+ override fun convert(value: List): TangemTokenRowUM {
+ val representative = value.first()
+ if (value.all { it.value is CryptoCurrencyStatus.Loading }) {
return TangemTokenRowUM.Loading(id = representative.currency.id.value)
}
val currency = representative.currency
- val cryptoAmount = statuses.sumOf { it.value.amount.orZero() }
- val fiatAmount = statuses.sumOf { it.value.fiatAmount.orZero() }
- val state = statuses.classify()
+ val cryptoAmount = value.sumOf { it.value.amount.orZero() }
+ val fiatAmount = value.sumOf { it.value.fiatAmount.orZero() }
+ val state = value.classify()
return TangemTokenRowUM.Content(
id = currency.id.value,
@@ -78,7 +78,7 @@ internal class ForYouPortfolioReviewTokenRowConverter(
/**
* Maps the aggregate status of [statuses] onto a row's top/bottom end content, rendering the given
* pre-summed [fiatAmount]. Reflects the same cache-flicker / could-not-refresh / no-address /
- * unreachable treatment as [convertNetworkGroup], so the asset-level row surfaces the combined status
+ * unreachable treatment as [convert], so the asset-level row surfaces the combined status
* of its holdings — analogous to how `AccountCryptoPortfolioItemStateConverter` reflects a
* `TotalFiatBalance`'s status on the account row.
*
@@ -158,7 +158,7 @@ internal class ForYouPortfolioReviewTokenRowConverter(
/** Bottom-end: percentage share for resolved states, no-address / unreachable treatment otherwise. */
private fun toRowBottomEnd(state: RowState, fiatAmount: BigDecimal): TangemTokenRowUM.EndContentUM = when (state) {
is RowState.Normal -> TangemTokenRowUM.EndContentUM.Content(
- text = stringReference(fiatAmount.toForYouPercent(totalFiatBalance).format { percent() }),
+ text = stringReference(fiatAmount.toForYouPercent(totalFiatBalance).orZero().format { percent() }),
isFlickering = state.isFlickering,
)
RowState.NoAddress -> attentionEndContent(R.string.common_no_address)
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouContent.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouContent.kt
index 63a964717d..cc4c2af243 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouContent.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouContent.kt
@@ -58,7 +58,11 @@ internal fun ForYouContent(
.drawBehind { drawRect(background.value) },
) {
promoBannersBlockComponent.ContentWithPadding(
- modifier = Modifier.padding(top = 12.dp),
+ modifier = Modifier
+ .padding(top = 12.dp)
+ .conditional(forYouUM.notifications.isEmpty()) {
+ padding(bottom = 48.dp)
+ },
walletId = null,
horizontalItemPadding = 16.dp,
)
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouPortfolioReview.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouPortfolioReview.kt
index e6b07656e9..9624f1f01e 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouPortfolioReview.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/ForYouPortfolioReview.kt
@@ -13,12 +13,13 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.ds.image.TangemIconUM
-import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.ds.tabs.TangemSegmentUM
import com.tangem.core.ui.ds.tabs.TangemSegmentedPicker
import com.tangem.core.ui.ds.tabs.TangemSegmentedPickerUM
import com.tangem.core.ui.ds2.badge.TangemBadge
+import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.shimmers.TangemShimmer
+import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
@@ -27,13 +28,10 @@ import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_chevron_down_16
import com.tangem.features.foryou.impl.R
import com.tangem.features.foryou.impl.components.MarketChart
-import com.tangem.features.foryou.impl.components.state.MarketChartUM
-import com.tangem.features.foryou.impl.entity.ForYouTokenListItemUM
import com.tangem.features.foryou.impl.entity.PortfolioReviewUM
import com.tangem.features.foryou.impl.ui.components.ForYouPortfolioTokenList
import com.tangem.features.foryou.impl.ui.preview.ForYouPortfolioReviewPreviewData
import kotlinx.collections.immutable.persistentListOf
-import kotlinx.collections.immutable.toPersistentList
@Composable
internal fun ForYouPortfolioReview(
@@ -84,6 +82,18 @@ internal fun ForYouPortfolioReview(
}
ForYouPortfolioTokenList(tokenList = portfolioReviewUM.tokenList)
+
+ if (portfolioReviewUM is PortfolioReviewUM.Content && portfolioReviewUM.onAddFundsClick != null) {
+ TangemButton(
+ text = resourceReference(R.string.common_add_funds),
+ onClick = portfolioReviewUM.onAddFundsClick,
+ variant = TangemButton.Variant.Secondary,
+ size = TangemButton.Size.X9,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp),
+ )
+ }
}
}
@@ -117,23 +127,8 @@ private class ForYouPortfolioReviewPreviewProvider : PreviewParameterProvider
get() = sequenceOf(
ForYouPortfolioReviewPreviewData.reviewContent,
- PortfolioReviewUM.Loading(
- marketChartUM = MarketChartUM.NoData,
- tokenList = buildList {
- repeat(4) { index ->
- add(
- ForYouTokenListItemUM(
- tokenRowUM = TangemTokenRowUM.Loading(
- id = index.toString(),
- ),
- tokenList = persistentListOf(),
- isExpanded = false,
- isExpandable = false,
- ),
- )
- }
- }.toPersistentList(),
- ),
+ ForYouPortfolioReviewPreviewData.loadingState,
+ ForYouPortfolioReviewPreviewData.zeroPortfolioState,
)
}
// endregion
\ No newline at end of file
diff --git a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/preview/ForYouPortfolioReviewPreviewData.kt b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/preview/ForYouPortfolioReviewPreviewData.kt
index 75aea81cde..69a5b25e33 100644
--- a/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/preview/ForYouPortfolioReviewPreviewData.kt
+++ b/features/for-you/impl/src/main/java/com/tangem/features/foryou/impl/ui/preview/ForYouPortfolioReviewPreviewData.kt
@@ -7,7 +7,9 @@ import com.tangem.core.ui.ds.badge.TangemBadgeType
import com.tangem.core.ui.ds.badge.TangemBadgeUM
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
+import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
+import com.tangem.features.foryou.impl.R
import com.tangem.features.foryou.impl.components.state.DonutChartUM
import com.tangem.features.foryou.impl.components.state.DonutSegmentColor
import com.tangem.features.foryou.impl.components.state.DonutSegmentUM
@@ -16,6 +18,7 @@ import com.tangem.features.foryou.impl.entity.ForYouTokenListItemUM
import com.tangem.features.foryou.impl.entity.PortfolioReviewUM
import com.tangem.utils.StringsSigns.DOT
import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toPersistentList
import java.math.BigDecimal
internal object ForYouPortfolioReviewPreviewData {
@@ -151,5 +154,70 @@ internal object ForYouPortfolioReviewPreviewData {
isExpandable = false,
),
),
+ onAddFundsClick = null,
+ )
+
+ val loadingState = PortfolioReviewUM.Loading(
+ marketChartUM = MarketChartUM.NoData(
+ title = resourceReference(R.string.market_chart_can_not_load_data),
+ donutText = resourceReference(R.string.market_chart_bubble_no_data),
+ ),
+ tokenList = buildList {
+ repeat(5) { index ->
+ add(
+ ForYouTokenListItemUM(
+ tokenRowUM = TangemTokenRowUM.Loading(
+ id = index.toString(),
+ ),
+ tokenList = persistentListOf(),
+ isExpanded = false,
+ isExpandable = false,
+ ),
+ )
+ }
+ }.toPersistentList(),
+ )
+
+ val zeroPortfolioState = PortfolioReviewUM.Content(
+ marketChartUM = MarketChartUM.NoData(
+ title = stringReference("You don’t have any tokens with amount"),
+ donutText = stringReference("No amount on tokens"),
+ ),
+ tokenList = buildList {
+ repeat(5) { index ->
+ add(
+ ForYouTokenListItemUM(
+ tokenRowUM = TangemTokenRowUM.Content(
+ id = "token_$index",
+ headIconUM = TangemIconUM.Currency(CurrencyIconState.Loading),
+ titleUM = TangemTokenRowUM.TitleUM.Content(
+ text = stringReference("Token $index"),
+ badge = TangemBadgeUM(
+ text = stringReference("Positive"),
+ size = TangemBadgeSize.X4,
+ type = TangemBadgeType.Tinted,
+ color = TangemBadgeColor.Green,
+ ),
+ ),
+ subtitleUM = TangemTokenRowUM.SubtitleUM.Content(
+ text = stringReference("Some network"),
+ ),
+ topEndContentUM = TangemTokenRowUM.EndContentUM.Content(
+ text = stringReference("\$0"),
+ ),
+ bottomEndContentUM = TangemTokenRowUM.EndContentUM.Content(
+ text = stringReference("0.00%"),
+ ),
+ onItemClick = {},
+ onItemLongClick = { _, _ -> },
+ ),
+ tokenList = persistentListOf(),
+ isExpanded = false,
+ isExpandable = false,
+ ),
+ )
+ }
+ }.toPersistentList(),
+ onAddFundsClick = { },
)
}
\ No newline at end of file
diff --git a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/ForYouModelTest.kt b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/ForYouModelTest.kt
index b021e7f4b2..c43fd9a2a7 100644
--- a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/ForYouModelTest.kt
+++ b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/ForYouModelTest.kt
@@ -108,7 +108,7 @@ internal class ForYouModelTest {
val loading = model.uiState.value.portfolioReviewUM as PortfolioReviewUM.Loading
assertThat(loading.tokenList).hasSize(4)
assertThat(loading.tokenList.all { it.tokenRowUM is TangemTokenRowUM.Loading }).isTrue()
- assertThat(loading.marketChartUM).isEqualTo(MarketChartUM.NoData)
+ assertThat(loading.marketChartUM).isInstanceOf(MarketChartUM.NoData::class.java)
}
@Test
diff --git a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverterTest.kt b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverterTest.kt
index 02e1a1dabc..1d5a83b0d9 100644
--- a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverterTest.kt
+++ b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewConverterTest.kt
@@ -341,7 +341,7 @@ internal class ForYouPortfolioReviewConverterTest {
val result = createConverter().convert(statusList) as PortfolioReviewUM.Content
// Assert
- assertThat(result.marketChartUM).isEqualTo(MarketChartUM.NoData)
+ assertThat(result.marketChartUM).isInstanceOf(MarketChartUM.NoData::class.java)
}
@Test
@@ -350,7 +350,155 @@ internal class ForYouPortfolioReviewConverterTest {
val result = createConverter().convert(null) as PortfolioReviewUM.Content
// Assert
- assertThat(result.marketChartUM).isEqualTo(MarketChartUM.NoData)
+ assertThat(result.marketChartUM).isInstanceOf(MarketChartUM.NoData::class.java)
+ }
+ }
+
+ @Nested
+ inner class ZeroBalancePortfolio {
+
+ @Test
+ fun `GIVEN all currencies have zero fiat WHEN convert THEN market chart is the no-amount NoData`() {
+ // Arrange
+ val statuses = listOf(
+ createStatus(
+ createCoin(rawCurrencyId = "btc", symbol = "BTC", networkId = "bitcoin"),
+ loadedValue(BigDecimal.ZERO, BigDecimal.ZERO),
+ ),
+ createStatus(
+ createCoin(rawCurrencyId = "eth", symbol = "ETH", networkId = "ethereum"),
+ loadedValue(BigDecimal.ZERO, BigDecimal.ZERO),
+ ),
+ )
+
+ // Act
+ val result = convert(statuses, totalFiatBalance = BigDecimal.ZERO)
+
+ // Assert — the zero-balance treatment, not the generic can-not-load-data chart
+ assertThat(result.marketChartUM).isEqualTo(
+ MarketChartUM.NoData(
+ title = resourceReference(R.string.market_chart_no_amount),
+ donutText = resourceReference(R.string.market_chart_bubble_no_amount),
+ ),
+ )
+ }
+
+ @Test
+ fun `GIVEN all currencies have zero fiat WHEN add funds clicked THEN callback receives the wallet id`() {
+ // Arrange
+ val statuses = listOf(
+ createStatus(
+ createCoin(rawCurrencyId = "btc", symbol = "BTC", networkId = "bitcoin"),
+ loadedValue(BigDecimal.ZERO, BigDecimal.ZERO),
+ ),
+ )
+ var addFundsWalletId: UserWalletId? = null
+ val converter = createConverter(onAddFundsClick = { addFundsWalletId = it })
+
+ // Act
+ val result = converter.convert(
+ accountStatusList(statuses, BigDecimal.ZERO),
+ ) as PortfolioReviewUM.Content
+ result.onAddFundsClick?.invoke()
+
+ // Assert
+ assertThat(result.onAddFundsClick).isNotNull()
+ assertThat(addFundsWalletId).isEqualTo(UserWalletId("01"))
+ }
+
+ @Test
+ fun `GIVEN a non-zero balance WHEN convert THEN add funds action is absent`() {
+ // Arrange
+ val statuses = listOf(
+ createStatus(
+ createCoin(rawCurrencyId = "btc", symbol = "BTC", networkId = "bitcoin"),
+ loadedValue(BigDecimal.ONE, BigDecimal("100")),
+ ),
+ )
+
+ // Act
+ val result = convert(statuses, totalFiatBalance = BigDecimal("100"))
+
+ // Assert
+ assertThat(result.onAddFundsClick).isNull()
+ }
+
+ @Test
+ fun `GIVEN null account status list WHEN add funds clicked THEN callback is not invoked`() {
+ // Arrange — without a wallet there is nowhere to add funds, so the click must be a no-op
+ var clicked = false
+ val converter = createConverter(onAddFundsClick = { clicked = true })
+
+ // Act
+ val result = converter.convert(null) as PortfolioReviewUM.Content
+ result.onAddFundsClick?.invoke()
+
+ // Assert
+ assertThat(clicked).isFalse()
+ }
+
+ @Test
+ fun `GIVEN more than five zero-fiat currencies WHEN convert THEN list is capped with no Other row`() {
+ // Arrange — 7 distinct zero-balance assets; the zero-balance branch shows the first 5
+ // as-is instead of ranking and collapsing the excess into an "Other" row
+ val statuses = (1..7).map { index ->
+ createStatus(
+ createCoin(rawCurrencyId = "asset-$index", symbol = "A$index", networkId = "net-$index"),
+ loadedValue(BigDecimal.ZERO, BigDecimal.ZERO),
+ )
+ }
+
+ // Act
+ val result = convert(statuses, totalFiatBalance = BigDecimal.ZERO)
+
+ // Assert
+ assertThat(result.tokenList.map { it.tokenRowUM.id })
+ .containsExactly("asset-1", "asset-2", "asset-3", "asset-4", "asset-5")
+ .inOrder()
+ }
+
+ @Test
+ fun `GIVEN zero-fiat asset on several networks WHEN convert THEN grouped into one expandable item`() {
+ // Arrange — the same asset (shared rawCurrencyId) with zero balances on two networks
+ val onEth = createToken(rawCurrencyId = "usdc", symbol = "USDC", networkId = "ethereum")
+ val onSol = createToken(rawCurrencyId = "usdc", symbol = "USDC", networkId = "solana")
+ val statuses = listOf(
+ createStatus(onEth, loadedValue(BigDecimal.ZERO, BigDecimal.ZERO)),
+ createStatus(onSol, loadedValue(BigDecimal.ZERO, BigDecimal.ZERO)),
+ )
+
+ // Act
+ val result = convert(statuses, totalFiatBalance = BigDecimal.ZERO)
+
+ // Assert
+ val item = result.tokenList.single()
+ assertThat(item.tokenRowUM.id).isEqualTo("usdc")
+ assertThat(item.tokenList).hasSize(2)
+ assertThat(item.isExpandable).isTrue()
+ }
+
+ @Test
+ fun `GIVEN zero and null fiat currencies mixed WHEN convert THEN zero-balance treatment is not applied`() {
+ // Arrange — an unreachable holding has an *unknown* balance, not a resolved zero, so the
+ // portfolio must not collapse into the add-funds empty state
+ val statuses = listOf(
+ createStatus(
+ createCoin(rawCurrencyId = "eth", symbol = "ETH", networkId = "ethereum"),
+ loadedValue(BigDecimal.ZERO, BigDecimal.ZERO),
+ ),
+ createStatus(
+ createCoin(rawCurrencyId = "btc", symbol = "BTC", networkId = "bitcoin"),
+ unreachableValue(),
+ ),
+ )
+
+ // Act
+ val result = convert(statuses, totalFiatBalance = BigDecimal.ZERO)
+
+ // Assert — falls through to the ranked branch: no add-funds action, the resolved zero is
+ // dropped, the unknown-balance holding stays visible
+ assertThat(result.onAddFundsClick).isNull()
+ assertThat(result.tokenList.map { it.tokenRowUM.id }).containsExactly("btc")
}
}
@@ -364,11 +512,13 @@ internal class ForYouPortfolioReviewConverterTest {
expandedAssetIds: Set = emptySet(),
expandClick: (String) -> Unit = {},
onTokenClick: (UserWalletId, CryptoCurrency) -> Unit = { _, _ -> },
+ onAddFundsClick: (UserWalletId) -> Unit = {},
): ForYouPortfolioReviewConverter = ForYouPortfolioReviewConverter(
appCurrency = appCurrency,
expandedAssetIds = expandedAssetIds,
expandClick = expandClick,
onTokenClick = onTokenClick,
+ onAddFundsClick = onAddFundsClick,
)
private fun accountStatusList(
diff --git a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverterTest.kt b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverterTest.kt
index 15447c10cb..db070a0d17 100644
--- a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverterTest.kt
+++ b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/converter/portfolioReview/ForYouPortfolioReviewTokenRowConverterTest.kt
@@ -25,24 +25,24 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
private val appCurrency: AppCurrency = AppCurrency.Default
@Nested
- inner class ConvertNetworkGroup {
+ inner class Convert {
@Test
- fun `GIVEN all statuses Loading WHEN convertNetworkGroup THEN row is Loading with representative id`() {
+ fun `GIVEN all statuses Loading WHEN convert THEN row is Loading with representative id`() {
// Arrange
val currency = createCurrency(id = "coin-eth", symbol = "ETH")
val statuses = listOf(createStatus(currency, CryptoCurrencyStatus.Loading))
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses)
+ val result = converter.convert(statuses)
// Assert
assertThat(result).isEqualTo(TangemTokenRowUM.Loading(id = "coin-eth"))
}
@Test
- fun `GIVEN single loaded status WHEN convertNetworkGroup THEN row is Content with its amounts`() {
+ fun `GIVEN single loaded status WHEN convert THEN row is Content with its amounts`() {
// Arrange
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(
@@ -51,7 +51,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert
assertThat(result.id).isEqualTo("coin-eth")
@@ -62,7 +62,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN several statuses of the same asset on one network WHEN convertNetworkGroup THEN amounts are summed`() {
+ fun `GIVEN several statuses of the same asset on one network WHEN convert THEN amounts are summed`() {
// Arrange — same asset held in two accounts on the same network aggregates into one row
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(
@@ -72,7 +72,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert
val topEnd = result.topEndContentUM as TangemTokenRowUM.EndContentUM.Content
@@ -80,7 +80,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN mixed Loading and Loaded statuses WHEN convertNetworkGroup THEN row is Content`() {
+ fun `GIVEN mixed Loading and Loaded statuses WHEN convert THEN row is Content`() {
// Arrange — not *all* statuses are Loading, so it should not collapse to a Loading row
val currency = createCurrency(id = "coin-eth", symbol = "ETH")
val statuses = listOf(
@@ -90,14 +90,14 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses)
+ val result = converter.convert(statuses)
// Assert
assertThat(result).isInstanceOf(TangemTokenRowUM.Content::class.java)
}
@Test
- fun `GIVEN loaded status from cache WHEN convertNetworkGroup THEN content flickers`() {
+ fun `GIVEN loaded status from cache WHEN convert THEN content flickers`() {
// Arrange
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(
@@ -109,7 +109,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert
val topEnd = result.topEndContentUM as TangemTokenRowUM.EndContentUM.Content
@@ -120,7 +120,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN loaded status only-cache WHEN convertNetworkGroup THEN error-sync start icon shown`() {
+ fun `GIVEN loaded status only-cache WHEN convert THEN error-sync start icon shown`() {
// Arrange
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(
@@ -136,7 +136,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert
val topEnd = result.topEndContentUM as TangemTokenRowUM.EndContentUM.Content
@@ -145,14 +145,14 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN missed derivation status WHEN convertNetworkGroup THEN no-address treatment`() {
+ fun `GIVEN missed derivation status WHEN convert THEN no-address treatment`() {
// Arrange
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(createStatus(currency, missedDerivationValue()))
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert — top-end is a dash, bottom-end carries the attention "no address" icon
val topEnd = result.topEndContentUM as TangemTokenRowUM.EndContentUM.Content
@@ -162,14 +162,14 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN unreachable status WHEN convertNetworkGroup THEN dash on top and attention icon on bottom`() {
+ fun `GIVEN unreachable status WHEN convert THEN dash on top and attention icon on bottom`() {
// Arrange
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(createStatus(currency, unreachableValue()))
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert — top-end is a bare dash, the attention "unreachable" icon lives on the bottom end
val topEnd = result.topEndContentUM as TangemTokenRowUM.EndContentUM.Content
@@ -179,7 +179,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN mixed Loaded and Unreachable WHEN convertNetworkGroup THEN collapses to unreachable`() {
+ fun `GIVEN mixed Loaded and Unreachable WHEN convert THEN collapses to unreachable`() {
// Arrange — one account resolved, another unreachable: the row must surface the error state
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(
@@ -189,7 +189,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert — the unreachable treatment (attention icon on the bottom end) wins over the loaded amount
val bottomEnd = result.bottomEndContentUM as TangemTokenRowUM.EndContentUM.Content
@@ -212,7 +212,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
)
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
result.onItemClick?.invoke()
// Assert
@@ -234,7 +234,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
)
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
result.onItemClick?.invoke()
// Assert
@@ -242,7 +242,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
}
@Test
- fun `GIVEN mixed MissedDerivation and Unreachable WHEN convertNetworkGroup THEN missed-derivation wins`() {
+ fun `GIVEN mixed MissedDerivation and Unreachable WHEN convert THEN missed-derivation wins`() {
// Arrange — missed derivation is the most severe terminal state and dominates
val currency = createCurrency(id = "coin-eth", symbol = "ETH", networkName = "Ethereum")
val statuses = listOf(
@@ -252,7 +252,7 @@ internal class ForYouPortfolioReviewTokenRowConverterTest {
val converter = createConverter(totalFiatBalance = BigDecimal("1000"))
// Act
- val result = converter.convertNetworkGroup(statuses) as TangemTokenRowUM.Content
+ val result = converter.convert(statuses) as TangemTokenRowUM.Content
// Assert — top-end is a dash (no-address treatment), not an unreachable label
val topEnd = result.topEndContentUM as TangemTokenRowUM.EndContentUM.Content
diff --git a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/transformer/SetPortfolioReviewTransformerTest.kt b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/transformer/SetPortfolioReviewTransformerTest.kt
index c8c458b12a..bfef65a043 100644
--- a/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/transformer/SetPortfolioReviewTransformerTest.kt
+++ b/features/for-you/impl/src/test/kotlin/com/tangem/features/foryou/impl/model/transformer/SetPortfolioReviewTransformerTest.kt
@@ -137,7 +137,8 @@ internal class SetPortfolioReviewTransformerTest {
private fun contentPortfolioReview(): PortfolioReviewUM.Content = PortfolioReviewUM.Content(
tokenList = persistentListOf(),
- marketChartUM = MarketChartUM.NoData,
+ marketChartUM = noDataChart(),
+ onAddFundsClick = null,
)
private fun contentEarnOpportunities(): EarnOpportunitiesUM.Content = EarnOpportunitiesUM.Content(
@@ -148,6 +149,11 @@ internal class SetPortfolioReviewTransformerTest {
onAllEarnTokensClick = {},
)
+ private fun noDataChart(): MarketChartUM.NoData = MarketChartUM.NoData(
+ title = stringReference("No data"),
+ donutText = stringReference("No data"),
+ )
+
private fun accountStatusList(totalFiatBalance: TotalFiatBalance): AccountStatusList = mockk {
every { this@mockk.totalFiatBalance } returns totalFiatBalance
}
@@ -158,7 +164,7 @@ internal class SetPortfolioReviewTransformerTest {
private fun loadingState(): ForYouUM = ForYouUM(
portfolioReviewUM = PortfolioReviewUM.Loading(
tokenList = persistentListOf(),
- marketChartUM = MarketChartUM.NoData,
+ marketChartUM = noDataChart(),
),
earnOpportunities = EarnOpportunitiesUM.Loading(tokenList = persistentListOf()),
notifications = persistentListOf(),