Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-01 08:16:56 +02:00
parent 4ff20f3479
commit 0c5ff2eb37
14 changed files with 400 additions and 123 deletions

View file

@ -86,14 +86,6 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
innerRouter.push(
route = FeedEntryChildFactory.Child.TokenList(
params = DefaultMarketsTokenListComponent.Params(
onBackClicked = { onChildBack() },
onTokenClick = { token, currency ->
onMarketItemClick(
token = token,
appCurrency = currency,
source = AnalyticsParam.ScreensSources.Market.value,
)
},
preselectedSortType = sortBy ?: SortByTypeUM.Rating,
shouldAlwaysShowSearchBar = sortBy == null,
),
@ -243,14 +235,6 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
)
FeedEntryRoute.MarketTokenList -> FeedEntryChildFactory.Child.TokenList(
DefaultMarketsTokenListComponent.Params(
onBackClicked = { router.pop() },
onTokenClick = { token, currency ->
clickIntents.onMarketItemClick(
token = token,
appCurrency = currency,
source = AnalyticsParam.ScreensSources.Market.value,
)
},
preselectedSortType = SortByTypeUM.Rating,
shouldAlwaysShowSearchBar = false,
),

View file

@ -63,6 +63,7 @@ internal class FeedEntryChildFactory @Inject constructor(
data object Search : Child
}
@Suppress("LongMethod")
fun createChild(
child: Child,
appComponentContext: AppComponentContext,
@ -82,6 +83,17 @@ internal class FeedEntryChildFactory @Inject constructor(
DefaultMarketsTokenListComponent(
appComponentContext = appComponentContext,
params = child.params,
clickIntents = DefaultMarketsTokenListComponent.ClickIntents(
onBackClicked = onBackClicked,
onSearchClicked = feedEntryClickIntents::openSearch,
onTokenClick = { token, currency ->
feedEntryClickIntents.onMarketItemClick(
token = token,
appCurrency = currency,
source = AnalyticsParam.ScreensSources.Market.value,
)
},
),
)
}
is Child.NewsDetails -> {

View file

@ -1,20 +1,34 @@
package com.tangem.features.feed.components.market.list
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.R
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
import com.tangem.core.ui.extensions.clickableSingle
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.LocalRedesignEnabled
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.SortByTypeUM
import com.tangem.features.feed.ui.components.FeedSearchBar
import com.tangem.features.feed.ui.market.list.MarketsList
import com.tangem.features.feed.ui.market.list.TopBarWithSearch
import kotlinx.serialization.Serializable
@ -22,20 +36,54 @@ import kotlinx.serialization.Serializable
internal class DefaultMarketsTokenListComponent(
appComponentContext: AppComponentContext,
private val params: Params,
private val clickIntents: ClickIntents,
) : ComposableModularBottomSheetContentComponent, AppComponentContext by appComponentContext {
private val model: MarketsListModel = getOrCreateModel<MarketsListModel, Params>(params = params)
private val model: MarketsListModel = getOrCreateModel<MarketsListModel, ModelParams>(
params = ModelParams(
params = params,
clickIntents = clickIntents,
),
)
@Composable
override fun Title(bottomSheetState: State<BottomSheetState>) {
val state by model.state.collectAsStateWithLifecycle()
val bsState by bottomSheetState
TopBarWithSearch(
onBackClick = params.onBackClicked,
onSearchClick = state.onSearchClicked,
marketsSearchBar = state.marketsSearchBar,
bottomSheetState = bsState,
)
val background = LocalMainBottomSheetColor.current.value
if (LocalRedesignEnabled.current) {
FeedSearchBar(
isSearchBarClickable = bottomSheetState.value == BottomSheetState.EXPANDED,
feedListSearchBar = state.feedListSearchBar,
modifier = Modifier.drawBehind { drawRect(background) },
startContent = {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_arrow_back_28),
contentDescription = null,
tint = TangemTheme.colors2.graphic.neutral.primary,
modifier = Modifier
.size(TangemTheme.dimens2.x11)
.background(
color = TangemTheme.colors2.button.backgroundSecondary,
shape = CircleShape,
)
.clickableSingle(
onClick = clickIntents.onBackClicked,
enabled = bottomSheetState.value == BottomSheetState.EXPANDED,
)
.padding(TangemTheme.dimens2.x2),
)
},
)
} else {
TopBarWithSearch(
onBackClick = clickIntents.onBackClicked,
onSearchClick = state.onSearchClicked,
marketsSearchBar = state.marketsSearchBar,
bottomSheetState = bsState,
)
}
}
@Composable
@ -62,9 +110,18 @@ internal class DefaultMarketsTokenListComponent(
@Serializable
data class Params(
val onBackClicked: () -> Unit,
val onTokenClick: ((TokenMarketParams, AppCurrency) -> Unit),
val preselectedSortType: SortByTypeUM,
val shouldAlwaysShowSearchBar: Boolean,
)
data class ClickIntents(
val onBackClicked: () -> Unit,
val onSearchClicked: () -> Unit,
val onTokenClick: ((TokenMarketParams, AppCurrency) -> Unit),
)
data class ModelParams(
val params: Params,
val clickIntents: ClickIntents,
)
}

View file

@ -45,7 +45,7 @@ internal class MarketsListModel @Inject constructor(
private val updateQuotesJob = JobHolder()
private val params = paramsContainer.require<DefaultMarketsTokenListComponent.Params>()
private val modelParams = paramsContainer.require<DefaultMarketsTokenListComponent.ModelParams>()
private val currentAppCurrency = getSelectedAppCurrencyUseCase().map { maybeAppCurrency ->
maybeAppCurrency.getOrElse { AppCurrency.Default }
@ -65,10 +65,11 @@ internal class MarketsListModel @Inject constructor(
onRetryButtonClicked = { activeListManager.reload() },
onTokenClick = { onTokenUIClicked(it) },
onShowTokensUnder100kClicked = { analyticsEventHandler.send(MarketsListAnalyticsEvent.ShowTokens()) },
shouldAlwaysShowSearchBar = Provider { params.shouldAlwaysShowSearchBar },
preselectedSortType = Provider { params.preselectedSortType },
onBackClick = params.onBackClicked,
shouldAlwaysShowSearchBar = Provider { modelParams.params.shouldAlwaysShowSearchBar },
preselectedSortType = Provider { modelParams.params.preselectedSortType },
onBackClick = modelParams.clickIntents.onBackClicked,
analyticsEventHandler = analyticsEventHandler,
onSearchBarClick = modelParams.clickIntents.onSearchClicked,
)
}
@ -261,7 +262,7 @@ internal class MarketsListModel @Inject constructor(
private fun onTokenUIClicked(token: MarketsListItemUM) {
modelScope.launch {
activeListManager.getTokenById(token.id)?.let { found ->
params.onTokenClick(found.toSerializableParam(), currentAppCurrency.value)
modelParams.clickIntents.onTokenClick(found.toSerializableParam(), currentAppCurrency.value)
}
}
}

View file

@ -9,6 +9,7 @@ import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
import kotlinx.collections.immutable.ImmutableList
internal data class MarketsListUM(
@ -20,6 +21,8 @@ internal data class MarketsListUM(
val onIntervalClick: (TrendInterval) -> Unit,
val onSortByButtonClick: () -> Unit,
val onSearchClicked: () -> Unit,
val feedListSearchBar: FeedListSearchBar,
val sortByMenuUM: SortByMenuUM,
) {
val isInSearchMode
get() = marketsSearchBar.searchBarUM.query.isNotEmpty()

View file

@ -0,0 +1,6 @@
package com.tangem.features.feed.model.market.list.state
internal data class SortByMenuUM(
val selectedOption: SortByTypeUM,
val onOptionClicked: (SortByTypeUM) -> Unit,
)

View file

@ -12,6 +12,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.feed.impl.R
import com.tangem.features.feed.model.feed.analytics.FeedAnalyticsEvent
import com.tangem.features.feed.model.market.list.state.*
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@ -33,6 +34,7 @@ internal class MarketsListUMStateManager(
private val onShowTokensUnder100kClicked: () -> Unit,
private val onBackClick: () -> Unit,
private val analyticsEventHandler: AnalyticsEventHandler,
private val onSearchBarClick: () -> Unit,
) {
val state = MutableStateFlow(state())
@ -64,6 +66,9 @@ internal class MarketsListUMStateManager(
selectedOption = value,
),
),
sortByMenuUM = marketsListUM.sortByMenuUM.copy(
selectedOption = value,
),
list = if (marketsListUM.list is ListUM.Content && marketsListUM.selectedSortBy != value) {
marketsListUM.list.copy(
triggerScrollReset = triggeredEvent(Unit) { consumeTriggerResetScrollEvent() },
@ -232,16 +237,24 @@ internal class MarketsListUMStateManager(
onDismissRequest = { isSortByBottomSheetShown = false },
content = SortByBottomSheetContentUM(
selectedOption = preselectedSortType(),
onOptionClicked = ::onBottomSheetOptionClicked,
onOptionClicked = ::onBottomSheetOrMenuOptionClicked,
),
),
onSearchClicked = {
analyticsEventHandler.send(FeedAnalyticsEvent.TokenSearchedClicked())
changeSearchBarIsActive(true)
},
feedListSearchBar = FeedListSearchBar(
onBarClick = onSearchBarClick,
placeholderText = resourceReference(id = R.string.markets_search_title_placeholder),
),
sortByMenuUM = SortByMenuUM(
selectedOption = preselectedSortType(),
onOptionClicked = ::onBottomSheetOrMenuOptionClicked,
),
)
private fun onBottomSheetOptionClicked(sortByTypeUM: SortByTypeUM) {
private fun onBottomSheetOrMenuOptionClicked(sortByTypeUM: SortByTypeUM) {
state.update { marketsListUM ->
marketsListUM.copy(
selectedSortBy = sortByTypeUM,
@ -251,6 +264,7 @@ internal class MarketsListUMStateManager(
selectedOption = sortByTypeUM,
),
),
sortByMenuUM = marketsListUM.sortByMenuUM.copy(selectedOption = sortByTypeUM),
)
}
}

View file

@ -111,20 +111,23 @@ private fun InsightsBlockV1(state: InsightsUM, modifier: Modifier = Modifier) {
@Composable
private fun InsightsBlockV2(state: InsightsUM, modifier: Modifier = Modifier) {
val segmentItems = persistentListOf(
TangemSegmentUM(
id = PriceChangeInterval.H24.name,
title = resourceReference(R.string.markets_token_details_insight_day_timeline),
),
TangemSegmentUM(
id = PriceChangeInterval.WEEK.name,
title = resourceReference(R.string.markets_token_details_insight_week_timeline),
),
TangemSegmentUM(
id = PriceChangeInterval.MONTH.name,
title = resourceReference(R.string.markets_token_details_insight_month_timeline),
),
)
val segmentItems = remember {
persistentListOf(
TangemSegmentUM(
id = PriceChangeInterval.H24.name,
title = resourceReference(R.string.markets_token_details_insight_day_timeline),
),
TangemSegmentUM(
id = PriceChangeInterval.WEEK.name,
title = resourceReference(R.string.markets_token_details_insight_week_timeline),
),
TangemSegmentUM(
id = PriceChangeInterval.MONTH.name,
title = resourceReference(R.string.markets_token_details_insight_month_timeline),
),
)
}
var currentInterval by remember { mutableStateOf(segmentItems.first()) }
TokenMarketInformationBlock(

View file

@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester
@ -24,27 +23,27 @@ import com.tangem.core.ui.components.SpacerH8
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.conditionalCompose
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.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.feed.impl.R
import com.tangem.features.feed.model.market.list.state.*
import com.tangem.features.feed.ui.feed.state.FeedListSearchBar
import com.tangem.features.feed.ui.market.list.components.MarketsListLazyColumn
import com.tangem.features.feed.ui.market.list.components.MarketsListSortByBottomSheet
import kotlinx.collections.immutable.persistentListOf
import com.tangem.features.feed.ui.market.list.components.Options
import dev.chrisbanes.haze.rememberHazeState
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.delay
@ -123,7 +122,16 @@ internal fun MarketsList(state: MarketsListUM, modifier: Modifier = Modifier) {
@Suppress("LongMethod")
@Composable
private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modifier) {
val strokeColor = TangemTheme.colors.stroke.primary
val isRedesignEnabled = LocalRedesignEnabled.current
val hazeState = rememberHazeState()
val strokeColor = if (isRedesignEnabled) {
TangemTheme.colors2.border.neutral.primary
} else {
TangemTheme.colors.stroke.primary
}
val scrolledState = remember { mutableStateOf(false) }
Column(modifier.padding(horizontal = TangemTheme.dimens.size16)) {
@ -145,11 +153,19 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
Column {
AnimatedVisibility(!state.isInSearchMode && !state.marketsSearchBar.shouldAlwaysShowSearchBar) {
Options(
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
modifier = Modifier.padding(
bottom = if (isRedesignEnabled) {
TangemTheme.dimens2.x2
} else {
TangemTheme.dimens.spacing12
},
),
sortByTypeUM = state.selectedSortBy,
trendInterval = state.selectedInterval,
onIntervalClick = state.onIntervalClick,
onSortByClick = state.onSortByButtonClick,
sortMenuUM = state.sortByMenuUM,
hazeState = hazeState,
)
}
}
@ -172,65 +188,18 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
},
)
ItemsList(
modifier = Modifier.conditionalCompose(
condition = isRedesignEnabled,
modifier = {
hazeSourceTangem(zIndex = 0f, state = hazeState)
},
),
scrolledState = scrolledState,
isInSearchMode = state.isInSearchMode,
state = state.list,
)
}
@Composable
private fun Options(
sortByTypeUM: SortByTypeUM,
trendInterval: MarketsListUM.TrendInterval,
onSortByClick: () -> Unit,
onIntervalClick: (MarketsListUM.TrendInterval) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.height(IntrinsicSize.Max)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
SecondarySmallButton(
config = SmallButtonConfig(
text = sortByTypeUM.text,
onClick = onSortByClick,
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_chevron_24),
),
)
SegmentedButtons(
config = persistentListOf(
MarketsListUM.TrendInterval.H24,
MarketsListUM.TrendInterval.D7,
MarketsListUM.TrendInterval.M1,
),
color = TangemTheme.colors.button.secondary,
initialSelectedItem = trendInterval,
onClick = onIntervalClick,
modifier = Modifier
.width(160.dp)
.fillMaxHeight(),
) {
Box(
Modifier
.fillMaxSize()
.align(Alignment.Center)
.padding(
vertical = TangemTheme.dimens.spacing4,
),
) {
Text(
modifier = Modifier.align(Alignment.Center),
text = it.text.resolveReference(),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.primary1,
)
}
}
}
}
@Composable
private fun ItemsList(
scrolledState: MutableState<Boolean>,
@ -343,6 +312,14 @@ private fun Preview() {
content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {},
),
onSearchClicked = {},
feedListSearchBar = FeedListSearchBar(
onBarClick = {},
placeholderText = resourceReference(id = R.string.markets_search_title_placeholder),
),
sortByMenuUM = SortByMenuUM(
selectedOption = SortByTypeUM.Rating,
onOptionClicked = {},
),
),
)
}

View file

@ -3,7 +3,7 @@ package com.tangem.features.feed.ui.market.list.components
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
import androidx.compose.runtime.*
@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.markets.MarketsListItem
import com.tangem.common.ui.markets.MarketsListItemPlaceholder
import com.tangem.common.ui.markets.models.MarketsListItemUM.Companion.TOKEN_LAZY_LIST_ID_SEPARATOR
@ -19,9 +20,12 @@ import com.tangem.core.ui.components.UnableToLoadData
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.list.InfiniteListHandler
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.conditionalCompose
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.MarketsTestTags
import com.tangem.domain.models.currency.CryptoCurrency
@ -40,6 +44,7 @@ internal fun MarketsListLazyColumn(
lazyListState: LazyListState,
modifier: Modifier = Modifier,
) {
val isRedesignEnabled = LocalRedesignEnabled.current
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
val coroutineScope = rememberCoroutineScope()
@ -93,11 +98,22 @@ internal fun MarketsListLazyColumn(
}
}
is ListUM.Content -> {
items(
itemsIndexed(
items = state.items,
key = { it.getComposeKey() },
) { item ->
key = { _, item -> item.getComposeKey() },
) { index, item ->
MarketsListItem(
modifier = Modifier.conditionalCompose(
condition = isRedesignEnabled,
modifier = {
roundedShapeItemDecoration(
currentIndex = index,
lastIndex = state.items.lastIndex,
backgroundColor = TangemTheme.colors2.surface.level3,
radius = TangemTheme.dimens2.x5,
)
},
),
model = item,
onClick = { state.onItemClick(item) },
)
@ -144,8 +160,8 @@ private fun LoadingErrorItem(onTryAgain: () -> Unit, modifier: Modifier = Modifi
Box(
modifier
.padding(
horizontal = TangemTheme.dimens.spacing16,
vertical = TangemTheme.dimens.spacing12,
horizontal = 16.dp,
vertical = 12.dp,
)
.fillMaxWidth(),
contentAlignment = Alignment.Center,

View file

@ -0,0 +1,176 @@
package com.tangem.features.feed.ui.market.list.components
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
import com.tangem.core.ui.components.haze.hazeEffectTangem
import com.tangem.core.ui.ds.button.PrimaryInverseTangemButton
import com.tangem.core.ui.ds.button.TangemButtonShape
import com.tangem.core.ui.ds.button.TangemButtonSize
import com.tangem.core.ui.ds.tabs.TangemSegmentUM
import com.tangem.core.ui.ds.tabs.TangemSegmentedPicker
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.feed.impl.R
import com.tangem.features.feed.model.market.list.state.MarketsListUM
import com.tangem.features.feed.model.market.list.state.SortByMenuUM
import com.tangem.features.feed.model.market.list.state.SortByTypeUM
import dev.chrisbanes.haze.HazeState
import kotlinx.collections.immutable.persistentListOf
import com.tangem.core.ui.ds.button.TangemButtonIconPosition as RedesignTangemButtonIconPosition
@Suppress("LongParameterList")
@Composable
internal fun Options(
sortMenuUM: SortByMenuUM,
sortByTypeUM: SortByTypeUM,
trendInterval: MarketsListUM.TrendInterval,
hazeState: HazeState,
onSortByClick: () -> Unit,
onIntervalClick: (MarketsListUM.TrendInterval) -> Unit,
modifier: Modifier = Modifier,
) {
if (LocalRedesignEnabled.current) {
OptionsV2(
sortMenuUM = sortMenuUM,
trendInterval = trendInterval,
onIntervalClick = onIntervalClick,
modifier = modifier,
hazeState = hazeState,
)
} else {
OptionsV1(
sortByTypeUM = sortByTypeUM,
trendInterval = trendInterval,
onSortByClick = onSortByClick,
onIntervalClick = onIntervalClick,
modifier = modifier,
)
}
}
@Composable
private fun OptionsV1(
sortByTypeUM: SortByTypeUM,
trendInterval: MarketsListUM.TrendInterval,
onSortByClick: () -> Unit,
onIntervalClick: (MarketsListUM.TrendInterval) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.height(IntrinsicSize.Max)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
SecondarySmallButton(
config = SmallButtonConfig(
text = sortByTypeUM.text,
onClick = onSortByClick,
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_chevron_24),
),
)
SegmentedButtons(
config = persistentListOf(
MarketsListUM.TrendInterval.H24,
MarketsListUM.TrendInterval.D7,
MarketsListUM.TrendInterval.M1,
),
color = TangemTheme.colors.button.secondary,
initialSelectedItem = trendInterval,
onClick = onIntervalClick,
modifier = Modifier
.width(160.dp)
.fillMaxHeight(),
) {
Box(
Modifier
.fillMaxSize()
.align(Alignment.Center)
.padding(
vertical = TangemTheme.dimens.spacing4,
),
) {
Text(
modifier = Modifier.align(Alignment.Center),
text = it.text.resolveReference(),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.primary1,
)
}
}
}
}
@Composable
private fun OptionsV2(
sortMenuUM: SortByMenuUM,
trendInterval: MarketsListUM.TrendInterval,
hazeState: HazeState,
onIntervalClick: (MarketsListUM.TrendInterval) -> Unit,
modifier: Modifier = Modifier,
) {
var isShowDropdownMenu by rememberSaveable { mutableStateOf(false) }
val segmentItems = remember {
persistentListOf(
TangemSegmentUM(
id = MarketsListUM.TrendInterval.H24.name,
title = MarketsListUM.TrendInterval.H24.text,
),
TangemSegmentUM(
id = MarketsListUM.TrendInterval.D7.name,
title = MarketsListUM.TrendInterval.D7.text,
),
TangemSegmentUM(
id = MarketsListUM.TrendInterval.M1.name,
title = MarketsListUM.TrendInterval.M1.text,
),
)
}
Row(
modifier = modifier
.height(IntrinsicSize.Max)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
PrimaryInverseTangemButton(
onClick = {
isShowDropdownMenu = true
},
iconPosition = RedesignTangemButtonIconPosition.End,
iconRes = R.drawable.ic_chewron_down_20,
text = sortMenuUM.selectedOption.text,
size = TangemButtonSize.X9,
shape = TangemButtonShape.Rounded,
)
TangemSegmentedPicker(
items = segmentItems,
initialSelectedItem = segmentItems.firstOrNull { it.id == trendInterval.name },
isFixed = false,
isAltSurface = true,
minSegmentWidth = 54.dp,
onClick = { segment -> onIntervalClick(MarketsListUM.TrendInterval.valueOf(segment.id)) },
)
}
SortByMenu(
sortMenuUM = sortMenuUM,
showDropdownMenu = isShowDropdownMenu,
onDropdownDismiss = { isShowDropdownMenu = false },
modifier = Modifier.hazeEffectTangem(hazeState) {
blurRadius = 10.dp
},
)
}

View file

@ -0,0 +1,36 @@
package com.tangem.features.feed.ui.market.list.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.util.fastForEach
import com.tangem.core.ui.ds.contextmenu.TangemContextMenu
import com.tangem.core.ui.ds.contextmenu.TangemContextMenuCheckboxItem
import com.tangem.features.feed.model.market.list.state.SortByMenuUM
import com.tangem.features.feed.model.market.list.state.SortByTypeUM
@Composable
internal fun SortByMenu(
sortMenuUM: SortByMenuUM,
showDropdownMenu: Boolean,
onDropdownDismiss: () -> Unit,
modifier: Modifier = Modifier,
) {
TangemContextMenu(
expanded = showDropdownMenu,
onDismissRequest = onDropdownDismiss,
offset = DpOffset.Zero,
modifier = modifier,
) {
SortByTypeUM.entries.fastForEach { sortType ->
TangemContextMenuCheckboxItem(
title = sortType.text,
isChecked = sortMenuUM.selectedOption == sortType,
onClick = {
sortMenuUM.onOptionClicked(sortType)
onDropdownDismiss()
},
)
}
}
}

View file

@ -13,11 +13,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.UnableToLoadData
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.components.pager.PagerIndicator
import com.tangem.core.ui.ds.TangemPagerIndicator
import com.tangem.core.ui.ds.TangemPagerIndicatorColors
import com.tangem.core.ui.extensions.conditionalCompose
import com.tangem.core.ui.res.*
import com.tangem.features.feed.ui.news.details.components.ArticleDetail
import com.tangem.features.feed.ui.news.details.components.NewsDetailsPlaceholder
@ -84,12 +82,6 @@ private fun Content(state: NewsDetailsUM, background: Color) {
Column(
modifier = Modifier
.fillMaxSize()
.conditionalCompose(
condition = isRedesignEnabled,
modifier = {
hazeSourceTangem(zIndex = 1f)
},
)
.background(background),
) {
Box(modifier = Modifier.fillMaxSize()) {