diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt index 751a37c088..dc5221c182 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt @@ -144,7 +144,7 @@ private fun ButtonContent( ) { Column { AnimatedVisibility(text != null) { - val wrappedText = remember(this) { text.orEmpty() } + val wrappedText = remember(this, text) { text.orEmpty() } val textStyle = size.toTextStyle() Text( text = wrappedText.resolveReference(), 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 2576b72a84..48d74bc9f4 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 @@ -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, ), 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 b4dd71046e..752b079b3f 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 @@ -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 -> { diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/list/DefaultMarketsTokenListComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/list/DefaultMarketsTokenListComponent.kt index c4c3190a5a..81f649ec89 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/list/DefaultMarketsTokenListComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/list/DefaultMarketsTokenListComponent.kt @@ -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(params = params) + private val model: MarketsListModel = getOrCreateModel( + params = ModelParams( + params = params, + clickIntents = clickIntents, + ), + ) @Composable override fun Title(bottomSheetState: State) { 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, + ) } \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/MarketsListModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/MarketsListModel.kt index bf202960d8..11a933c2f1 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/MarketsListModel.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/MarketsListModel.kt @@ -45,7 +45,7 @@ internal class MarketsListModel @Inject constructor( private val updateQuotesJob = JobHolder() - private val params = paramsContainer.require() + private val modelParams = paramsContainer.require() 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) } } } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/MarketsListUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/MarketsListUM.kt index c3b5d75360..a68a6bfcef 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/MarketsListUM.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/MarketsListUM.kt @@ -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() diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/SortByMenuUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/SortByMenuUM.kt new file mode 100644 index 0000000000..0cdbbcb451 --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/state/SortByMenuUM.kt @@ -0,0 +1,6 @@ +package com.tangem.features.feed.model.market.list.state + +internal data class SortByMenuUM( + val selectedOption: SortByTypeUM, + val onOptionClicked: (SortByTypeUM) -> Unit, +) \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/statemanager/MarketsListUMStateManager.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/statemanager/MarketsListUMStateManager.kt index 48d95edb99..fe1b3b15a1 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/statemanager/MarketsListUMStateManager.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/market/list/statemanager/MarketsListUMStateManager.kt @@ -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), ) } } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/InsightsBlock.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/InsightsBlock.kt index 30fd5eda07..18c97a1f39 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/InsightsBlock.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/InsightsBlock.kt @@ -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( diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/MarketsList.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/MarketsList.kt index dc00b05e46..8a1330df5d 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/MarketsList.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/MarketsList.kt @@ -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, @@ -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 = {}, + ), ), ) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/MarketsListLazyColumn.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/MarketsListLazyColumn.kt index 917bd83e8c..3f7a0fccf5 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/MarketsListLazyColumn.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/MarketsListLazyColumn.kt @@ -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, diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/Options.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/Options.kt new file mode 100644 index 0000000000..c8e073eb9c --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/Options.kt @@ -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 + }, + ) +} \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/SortByMenu.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/SortByMenu.kt new file mode 100644 index 0000000000..559240a0ca --- /dev/null +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/list/components/SortByMenu.kt @@ -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() + }, + ) + } + } +} \ No newline at end of file diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/news/details/NewsDetailsContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/news/details/NewsDetailsContent.kt index 87ee61acdf..e592094a1a 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/news/details/NewsDetailsContent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/news/details/NewsDetailsContent.kt @@ -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()) {