From 7db38100645a477c21b9e0de5733c9c2236c3cd4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 15 Jun 2026 11:30:30 +0200 Subject: [PATCH] Updated on 2026-08-14 --- .../components/DefaultFeedEntryComponent.kt | 12 ++--- .../feed/components/FeedEntryChildFactory.kt | 4 +- .../search/DefaultSearchComponent.kt | 4 ++ .../feed/state/FeedMarketsBatchFlowManager.kt | 9 +--- .../features/feed/model/search/SearchModel.kt | 54 +++++++++++++++++++ .../search/state/SearchStateController.kt | 2 + .../transformers/SetTopMarketsTransformer.kt | 11 ++++ .../tangem/features/feed/ui/feed/FeedList.kt | 4 +- .../feed/ui/feed/components/BlockHeader.kt | 10 ++-- .../feed/ui/feed/components/EarnBlock.kt | 2 + .../feed/ui/feed/components/MarketsBlock.kt | 23 +++++--- .../feed/ui/feed/components/NewsBlock.kt | 8 ++- .../features/feed/ui/search/SearchContent.kt | 34 +++++++++--- .../ui/search/preview/SearchContentPreview.kt | 16 +++++- .../feed/ui/search/state/SearchCallbacks.kt | 2 + .../features/feed/ui/search/state/SearchUM.kt | 4 +- 16 files changed, 159 insertions(+), 40 deletions(-) create mode 100644 features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/SetTopMarketsTransformer.kt diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/DefaultFeedEntryComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/DefaultFeedEntryComponent.kt index 0ea374a12d..e5ae65dc08 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/DefaultFeedEntryComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/DefaultFeedEntryComponent.kt @@ -5,10 +5,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import com.arkivanov.decompose.extensions.compose.subscribeAsState -import com.arkivanov.decompose.router.stack.ChildStack -import com.arkivanov.decompose.router.stack.StackNavigation -import com.arkivanov.decompose.router.stack.childStack -import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.* import com.arkivanov.decompose.value.Value import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.decompose.context.AppComponentContext @@ -87,8 +84,9 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor( } override fun onMarketOpenClick(sortBy: SortByTypeUM?) { - innerRouter.push( - route = FeedEntryChildFactory.Child.TokenList( + // Markets list and search can reach each other + stackNavigation.bringToFront( + FeedEntryChildFactory.Child.TokenList( params = DefaultMarketsTokenListComponent.Params( preselectedSortType = sortBy ?: SortByTypeUM.Rating, preselectedInterval = MarketsListUM.TrendInterval.H24, @@ -142,7 +140,7 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor( } override fun openSearch(source: String) { - innerRouter.push(FeedEntryChildFactory.Child.Search(source)) + stackNavigation.bringToFront(FeedEntryChildFactory.Child.Search(source)) } } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/FeedEntryChildFactory.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/FeedEntryChildFactory.kt index 4e65f19449..41a971c02d 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/FeedEntryChildFactory.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/FeedEntryChildFactory.kt @@ -7,17 +7,18 @@ import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.navigation.Route import com.tangem.core.ui.DesignFeatureToggles import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent +import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent import com.tangem.features.feed.components.earn.DefaultEarnComponent import com.tangem.features.feed.components.feed.DefaultFeedComponent import com.tangem.features.feed.components.feed.DefaultFeedComponent.FeedParams import com.tangem.features.feed.components.market.details.DefaultMarketsTokenDetailsComponent -import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent import com.tangem.features.feed.components.market.details.portfolio.api.MarketsPortfolioComponent import com.tangem.features.feed.components.market.details.portfolioblock.PortfolioBlockComponent import com.tangem.features.feed.components.market.list.DefaultMarketsTokenListComponent import com.tangem.features.feed.components.news.details.DefaultNewsDetailsComponent import com.tangem.features.feed.components.news.list.DefaultNewsListComponent import com.tangem.features.feed.components.search.DefaultSearchComponent +import com.tangem.features.feed.model.market.list.state.SortByTypeUM import com.tangem.features.promobanners.api.PromoBannersBlockComponent import kotlinx.serialization.Serializable import javax.inject.Inject @@ -142,6 +143,7 @@ internal class FeedEntryChildFactory @Inject constructor( ) }, sourceParams = child.source, + onSeeAllMarketsClick = { feedEntryClickIntents.onMarketOpenClick(SortByTypeUM.Rating) }, ), ) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt index d14bce3f5d..57efcc2c7e 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/search/DefaultSearchComponent.kt @@ -84,11 +84,14 @@ internal class DefaultSearchComponent( onTextHintClick = model::onTextHintClick, onResultMarketTokenClick = model::onResultMarketTokenClick, onHistoryTokenClick = model::onHistoryTokenClick, + onTopMarketSeeAllClick = model::onTopMarketSeeAllClick, + onTopMarketItemClick = model::onTopMarketItemClick, ) } SearchContent( modifier = modifier, content = state.content, + topMarkets = state.topMarkets, searchCallbacks = searchCallbacks, contentPadding = contentPadding, ) @@ -114,5 +117,6 @@ internal class DefaultSearchComponent( val onBackClick: () -> Unit, val onMarketTokenClick: ((TokenMarketParams, AppCurrency) -> Unit), val sourceParams: String, + val onSeeAllMarketsClick: () -> Unit, ) } \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/feed/state/FeedMarketsBatchFlowManager.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/feed/state/FeedMarketsBatchFlowManager.kt index 056232c69b..e6883b7291 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/feed/state/FeedMarketsBatchFlowManager.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/feed/state/FeedMarketsBatchFlowManager.kt @@ -29,14 +29,9 @@ internal class FeedMarketsBatchFlowManager( private val currentAppCurrency: Provider, private val modelScope: CoroutineScope, private val dispatchers: CoroutineDispatcherProvider, + orders: List = TokenMarketListConfig.Order.entries, ) { - private val managersByOrder = listOf( - TokenMarketListConfig.Order.ByRating, - TokenMarketListConfig.Order.Trending, - TokenMarketListConfig.Order.Buyers, - TokenMarketListConfig.Order.TopGainers, - TokenMarketListConfig.Order.TopLosers, - ).associateWith { order -> + private val managersByOrder = orders.associateWith { order -> createManagerForOrder(order) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt index 691e91a017..535d5f3419 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/SearchModel.kt @@ -26,6 +26,7 @@ import com.tangem.domain.search.usecase.SaveRecentSearchTokenUseCase import com.tangem.domain.search.usecase.SaveSearchQueryUseCase import com.tangem.features.feed.components.search.DefaultSearchComponent import com.tangem.features.feed.components.search.SearchBottomSheetRoute +import com.tangem.features.feed.model.feed.state.FeedMarketsBatchFlowManager import com.tangem.features.feed.model.market.list.state.MarketsListUM import com.tangem.features.feed.model.market.list.state.SortByTypeUM import com.tangem.features.feed.model.market.list.statemanager.MarketsListBatchFlowManager @@ -33,6 +34,8 @@ import com.tangem.features.feed.model.search.analytics.SearchAnalyticsHelper import com.tangem.features.feed.model.search.converter.* import com.tangem.features.feed.model.search.state.SearchStateController import com.tangem.features.feed.model.search.state.transformers.* +import com.tangem.features.feed.ui.feed.state.MarketChartUM +import com.tangem.features.feed.ui.feed.state.SortChartConfigUM import com.tangem.features.feed.ui.search.state.MarketSearchResultUM import com.tangem.features.feed.ui.search.state.SearchContentUM import com.tangem.features.feed.ui.search.state.SearchUM @@ -42,6 +45,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -57,6 +61,7 @@ internal class SearchModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase, + private val getTopFiveMarketTokenUseCase: GetTopFiveMarketTokenUseCase, getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val getSearchResultsUseCase: GetSearchResultsUseCase, @@ -115,6 +120,16 @@ internal class SearchModel @Inject constructor( ) } + private val topMarketsManager by lazy { + FeedMarketsBatchFlowManager( + getTopFiveMarketTokenUseCase = getTopFiveMarketTokenUseCase, + currentAppCurrency = Provider { currentAppCurrency.value }, + modelScope = modelScope, + dispatchers = dispatchers, + orders = listOf(TokenMarketListConfig.Order.ByRating), + ) + } + val bottomSheetNavigation: SlotNavigation = SlotNavigation() val state: StateFlow get() = stateController.uiState @@ -127,6 +142,7 @@ internal class SearchModel @Inject constructor( subscribeToAppCurrencyChanges() subscribeToMarketLoadingErrors() subscribeToResultsShown() + subscribeToTopMarkets() loadHistory() searchAnalyticsHelper.sendSearchScreenOpened(params.sourceParams) } @@ -190,6 +206,15 @@ internal class SearchModel @Inject constructor( params.onMarketTokenClick(tokenMarketParams, currentAppCurrency.value) } + fun onTopMarketSeeAllClick() { + params.onSeeAllMarketsClick() + } + + fun onTopMarketItemClick(item: MarketsListItemUM) { + val token = topMarketsManager.getTokenMarketById(item.id) ?: return + params.onMarketTokenClick(token.toSerializableParam(), currentAppCurrency.value) + } + private fun initCallbacks() { stateController.update(object : SearchUMTransformer { override fun transform(prevState: SearchUM): SearchUM { @@ -402,6 +427,35 @@ internal class SearchModel @Inject constructor( } } + private fun subscribeToTopMarkets() { + combine( + topMarketsManager.itemsByOrder, + topMarketsManager.loadingStatesByOrder, + topMarketsManager.errorStatesByOrder, + ) { itemsByOrder, _, errorsByOrder -> + val ratingItems = itemsByOrder[SortByTypeUM.Rating] ?: persistentListOf() + val error = errorsByOrder[SortByTypeUM.Rating] + when { + ratingItems.isNotEmpty() -> MarketChartUM.Content( + items = ratingItems, + sortChartConfig = SortChartConfigUM(sortByType = SortByTypeUM.Rating, isSelected = true), + ) + error != null -> MarketChartUM.LoadingError( + onRetryClicked = { topMarketsManager.reloadManager(TokenMarketListConfig.Order.ByRating) }, + ) + else -> MarketChartUM.Loading + } + } + .distinctUntilChanged() + .onEach { chart -> + stateController.update(SetTopMarketsTransformer(chart)) + if (chart is MarketChartUM.Content) { + topMarketsManager.loadCharts(TokenMarketListConfig.Order.ByRating) + } + } + .launchIn(modelScope) + } + private fun loadHistory() { modelScope.launch { getSearchResultsUseCase(query = "").collectLatest { searchResult -> diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/SearchStateController.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/SearchStateController.kt index ceccae14fa..b2b8147559 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/SearchStateController.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/SearchStateController.kt @@ -5,6 +5,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.extensions.resourceReference import com.tangem.features.feed.impl.R import com.tangem.features.feed.model.search.state.transformers.SearchUMTransformer +import com.tangem.features.feed.ui.feed.state.MarketChartUM import com.tangem.features.feed.ui.search.state.SearchContentUM import com.tangem.features.feed.ui.search.state.SearchUM import kotlinx.coroutines.flow.MutableStateFlow @@ -38,6 +39,7 @@ internal class SearchStateController @Inject constructor() { onClearClick = {}, ), content = SearchContentUM.InitialEmpty, + topMarkets = MarketChartUM.Loading, ) } } \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/SetTopMarketsTransformer.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/SetTopMarketsTransformer.kt new file mode 100644 index 0000000000..aff67d7451 --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/search/state/transformers/SetTopMarketsTransformer.kt @@ -0,0 +1,11 @@ +package com.tangem.features.feed.model.search.state.transformers + +import com.tangem.features.feed.ui.feed.state.MarketChartUM +import com.tangem.features.feed.ui.search.state.SearchUM + +internal class SetTopMarketsTransformer(private val topMarkets: MarketChartUM) : SearchUMTransformer { + + override fun transform(prevState: SearchUM): SearchUM { + return prevState.copy(topMarkets = topMarkets) + } +} \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt index c180304707..6922f8a91b 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt @@ -109,7 +109,9 @@ private fun FeedListContent( MarketBlock( marketChart = state.marketChartConfig.marketCharts[SortByTypeUM.Rating], - feedListCallbacks = state.feedListCallbacks, + onSeeAllClick = { state.feedListCallbacks.onMarketOpenClick(SortByTypeUM.Rating) }, + onItemClick = state.feedListCallbacks.onMarketItemClick, + modifier = Modifier.padding(horizontal = 16.dp), ) promoBannersBlockComponent?.Content( diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt index 0fe962de35..d85eb11789 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt @@ -28,17 +28,19 @@ internal fun ColumnScope.Header( onSeeAllClick: () -> Unit, isLoading: Boolean, shouldShowSeeAll: Boolean, + modifier: Modifier = Modifier, title: @Composable () -> Unit, ) { val isRedesignEnabled = LocalRedesignEnabled.current if (isRedesignEnabled) { SpacerH(12.dp) } - AnimatedContent(isLoading) { animatedState -> + AnimatedContent( + targetState = isLoading, + modifier = modifier, + ) { animatedState -> Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp), + modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/EarnBlock.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/EarnBlock.kt index b2984c929c..087dbfa992 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/EarnBlock.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/EarnBlock.kt @@ -52,6 +52,7 @@ private fun EarnBlockV1(onSeeAllClick: () -> Unit, earnListUM: EarnListUM, modif onSeeAllClick = onSeeAllClick, isLoading = earnListUM is EarnListUM.Loading, shouldShowSeeAll = earnListUM is EarnListUM.Content, + modifier = Modifier.padding(horizontal = 20.dp), ) SpacerH(12.dp) @@ -96,6 +97,7 @@ private fun EarnBlockV2(onSeeAllClick: () -> Unit, earnListUM: EarnListUM, modif onSeeAllClick = onSeeAllClick, isLoading = earnListUM is EarnListUM.Loading, shouldShowSeeAll = earnListUM is EarnListUM.Content, + modifier = Modifier.padding(horizontal = 20.dp), ) SpacerH(12.dp) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt index 9bf3a68523..e4cfd4a92b 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt @@ -36,7 +36,12 @@ import com.tangem.features.feed.ui.feed.state.MarketChartConfig import com.tangem.features.feed.ui.feed.state.MarketChartUM @Composable -internal fun MarketBlock(marketChart: MarketChartUM?, feedListCallbacks: FeedListCallbacks) { +internal fun MarketBlock( + marketChart: MarketChartUM?, + onSeeAllClick: () -> Unit, + onItemClick: (MarketsListItemUM) -> Unit, + modifier: Modifier = Modifier, +) { val isRedesignEnabled = LocalRedesignEnabled.current AnimatedContent( targetState = marketChart, @@ -48,7 +53,7 @@ internal fun MarketBlock(marketChart: MarketChartUM?, feedListCallbacks: FeedLis MarketChartUM.Loading, is MarketChartUM.LoadingError, -> { - Column(modifier = Modifier.fillMaxWidth()) { + Column(modifier = modifier.fillMaxWidth()) { Header( title = { Text( @@ -67,16 +72,18 @@ internal fun MarketBlock(marketChart: MarketChartUM?, feedListCallbacks: FeedLis maxLines = 1, ) }, - onSeeAllClick = { feedListCallbacks.onMarketOpenClick(SortByTypeUM.Rating) }, + onSeeAllClick = onSeeAllClick, shouldShowSeeAll = currentChart is MarketChartUM.Content, isLoading = currentChart is MarketChartUM.Loading, + // Header text is inset so it aligns with the list item text inside the card; the card itself + // sits at the block edge (supplied by [modifier]). + modifier = Modifier.padding(horizontal = MARKET_BLOCK_HEADER_PADDING), ) SpacerH(if (isRedesignEnabled) 20.dp else 12.dp) Charts( - onItemClick = feedListCallbacks.onMarketItemClick, - modifier = Modifier.padding(horizontal = 16.dp), + onItemClick = onItemClick, marketChart = currentChart, ) } @@ -115,6 +122,7 @@ internal fun ColumnScope.MarketPulseBlock(marketChartConfig: MarketChartConfig, onSeeAllClick = { onSeeAllClick() }, shouldShowSeeAll = true, isLoading = marketChartConfig.marketCharts[marketChartConfig.currentSortByType] is MarketChartUM.Loading, + modifier = Modifier.padding(horizontal = 20.dp), ) LazyRow( @@ -219,4 +227,7 @@ private fun Charts( } } -private const val DEFAULT_CHART_SIZE_IN_MARKET = 5 \ No newline at end of file +private const val DEFAULT_CHART_SIZE_IN_MARKET = 5 + +/** Header inset so its text aligns with the list item text inside the card (the card sits at the block edge). */ +private val MARKET_BLOCK_HEADER_PADDING = 4.dp \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/NewsBlock.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/NewsBlock.kt index 84414ebab7..8fc948caa6 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/NewsBlock.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/NewsBlock.kt @@ -2,11 +2,7 @@ package com.tangem.features.feed.ui.feed.components import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -148,6 +144,7 @@ private fun NewsContentBlock(feedListCallbacks: FeedListCallbacks, news: NewsUM, onSeeAllClick = { feedListCallbacks.onOpenAllNews(false) }, isLoading = news.newsUMState == NewsUMState.LOADING, shouldShowSeeAll = news.newsUMState == NewsUMState.CONTENT, + modifier = Modifier.padding(horizontal = 20.dp), ) SpacerH(12.dp) @@ -200,6 +197,7 @@ private fun NewsErrorBlock(onRetryClick: () -> Unit) { onSeeAllClick = {}, shouldShowSeeAll = false, isLoading = false, + modifier = Modifier.padding(horizontal = 20.dp), ) SpacerH(12.dp) BlockCard( diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt index 41bed10ea9..2c6f115e59 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/SearchContent.kt @@ -36,7 +36,12 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.LocalMainBottomSheetColor import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.feed.ui.search.state.* +import com.tangem.features.feed.ui.feed.components.MarketBlock +import com.tangem.features.feed.ui.feed.state.MarketChartUM +import com.tangem.features.feed.ui.search.state.MarketSearchResultUM +import com.tangem.features.feed.ui.search.state.SearchCallbacks +import com.tangem.features.feed.ui.search.state.SearchContentUM +import com.tangem.features.feed.ui.search.state.TextHintItemUM import kotlinx.collections.immutable.ImmutableList private const val PLACEHOLDER_COUNT = 10 @@ -46,6 +51,7 @@ private const val USER_ASSETS_LIMIT = 3 @Composable internal fun SearchContent( content: SearchContentUM, + topMarkets: MarketChartUM, searchCallbacks: SearchCallbacks, contentPadding: PaddingValues, modifier: Modifier = Modifier, @@ -85,12 +91,16 @@ internal fun SearchContent( ) { when (content) { is SearchContentUM.InitialEmpty -> Unit - is SearchContentUM.History -> searchHistoryItems( - history = content, - onClearAllClick = searchCallbacks.onClearHintsClick, - onHintClick = searchCallbacks.onTextHintClick, - onHistoryTokenClick = searchCallbacks.onHistoryTokenClick, - ) + is SearchContentUM.History -> if (content.textHints.isEmpty() && content.recentTokens.isEmpty()) { + topMarketsBlock(topMarkets, searchCallbacks) + } else { + searchHistoryItems( + history = content, + onClearAllClick = searchCallbacks.onClearHintsClick, + onHintClick = searchCallbacks.onTextHintClick, + onHistoryTokenClick = searchCallbacks.onHistoryTokenClick, + ) + } is SearchContentUM.Results -> searchResultsItems( results = content, isUserAssetsExpanded = isUserAssetsExpanded, @@ -114,6 +124,16 @@ internal fun SearchContent( } } +private fun LazyListScope.topMarketsBlock(topMarkets: MarketChartUM, searchCallbacks: SearchCallbacks) { + item(key = "top_markets") { + MarketBlock( + marketChart = topMarkets, + onSeeAllClick = searchCallbacks.onTopMarketSeeAllClick, + onItemClick = searchCallbacks.onTopMarketItemClick, + ) + } +} + private fun LazyListScope.searchHistoryItems( history: SearchContentUM.History, onClearAllClick: (() -> Unit), diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt index 24cc5d32c7..edf494706e 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/preview/SearchContentPreview.kt @@ -21,8 +21,14 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.features.feed.model.market.list.state.SortByTypeUM +import com.tangem.features.feed.ui.feed.state.MarketChartUM +import com.tangem.features.feed.ui.feed.state.SortChartConfigUM import com.tangem.features.feed.ui.search.SearchContent -import com.tangem.features.feed.ui.search.state.* +import com.tangem.features.feed.ui.search.state.MarketSearchResultUM +import com.tangem.features.feed.ui.search.state.SearchCallbacks +import com.tangem.features.feed.ui.search.state.SearchContentUM +import com.tangem.features.feed.ui.search.state.TextHintItemUM import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -373,6 +379,11 @@ internal object SearchContentPreviewFixtures { ), ).toImmutableList() + fun topMarketsContent(): MarketChartUM = MarketChartUM.Content( + items = marketListShort(), + sortChartConfig = SortChartConfigUM(sortByType = SortByTypeUM.Rating, isSelected = true), + ) + fun allScenarios(): List = listOf( scenarioInitialEmpty, scenarioHistoryEmptyBoth, @@ -398,6 +409,8 @@ private val SearchContentPreviewCallbacks = SearchCallbacks( onTextHintClick = { _ -> }, onResultMarketTokenClick = { _ -> }, onHistoryTokenClick = { _ -> }, + onTopMarketSeeAllClick = {}, + onTopMarketItemClick = { _ -> }, ) /** All [SearchContentPreviewScenario] values for the Preview Parameter dropdown in Android Studio. */ @@ -420,6 +433,7 @@ private fun SearchContentPreviewHost( ) { SearchContent( content = scenario.content, + topMarkets = SearchContentPreviewFixtures.topMarketsContent(), searchCallbacks = SearchContentPreviewCallbacks, modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(), diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt index 9535331da7..9dcc6bb818 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchCallbacks.kt @@ -8,4 +8,6 @@ internal data class SearchCallbacks( val onTextHintClick: (hint: String) -> Unit, val onResultMarketTokenClick: (MarketsListItemUM) -> Unit, val onHistoryTokenClick: (MarketsListItemUM) -> Unit, + val onTopMarketSeeAllClick: () -> Unit, + val onTopMarketItemClick: (MarketsListItemUM) -> Unit, ) \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchUM.kt index 7dbf384023..51ea683a70 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchUM.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/search/state/SearchUM.kt @@ -4,11 +4,13 @@ import androidx.compose.runtime.Immutable import com.tangem.common.ui.markets.models.MarketsListItemUM import com.tangem.common.ui.markets.tokenselector.UserAssetItemUM import com.tangem.core.ui.components.fields.entity.SearchBarUM +import com.tangem.features.feed.ui.feed.state.MarketChartUM import kotlinx.collections.immutable.ImmutableList -data class SearchUM( +internal data class SearchUM( val searchBar: SearchBarUM, val content: SearchContentUM, + val topMarkets: MarketChartUM, ) @Immutable