Updated on 2026-08-14
This commit is contained in:
parent
9f4dae9fa1
commit
236794fa00
26 changed files with 329 additions and 16 deletions
|
|
@ -1,6 +1,9 @@
|
|||
package com.tangem.features.feed.entry.components
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.PreselectedMarketsInterval
|
||||
import com.tangem.domain.markets.PreselectedMarketsOrder
|
||||
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
|
@ -13,6 +16,9 @@ sealed interface FeedEntryRoute {
|
|||
val appCurrency: AppCurrency,
|
||||
val shouldShowPortfolio: Boolean,
|
||||
val analyticsParams: AnalyticsParams? = null,
|
||||
val preselectedSection: PreselectedTokenDetailsSection? = null,
|
||||
val shouldOpenExchanges: Boolean = false,
|
||||
val exchangesCount: Int? = null,
|
||||
) : FeedEntryRoute {
|
||||
|
||||
@Serializable
|
||||
|
|
@ -23,7 +29,10 @@ sealed interface FeedEntryRoute {
|
|||
}
|
||||
|
||||
@Serializable
|
||||
data object MarketTokenList : FeedEntryRoute
|
||||
data class MarketTokenList(
|
||||
val preselectedOrder: PreselectedMarketsOrder? = null,
|
||||
val preselectedInterval: PreselectedMarketsInterval? = null,
|
||||
) : FeedEntryRoute
|
||||
|
||||
@Serializable
|
||||
data class NewsDetail(val articleId: Int, val preselectedArticlesId: List<Int>) : FeedEntryRoute
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ package com.tangem.features.feed.entry.deeplink
|
|||
interface MarketsDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(): MarketsDeepLinkHandler
|
||||
fun create(params: Map<String, String>): MarketsDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.feed.entry.deeplink
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
interface MarketsTokenExchangesDeepLinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope, params: Map<String, String>): MarketsTokenExchangesDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,9 @@ import com.tangem.features.feed.entry.components.FeedEntryComponent
|
|||
import com.tangem.features.feed.entry.components.FeedEntryRoute
|
||||
import com.tangem.features.feed.model.FeedEntryModel
|
||||
import com.tangem.features.feed.model.feed.FeedModelClickIntents
|
||||
import com.tangem.domain.markets.PreselectedMarketsInterval
|
||||
import com.tangem.domain.markets.PreselectedMarketsOrder
|
||||
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.ui.EntryContent
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -87,6 +90,7 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
|
|||
route = FeedEntryChildFactory.Child.TokenList(
|
||||
params = DefaultMarketsTokenListComponent.Params(
|
||||
preselectedSortType = sortBy ?: SortByTypeUM.Rating,
|
||||
preselectedInterval = MarketsListUM.TrendInterval.H24,
|
||||
shouldAlwaysShowSearchBar = sortBy == null,
|
||||
),
|
||||
),
|
||||
|
|
@ -231,11 +235,15 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
|
|||
paginationConfig = null,
|
||||
)
|
||||
},
|
||||
preselectedSection = entryRoute.preselectedSection,
|
||||
shouldOpenExchanges = entryRoute.shouldOpenExchanges,
|
||||
exchangesCount = entryRoute.exchangesCount,
|
||||
),
|
||||
)
|
||||
FeedEntryRoute.MarketTokenList -> FeedEntryChildFactory.Child.TokenList(
|
||||
is FeedEntryRoute.MarketTokenList -> FeedEntryChildFactory.Child.TokenList(
|
||||
DefaultMarketsTokenListComponent.Params(
|
||||
preselectedSortType = SortByTypeUM.Rating,
|
||||
preselectedSortType = mapOrderToSortType(entryRoute.preselectedOrder),
|
||||
preselectedInterval = mapIntervalToTrendInterval(entryRoute.preselectedInterval),
|
||||
shouldAlwaysShowSearchBar = false,
|
||||
),
|
||||
)
|
||||
|
|
@ -265,4 +273,24 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun mapOrderToSortType(order: PreselectedMarketsOrder?): SortByTypeUM {
|
||||
return when (order) {
|
||||
PreselectedMarketsOrder.Rating -> SortByTypeUM.Rating
|
||||
PreselectedMarketsOrder.Trending -> SortByTypeUM.Trending
|
||||
PreselectedMarketsOrder.Buyers -> SortByTypeUM.ExperiencedBuyers
|
||||
PreselectedMarketsOrder.Gainers -> SortByTypeUM.TopGainers
|
||||
PreselectedMarketsOrder.Losers -> SortByTypeUM.TopLosers
|
||||
null -> SortByTypeUM.Rating
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapIntervalToTrendInterval(interval: PreselectedMarketsInterval?): MarketsListUM.TrendInterval {
|
||||
return when (interval) {
|
||||
PreselectedMarketsInterval.H24 -> MarketsListUM.TrendInterval.H24
|
||||
PreselectedMarketsInterval.W1 -> MarketsListUM.TrendInterval.D7
|
||||
PreselectedMarketsInterval.D30 -> MarketsListUM.TrendInterval.M1
|
||||
null -> MarketsListUM.TrendInterval.H24
|
||||
}
|
||||
}
|
||||
|
||||
internal interface FeedEntryClickIntents : FeedModelClickIntents
|
||||
|
|
@ -17,6 +17,7 @@ import androidx.compose.ui.res.vectorResource
|
|||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
|
|
@ -228,6 +229,9 @@ internal class DefaultMarketsTokenDetailsComponent(
|
|||
val analyticsParams: AnalyticsParams?,
|
||||
val onBackClicked: () -> Unit,
|
||||
val onArticleClick: (articleId: Int, preselectedArticlesId: List<Int>) -> Unit,
|
||||
val preselectedSection: PreselectedTokenDetailsSection? = null,
|
||||
val shouldOpenExchanges: Boolean = false,
|
||||
val exchangesCount: Int? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.features.feed.model.market.list.MarketsListModel
|
||||
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.ui.components.FeedSearchBar
|
||||
import com.tangem.features.feed.ui.market.list.MarketsList
|
||||
|
|
@ -127,6 +128,7 @@ internal class DefaultMarketsTokenListComponent(
|
|||
@Serializable
|
||||
data class Params(
|
||||
val preselectedSortType: SortByTypeUM,
|
||||
val preselectedInterval: MarketsListUM.TrendInterval,
|
||||
val shouldAlwaysShowSearchBar: Boolean,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,20 +2,31 @@ package com.tangem.features.feed.deeplink
|
|||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.INTERVAL_KEY
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.ORDER_KEY
|
||||
import com.tangem.domain.markets.PreselectedMarketsInterval
|
||||
import com.tangem.domain.markets.PreselectedMarketsOrder
|
||||
import com.tangem.features.feed.entry.deeplink.MarketsDeepLinkHandler
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultMarketsDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted private val queryParams: Map<String, String>,
|
||||
appRouter: AppRouter,
|
||||
) : MarketsDeepLinkHandler {
|
||||
|
||||
init {
|
||||
appRouter.push(AppRoute.Markets)
|
||||
appRouter.push(
|
||||
AppRoute.Markets(
|
||||
preselectedOrder = PreselectedMarketsOrder.parse(queryParams[ORDER_KEY]),
|
||||
preselectedInterval = PreselectedMarketsInterval.parse(queryParams[INTERVAL_KEY]),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MarketsDeepLinkHandler.Factory {
|
||||
override fun create(): DefaultMarketsDeepLinkHandler
|
||||
override fun create(params: Map<String, String>): DefaultMarketsDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,9 @@ package com.tangem.features.feed.deeplink
|
|||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.SECTION_KEY
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.TOKEN_ID_KEY
|
||||
import com.tangem.data.common.currency.getTokenIconUrlFromDefaultHost
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
|
|
@ -11,12 +13,12 @@ import com.tangem.domain.markets.GetTokenMarketInfoUseCase
|
|||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.feed.entry.deeplink.MarketsTokenDetailDeepLinkHandler
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
||||
internal class DefaultMarketsTokenDetailDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
|
|
@ -32,8 +34,15 @@ internal class DefaultMarketsTokenDetailDeepLinkHandler @AssistedInject construc
|
|||
|
||||
private fun handleDeepLink() {
|
||||
val tokenId = queryParams[TOKEN_ID_KEY]
|
||||
val section = PreselectedTokenDetailsSection.parse(queryParams[SECTION_KEY])
|
||||
|
||||
val rawTokenId = CryptoCurrency.RawID(tokenId.orEmpty())
|
||||
if (tokenId.isNullOrEmpty()) {
|
||||
TangemLogger.e("Markets token details deeplink does not contain token_id")
|
||||
appRouter.push(AppRoute.Markets())
|
||||
return
|
||||
}
|
||||
|
||||
val rawTokenId = CryptoCurrency.RawID(tokenId)
|
||||
|
||||
scope.launch {
|
||||
val appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse {
|
||||
|
|
@ -65,6 +74,7 @@ internal class DefaultMarketsTokenDetailDeepLinkHandler @AssistedInject construc
|
|||
appCurrency = appCurrency,
|
||||
shouldShowPortfolio = true,
|
||||
analyticsParams = null,
|
||||
preselectedSection = section,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
package com.tangem.features.feed.deeplink
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.TOKEN_ID_KEY
|
||||
import com.tangem.data.common.currency.getTokenIconUrlFromDefaultHost
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.GetTokenMarketInfoUseCase
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.feed.entry.deeplink.MarketsTokenExchangesDeepLinkHandler
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class DefaultMarketsTokenExchangesDeepLinkHandler @AssistedInject constructor(
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
@Assisted private val queryParams: Map<String, String>,
|
||||
private val appRouter: AppRouter,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getTokenMarketInfoUseCase: GetTokenMarketInfoUseCase,
|
||||
) : MarketsTokenExchangesDeepLinkHandler {
|
||||
|
||||
init {
|
||||
handleDeepLink()
|
||||
}
|
||||
|
||||
private fun handleDeepLink() {
|
||||
val tokenId = queryParams[TOKEN_ID_KEY]
|
||||
|
||||
if (tokenId.isNullOrEmpty()) {
|
||||
TangemLogger.e("Markets token exchanges deeplink does not contain token_id")
|
||||
appRouter.push(AppRoute.Markets())
|
||||
return
|
||||
}
|
||||
|
||||
val rawTokenId = CryptoCurrency.RawID(tokenId)
|
||||
|
||||
scope.launch {
|
||||
val appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse {
|
||||
AppCurrency.Default
|
||||
}
|
||||
val tokenInfo = getTokenMarketInfoUseCase(
|
||||
appCurrency = appCurrency,
|
||||
tokenId = rawTokenId,
|
||||
tokenSymbol = "",
|
||||
).getOrElse {
|
||||
TangemLogger.e("Failed to get market token info for exchanges deeplink")
|
||||
appRouter.push(AppRoute.Markets())
|
||||
return@launch
|
||||
}
|
||||
|
||||
appRouter.push(
|
||||
AppRoute.MarketsTokenDetails(
|
||||
token = TokenMarketParams(
|
||||
id = rawTokenId,
|
||||
name = tokenInfo.name,
|
||||
symbol = tokenInfo.symbol,
|
||||
tokenQuotes = TokenMarketParams.Quotes(
|
||||
currentPrice = tokenInfo.quotes.currentPrice,
|
||||
h24Percent = tokenInfo.quotes.h24ChangePercent,
|
||||
weekPercent = tokenInfo.quotes.weekChangePercent,
|
||||
monthPercent = tokenInfo.quotes.monthChangePercent,
|
||||
),
|
||||
imageUrl = getTokenIconUrlFromDefaultHost(rawTokenId),
|
||||
),
|
||||
appCurrency = appCurrency,
|
||||
shouldShowPortfolio = true,
|
||||
shouldOpenExchanges = true,
|
||||
exchangesCount = tokenInfo.exchangesAmount,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MarketsTokenExchangesDeepLinkHandler.Factory {
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
queryParams: Map<String, String>,
|
||||
): DefaultMarketsTokenExchangesDeepLinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,10 @@ package com.tangem.features.feed.deeplink.di
|
|||
|
||||
import com.tangem.features.feed.deeplink.DefaultMarketsDeepLinkHandler
|
||||
import com.tangem.features.feed.deeplink.DefaultMarketsTokenDetailDeepLinkHandler
|
||||
import com.tangem.features.feed.deeplink.DefaultMarketsTokenExchangesDeepLinkHandler
|
||||
import com.tangem.features.feed.entry.deeplink.MarketsDeepLinkHandler
|
||||
import com.tangem.features.feed.entry.deeplink.MarketsTokenDetailDeepLinkHandler
|
||||
import com.tangem.features.feed.entry.deeplink.MarketsTokenExchangesDeepLinkHandler
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -23,4 +25,10 @@ internal interface MarketsDeepLinkModule {
|
|||
fun bindMarketsTokenDetailDeepLinkHandlerFactory(
|
||||
impl: DefaultMarketsTokenDetailDeepLinkHandler.Factory,
|
||||
): MarketsTokenDetailDeepLinkHandler.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMarketsTokenExchangesDeepLinkHandlerFactory(
|
||||
impl: DefaultMarketsTokenExchangesDeepLinkHandler.Factory,
|
||||
): MarketsTokenExchangesDeepLinkHandler.Factory
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import arrow.core.Either
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.TangemSiteShareUrlBuilder
|
||||
import com.tangem.domain.markets.PreselectedTokenDetailsSection
|
||||
import com.tangem.common.ui.charts.state.MarketChartData
|
||||
import com.tangem.common.ui.charts.state.MarketChartDataProducer
|
||||
import com.tangem.common.ui.charts.state.sorted
|
||||
|
|
@ -21,6 +22,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
|
|
@ -95,6 +97,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
|
||||
private val quotesJob = JobHolder()
|
||||
private var userCountry: UserCountry? = null
|
||||
private var isScrollToSectionHandled = false
|
||||
private val params = paramsContainer.require<DefaultMarketsTokenDetailsComponent.Params>()
|
||||
private val analyticsEventBuilder = MarketDetailsAnalyticsEvent.EventBuilder(token = params.token)
|
||||
|
||||
|
|
@ -297,6 +300,15 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
|
||||
initialLoad()
|
||||
loadRelatedNews()
|
||||
|
||||
if (params.shouldOpenExchanges) {
|
||||
modelScope.launch {
|
||||
val exchangesCount = params.exchangesCount
|
||||
?: currentTokenInfo.value?.exchangesAmount
|
||||
?: 0
|
||||
onListedOnClick(exchangesCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initialLoad() {
|
||||
|
|
@ -519,6 +531,14 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
description = descriptionConverter.convert(newInfo),
|
||||
infoBlocks = infoConverter.convert(newInfo),
|
||||
),
|
||||
scrollToSection = if (!isScrollToSectionHandled) {
|
||||
mapSectionToKey(params.preselectedSection)?.let { key ->
|
||||
isScrollToSectionHandled = true
|
||||
triggeredEvent(data = key, onConsume = ::consumeScrollToSection)
|
||||
} ?: consumedEvent()
|
||||
} else {
|
||||
marketsTokenDetailsUM.scrollToSection
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -755,6 +775,17 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun mapSectionToKey(section: PreselectedTokenDetailsSection?): String? {
|
||||
return when (section) {
|
||||
PreselectedTokenDetailsSection.News -> MarketsTokenDetailsUM.RelatedNews.SECTION_KEY
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun consumeScrollToSection() {
|
||||
state.update { it.copy(scrollToSection = consumedEvent()) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val QUOTES_UPDATE_INTERVAL_MILLIS = 60000L
|
||||
const val RELATED_NEWS_LIMIT = 10
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ internal class MarketsListModel @Inject constructor(
|
|||
onShowTokensUnder100kClicked = { analyticsEventHandler.send(MarketsListAnalyticsEvent.ShowTokens()) },
|
||||
shouldAlwaysShowSearchBar = Provider { modelParams.params.shouldAlwaysShowSearchBar },
|
||||
preselectedSortType = Provider { modelParams.params.preselectedSortType },
|
||||
preselectedInterval = Provider { modelParams.params.preselectedInterval },
|
||||
onBackClick = modelParams.clickIntents.onBackClicked,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
onSearchBarClick = modelParams.clickIntents.onSearchClicked,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ internal class MarketsListUMStateManager(
|
|||
private val shouldAlwaysShowSearchBar: Provider<Boolean>,
|
||||
private val currentVisibleIds: Provider<List<CryptoCurrency.RawID>>,
|
||||
private val preselectedSortType: Provider<SortByTypeUM>,
|
||||
private val preselectedInterval: Provider<MarketsListUM.TrendInterval>,
|
||||
private val onLoadMoreUiItems: () -> Unit,
|
||||
private val visibleItemsChanged: (itemsKeys: List<CryptoCurrency.RawID>) -> Unit,
|
||||
private val onRetryButtonClicked: () -> Unit,
|
||||
|
|
@ -229,7 +230,7 @@ internal class MarketsListUMStateManager(
|
|||
shouldAlwaysShowSearchBar = shouldAlwaysShowSearchBar(),
|
||||
),
|
||||
selectedSortBy = preselectedSortType(),
|
||||
selectedInterval = MarketsListUM.TrendInterval.H24,
|
||||
selectedInterval = preselectedInterval(),
|
||||
onIntervalClick = { selectedInterval = it },
|
||||
onSortByButtonClick = { isSortByBottomSheetShown = true },
|
||||
sortByBottomSheet = TangemBottomSheetConfig(
|
||||
|
|
|
|||
|
|
@ -106,6 +106,13 @@ private fun Content(
|
|||
lazyListState = lazyListState,
|
||||
onShouldShowPriceSubtitleChange = state.onShouldShowPriceSubtitleChange,
|
||||
)
|
||||
EventEffect(state.scrollToSection) { targetKey ->
|
||||
val targetIndex = lazyListState.layoutInfo.visibleItemsInfo
|
||||
.firstOrNull { it.key == targetKey }?.index
|
||||
if (targetIndex != null) {
|
||||
lazyListState.animateScrollToItem(targetIndex)
|
||||
}
|
||||
}
|
||||
var bottomSpacing by remember { mutableStateOf(0.dp) }
|
||||
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ private fun LazyListScope.tokenMarketDetailsBodyV1(
|
|||
|
||||
if (relatedNews.articles.isNotEmpty()) {
|
||||
relatedNews(relatedNews)
|
||||
} else {
|
||||
sectionStub(RelatedNews.SECTION_KEY)
|
||||
}
|
||||
|
||||
aboutCoinHeader()
|
||||
|
|
@ -91,6 +93,11 @@ private fun LazyListScope.tokenMarketDetailsBodyV1(
|
|||
}
|
||||
}
|
||||
|
||||
// Empty item with a key so that deeplink scroll-to-section can target it before the real content is composed
|
||||
private fun LazyListScope.sectionStub(key: String) {
|
||||
item(key) { }
|
||||
}
|
||||
|
||||
@Suppress("CanBeNonNullable")
|
||||
private fun LazyListScope.tokenMarketDetailsBodyV2(state: MarketsTokenDetailsUM.Body, relatedNews: RelatedNews) {
|
||||
when (state) {
|
||||
|
|
@ -244,6 +251,8 @@ internal fun LazyListScope.infoBlocksListV2(state: MarketsTokenDetailsUM.Informa
|
|||
|
||||
if (relatedNews.articles.isNotEmpty()) {
|
||||
relatedNews(relatedNews)
|
||||
} else {
|
||||
sectionStub(RelatedNews.SECTION_KEY)
|
||||
}
|
||||
|
||||
if (state.securityScore != null) {
|
||||
|
|
@ -324,7 +333,7 @@ private fun LazyListScope.loadingInfoBlocksV2() {
|
|||
}
|
||||
|
||||
private fun LazyListScope.relatedNews(relatedNews: RelatedNews) {
|
||||
item("related-news") {
|
||||
item(RelatedNews.SECTION_KEY) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.common.ui.charts.state.MarketChartDataProducer
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.markets.PriceChangeInterval
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ArticleConfigUM
|
||||
|
|
@ -30,6 +31,7 @@ internal data class MarketsTokenDetailsUM(
|
|||
val onShouldShowPriceSubtitleChange: (Boolean) -> Unit,
|
||||
val relatedNews: RelatedNews,
|
||||
val onShareClick: () -> Unit,
|
||||
val scrollToSection: StateEvent<String> = consumedEvent(),
|
||||
) {
|
||||
|
||||
data class ChartState(
|
||||
|
|
@ -80,5 +82,9 @@ internal data class MarketsTokenDetailsUM(
|
|||
val onArticledClicked: (id: Int) -> Unit,
|
||||
val onFirstVisible: () -> Unit,
|
||||
val onScroll: () -> Unit,
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
const val SECTION_KEY = "related-news"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue