Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-19 14:08:10 +01:00
parent 27fd5458d1
commit 6b9aacb1ea
18 changed files with 235 additions and 132 deletions

View file

@ -1,6 +1,7 @@
package com.tangem.common.ui.news
import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@ -12,6 +13,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@ -100,6 +103,41 @@ private fun TrendingArticle(articleConfigUM: ArticleConfigUM) {
}
}
@Composable
fun ShowMoreArticlesCard(modifier: Modifier = Modifier, onClick: () -> Unit) {
BlockCard(
modifier = modifier,
onClick = onClick,
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(vertical = 31.dp, horizontal = 12.dp),
) {
Image(
imageVector = ImageVector.vectorResource(R.drawable.ic_show_more_news_48),
contentDescription = stringResourceSafe(R.string.common_show_more),
)
SpacerH(16.dp)
Text(
text = stringResourceSafe(R.string.news_all_news),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
Text(
text = stringResourceSafe(R.string.news_stay_in_the_loop),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
}
}
}
@Composable
private fun DefaultArticle(articleConfigUM: ArticleConfigUM) {
Column(modifier = Modifier.padding(12.dp)) {

View file

@ -10,9 +10,8 @@ import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
@ -51,16 +50,22 @@ fun SearchBar(
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val interactionSource = remember { MutableInteractionSource() }
var isInitialComposition by rememberSaveable { mutableStateOf(true) }
LaunchedEffect(Unit) {
isInitialComposition = false
}
BasicTextField(
modifier = modifier
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size48)
.onFocusChanged { focusState ->
if (focusState.isFocused) {
state.onActiveChange(true)
} else {
state.onActiveChange(false)
if (!isInitialComposition) {
if (focusState.isFocused) {
state.onActiveChange(true)
} else {
state.onActiveChange(false)
}
}
}
.focusRequester(focusRequester)
@ -163,6 +168,7 @@ private fun ClearButton(
focusManager.clearFocus()
keyboardController?.hide()
state.onActiveChange(false)
state.onClearClick()
},
) {
Icon(

View file

@ -8,4 +8,5 @@ data class SearchBarUM(
val onQueryChange: (String) -> Unit,
val isActive: Boolean,
val onActiveChange: (Boolean) -> Unit,
val onClearClick: () -> Unit = {},
)

View file

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<group>
<clip-path
android:pathData="M24,0L24,0A24,24 0,0 1,48 24L48,24A24,24 0,0 1,24 48L24,48A24,24 0,0 1,0 24L0,24A24,24 0,0 1,24 0z"/>
<path
android:pathData="M24,0L24,0A24,24 0,0 1,48 24L48,24A24,24 0,0 1,24 48L24,48A24,24 0,0 1,0 24L0,24A24,24 0,0 1,24 0z"
android:strokeAlpha="0.1"
android:fillColor="#0099FF"
android:fillAlpha="0.1"/>
<path
android:pathData="M15.782,24.005C15.781,23.508 16.184,23.105 16.681,23.104L29.128,23.099L23.92,17.891C23.569,17.539 23.569,16.97 23.92,16.618C24.272,16.267 24.842,16.267 25.193,16.618L31.943,23.368C32.295,23.72 32.295,24.289 31.943,24.641L25.193,31.391C24.842,31.742 24.272,31.742 23.92,31.391C23.569,31.039 23.569,30.47 23.92,30.118L29.139,24.899L16.682,24.904C16.185,24.905 15.782,24.502 15.782,24.005Z"
android:fillColor="#0099FF"/>
</group>
</vector>

View file

@ -60,14 +60,14 @@ internal class DefaultFeedEntryComponent @AssistedInject constructor(
)
}
override fun onMarketOpenClick(sortBy: SortByTypeUM) {
override fun onMarketOpenClick(sortBy: SortByTypeUM?) {
innerRouter.push(
route = FeedEntryChildFactory.Child.TokenList(
params = DefaultMarketsTokenListComponent.Params(
onBackClicked = { onChildBack() },
onTokenClick = { token, currency -> onMarketItemClick(token, currency) },
preselectedSortType = sortBy,
shouldAlwaysShowSearchBar = sortBy == SortByTypeUM.Rating,
preselectedSortType = sortBy ?: SortByTypeUM.Rating,
shouldAlwaysShowSearchBar = sortBy == null,
),
),
)

View file

@ -23,7 +23,7 @@ internal class DefaultFeedComponent(
@Composable
override fun Title() {
val state by feedComponentModel.state.collectAsStateWithLifecycle()
FeedListHeader(state.searchBar)
FeedListHeader(state.feedListSearchBar)
}
@Composable

View file

@ -26,7 +26,11 @@ internal class DefaultMarketsTokenListComponent(
@Composable
override fun Title() {
val state by model.state.collectAsStateWithLifecycle()
TopBarWithSearch(state.searchBar)
TopBarWithSearch(
onBackClick = params.onBackClicked,
onSearchClick = state.onSearchClicked,
marketsSearchBar = state.marketsSearchBar,
)
}
@Composable

View file

@ -5,7 +5,6 @@ import arrow.core.getOrElse
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@ -31,7 +30,6 @@ import kotlinx.coroutines.launch
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import javax.inject.Inject
import kotlin.collections.all
@Stable
@ModelScoped
@ -66,13 +64,6 @@ internal class FeedComponentModel @Inject constructor(
internal val state: StateFlow<FeedListUM>
field = MutableStateFlow<FeedListUM>(initialState())
private val searchBarStateFactory by lazy(LazyThreadSafetyMode.NONE) {
SearchBarStateFactory(
currentStateProvider = Provider { state.value },
onStateUpdate = { newState -> state.update { newState } },
)
}
private val trendingNewsStateFactory by lazy(LazyThreadSafetyMode.NONE) {
TrendingNewsStateFactory(
currentStateProvider = Provider { state.value },
@ -137,14 +128,9 @@ internal class FeedComponentModel @Inject constructor(
private fun initialState(): FeedListUM {
return FeedListUM(
currentDate = getCurrentDate(),
searchBar = SearchBarUM(
feedListSearchBar = FeedListSearchBar(
placeholderText = resourceReference(R.string.markets_search_header_title),
query = "",
onQueryChange = {},
isActive = false,
onActiveChange = {
if (it) params.feedClickIntents.onMarketOpenClick(SortByTypeUM.Rating)
},
onBarClick = { params.feedClickIntents.onMarketOpenClick(null) },
),
feedListCallbacks = FeedListCallbacks(
onSearchClick = {},
@ -307,7 +293,6 @@ internal class FeedComponentModel @Inject constructor(
private fun updateCallbacks() {
state.update { feedListUM ->
feedListUM.copy(
searchBar = state.value.searchBar.copy(onQueryChange = searchBarStateFactory::onSearchQueryChange),
feedListCallbacks = feedListUM.feedListCallbacks.copy(
onSortTypeClick = ::onSortTypeClick,
onMarketItemClick = { item ->

View file

@ -9,7 +9,7 @@ import com.tangem.features.feed.ui.market.list.state.SortByTypeUM
*/
internal interface FeedModelClickIntents {
fun onMarketItemClick(token: TokenMarketParams, appCurrency: AppCurrency)
fun onMarketOpenClick(sortBy: SortByTypeUM)
fun onMarketOpenClick(sortBy: SortByTypeUM?)
fun onArticleClick(articleId: Int)
fun onOpenAllNews()
}

View file

@ -73,6 +73,7 @@ internal class MarketsListModel @Inject constructor(
onShowTokensUnder100kClicked = { analyticsEventHandler.send(MarketsListAnalyticsEvent.ShowTokens()) },
shouldAlwaysShowSearchBar = Provider { params.shouldAlwaysShowSearchBar },
preselectedSortType = Provider { params.preselectedSortType },
onBackClick = params.onBackClicked,
)
}

View file

@ -29,6 +29,7 @@ internal class MarketsListUMStateManager(
private val onRetryButtonClicked: () -> Unit,
private val onTokenClick: (MarketsListItemUM) -> Unit,
private val onShowTokensUnder100kClicked: () -> Unit,
private val onBackClick: () -> Unit,
) {
val state = MutableStateFlow(state())
@ -38,19 +39,17 @@ internal class MarketsListUMStateManager(
set(value) = state.update { it.copy(sortByBottomSheet = it.sortByBottomSheet.copy(isShown = value)) }
var searchQuery
get() = state.value.searchBar.query
get() = state.value.marketsSearchBar.searchBarUM.query
private set(value) = state.update { marketsListUM ->
marketsListUM.copy(
searchBar = marketsListUM.searchBar.copy(
query = value,
isActive = value.isNotEmpty(),
marketsSearchBar = marketsListUM.marketsSearchBar.copy(
searchBarUM = marketsListUM.marketsSearchBar.searchBarUM.copy(query = value),
),
)
}
var isInSearchState
get() = state.value.searchBar.isActive
private set(value) = state.update { it.copy(searchBar = it.searchBar.copy(isActive = value)) }
val isInSearchState
get() = state.value.marketsSearchBar.searchBarUM.isActive
var selectedSortByType
get() = state.value.selectedSortBy
@ -91,7 +90,7 @@ internal class MarketsListUMStateManager(
}
val isInSearchStateFlow = state.map { it.isInSearchMode }.distinctUntilChanged()
val searchQueryFlow = state.map { it.searchBar.query }.distinctUntilChanged()
val searchQueryFlow = state.map { it.marketsSearchBar.searchBarUM.query }.distinctUntilChanged()
fun onUiItemsChanged(
isInErrorState: Boolean,
@ -214,12 +213,20 @@ internal class MarketsListUMStateManager(
private fun state(): MarketsListUM = MarketsListUM(
list = ListUM.Loading,
searchBar = SearchBarUM(
placeholderText = resourceReference(R.string.markets_search_header_title),
query = "",
onQueryChange = { searchQuery = it },
isActive = false,
onActiveChange = { },
marketsSearchBar = MarketsSearchBar(
searchBarUM = SearchBarUM(
placeholderText = resourceReference(R.string.markets_search_header_title),
query = "",
onQueryChange = { searchQuery = it },
isActive = false,
onActiveChange = ::changeSearchBarIsActive,
onClearClick = {
if (shouldAlwaysShowSearchBar()) {
onBackClick()
}
},
),
shouldAlwaysShowSearchBar = shouldAlwaysShowSearchBar(),
),
selectedSortBy = preselectedSortType(),
selectedInterval = MarketsListUM.TrendInterval.H24,
@ -234,7 +241,7 @@ internal class MarketsListUMStateManager(
),
),
marketsNotificationUM = null,
shouldAlwaysShowSearchBar = shouldAlwaysShowSearchBar(),
onSearchClicked = { changeSearchBarIsActive(true) },
)
private fun onBottomSheetOptionClicked(sortByTypeUM: SortByTypeUM) {
@ -264,4 +271,14 @@ internal class MarketsListUMStateManager(
)
}
}
private fun changeSearchBarIsActive(isActive: Boolean) {
state.update { marketsListUM ->
marketsListUM.copy(
marketsSearchBar = marketsListUM.marketsSearchBar.copy(
searchBarUM = marketsListUM.marketsSearchBar.searchBarUM.copy(isActive = isActive),
),
)
}
}
}

View file

@ -8,6 +8,7 @@ import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
@ -33,6 +34,7 @@ import com.tangem.common.ui.markets.MarketsListItemPlaceholder
import com.tangem.common.ui.markets.models.MarketsListItemUM
import com.tangem.common.ui.news.ArticleCard
import com.tangem.common.ui.news.ArticleConfigUM
import com.tangem.common.ui.news.ShowMoreArticlesCard
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerW
@ -41,9 +43,6 @@ import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.components.block.TangemBlockCardColors
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
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.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
@ -55,25 +54,20 @@ import com.tangem.features.feed.ui.feed.state.*
import com.tangem.features.feed.ui.market.list.state.SortByTypeUM
@Composable
internal fun FeedListHeader(searchBarUM: SearchBarUM, modifier: Modifier = Modifier) {
internal fun FeedListHeader(feedListSearchBar: FeedListSearchBar, modifier: Modifier = Modifier) {
val background = LocalMainBottomSheetColor.current.value
SearchBar(
FeedSearchBar(
feedListSearchBar = feedListSearchBar,
modifier = modifier
.drawBehind { drawRect(background) }
.padding(horizontal = 16.dp)
.padding(bottom = 12.dp),
state = searchBarUM,
colors = TangemSearchBarDefaults.defaultTextFieldColors.copy(
focusedContainerColor = TangemTheme.colors.field.focused,
unfocusedContainerColor = TangemTheme.colors.field.focused,
),
)
}
@Composable
internal fun FeedList(state: FeedListUM, modifier: Modifier = Modifier) {
val background = LocalMainBottomSheetColor.current.value
AnimatedContent(
modifier = modifier,
targetState = state.globalState,
@ -103,6 +97,33 @@ internal fun FeedList(state: FeedListUM, modifier: Modifier = Modifier) {
}
}
@Composable
private fun FeedSearchBar(feedListSearchBar: FeedListSearchBar, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.clip(RoundedCornerShape(36.dp))
.background(color = TangemTheme.colors.field.focused)
.clickable(onClick = feedListSearchBar.onBarClick)
.padding(14.dp),
) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size20),
imageVector = ImageVector.vectorResource(id = R.drawable.ic_search_24),
tint = TangemTheme.colors.icon.informative,
contentDescription = null,
)
SpacerW(14.dp)
Text(
text = feedListSearchBar.placeholderText.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
}
}
@Composable
private fun FeeListContent(state: FeedListUM, modifier: Modifier = Modifier) {
val background = LocalMainBottomSheetColor.current.value
@ -308,7 +329,7 @@ private fun NewsContentBlock(
append(stringResourceSafe(R.string.feed_tangem_ai))
}
},
style = TangemTheme.typography.h3,
style = TangemTheme.typography.subtitle1,
)
}
},
@ -345,10 +366,17 @@ private fun NewsContentBlock(
onArticleClick = { feedListCallbacks.onArticleClick(article.id) },
modifier = Modifier
.height(164.dp)
.widthIn(max = 216.dp),
.width(216.dp),
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
)
}
item {
ShowMoreArticlesCard(
modifier = Modifier.size(width = 216.dp, height = 164.dp),
onClick = feedListCallbacks.onOpenAllNews,
)
}
}
SpacerH(32.dp)
}

View file

@ -3,7 +3,6 @@ package com.tangem.features.feed.ui.feed.preview
import com.tangem.common.ui.charts.state.MarketChartRawData
import com.tangem.common.ui.markets.models.MarketsListItemUM
import com.tangem.common.ui.news.ArticleConfigUM
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.label.entity.LabelLeadingContentUM
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.components.marketprice.PriceChangeType
@ -22,12 +21,9 @@ internal object FeedListPreviewDataProvider {
val marketItems = createSampleMarketItems()
return FeedListUM(
currentDate = "20 November",
searchBar = SearchBarUM(
feedListSearchBar = FeedListSearchBar(
placeholderText = TextReference.Str("Search tokens & news"),
query = "",
onQueryChange = {},
isActive = false,
onActiveChange = {},
onBarClick = {},
),
feedListCallbacks = FeedListCallbacks(
onSearchClick = {},

View file

@ -3,7 +3,7 @@ package com.tangem.features.feed.ui.feed.state
import androidx.compose.runtime.Immutable
import com.tangem.common.ui.markets.models.MarketsListItemUM
import com.tangem.common.ui.news.ArticleConfigUM
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.feed.ui.market.list.state.SortByTypeUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
@ -11,7 +11,7 @@ import kotlinx.collections.immutable.toPersistentList
internal data class FeedListUM(
val currentDate: String,
val searchBar: SearchBarUM,
val feedListSearchBar: FeedListSearchBar,
val feedListCallbacks: FeedListCallbacks,
val news: NewsUM,
val trendingArticle: ArticleConfigUM?,
@ -28,6 +28,11 @@ internal data class FeedListCallbacks(
val onSortTypeClick: (SortByTypeUM) -> Unit,
)
internal data class FeedListSearchBar(
val onBarClick: () -> Unit,
val placeholderText: TextReference,
)
@Immutable
internal sealed interface NewsUM {
data object Loading : NewsUM

View file

@ -1,24 +0,0 @@
package com.tangem.features.feed.ui.feed.state
import com.tangem.utils.Provider
internal class SearchBarStateFactory(
private val currentStateProvider: Provider<FeedListUM>,
private val onStateUpdate: (FeedListUM) -> Unit,
) {
val searchQuery: String
get() = currentStateProvider().searchBar.query
fun onSearchQueryChange(query: String) {
val currentState = currentStateProvider()
onStateUpdate(
currentState.copy(
searchBar = currentState.searchBar.copy(
query = query,
isActive = query.isNotEmpty(),
),
),
)
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.features.feed.ui.market.list
import android.content.res.Configuration
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.rememberLazyListState
@ -10,6 +11,7 @@ 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
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
@ -19,6 +21,7 @@ import com.tangem.common.ui.markets.preview.MarketChartListItemPreviewDataProvid
import com.tangem.core.ui.components.Keyboard
import com.tangem.core.ui.components.SpacerH12
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.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
@ -41,23 +44,47 @@ import com.tangem.features.feed.ui.market.list.components.YieldSupplyInMarketsPr
import com.tangem.features.feed.ui.market.list.state.*
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.delay
private const val SHOW_MORE_KEY = "privacyPolicy"
@Composable
internal fun TopBarWithSearch(searchBarUM: SearchBarUM) {
internal fun TopBarWithSearch(onBackClick: () -> Unit, onSearchClick: () -> Unit, marketsSearchBar: MarketsSearchBar) {
val background = LocalMainBottomSheetColor.current.value
SearchBar(
modifier = Modifier
.drawBehind { drawRect(background) }
.padding(horizontal = 16.dp)
.padding(bottom = 12.dp),
state = searchBarUM,
colors = TangemSearchBarDefaults.defaultTextFieldColors.copy(
focusedContainerColor = TangemTheme.colors.field.focused,
unfocusedContainerColor = TangemTheme.colors.field.focused,
),
)
val focusRequester: FocusRequester = remember { FocusRequester() }
AnimatedContent(
targetState = !marketsSearchBar.shouldAlwaysShowSearchBar && !marketsSearchBar.searchBarUM.isActive,
) { showAppBarWithBackIcon ->
if (showAppBarWithBackIcon) {
AppBarWithBackButtonAndIcon(
onBackClick = onBackClick,
text = stringResourceSafe(R.string.markets_common_title),
iconRes = R.drawable.ic_search_24,
onIconClick = onSearchClick,
backgroundColor = background,
)
} else {
SearchBar(
modifier = Modifier
.drawBehind { drawRect(background) }
.padding(horizontal = 16.dp)
.padding(bottom = 12.dp),
state = marketsSearchBar.searchBarUM,
colors = TangemSearchBarDefaults.defaultTextFieldColors.copy(
focusedContainerColor = TangemTheme.colors.field.focused,
unfocusedContainerColor = TangemTheme.colors.field.focused,
),
focusRequester = focusRequester,
)
LaunchedEffect(marketsSearchBar.shouldAlwaysShowSearchBar) {
if (marketsSearchBar.shouldAlwaysShowSearchBar) {
delay(timeMillis = 200)
focusRequester.requestFocus()
}
}
}
}
}
@Composable
@ -83,16 +110,22 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
Column(modifier.padding(horizontal = TangemTheme.dimens.size16)) {
AnimatedVisibility(
visible = scrolledState.value.not(),
visible = scrolledState.value.not() &&
state.isInSearchMode &&
state.marketsSearchBar.searchBarUM.query.isNotEmpty(),
) {
Column {
SpacerH8()
Title(isInSearchMode = state.isInSearchMode)
Text(
text = stringResourceSafe(id = R.string.markets_search_result_title),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
)
SpacerH12()
}
}
Column {
AnimatedVisibility(state.isInSearchMode.not()) {
AnimatedVisibility(!state.isInSearchMode && !state.marketsSearchBar.shouldAlwaysShowSearchBar) {
Options(
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
sortByTypeUM = state.selectedSortBy,
@ -161,20 +194,6 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
)
}
@Composable
private fun Title(isInSearchMode: Boolean, modifier: Modifier = Modifier) {
Text(
modifier = modifier,
text = if (isInSearchMode) {
stringResourceSafe(id = R.string.markets_search_result_title)
} else {
stringResourceSafe(id = R.string.markets_common_title)
},
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
)
}
@Composable
private fun Options(
sortByTypeUM: SortByTypeUM,
@ -320,12 +339,15 @@ private fun Preview() {
triggerScrollReset = consumedEvent(),
onItemClick = {},
),
searchBar = SearchBarUM(
placeholderText = resourceReference(R.string.markets_search_header_title),
query = "",
onQueryChange = {},
isActive = false,
onActiveChange = { },
marketsSearchBar = MarketsSearchBar(
searchBarUM = SearchBarUM(
placeholderText = resourceReference(R.string.markets_search_header_title),
query = "",
onQueryChange = {},
isActive = false,
onActiveChange = { },
),
shouldAlwaysShowSearchBar = true,
),
selectedSortBy = SortByTypeUM.Rating,
selectedInterval = MarketsListUM.TrendInterval.H24,
@ -340,7 +362,7 @@ private fun Preview() {
onClick = {},
onCloseClick = {},
),
shouldAlwaysShowSearchBar = true,
onSearchClicked = {},
),
)
}

View file

@ -13,17 +13,18 @@ import kotlinx.collections.immutable.ImmutableList
internal data class MarketsListUM(
val list: ListUM,
val searchBar: SearchBarUM,
val marketsSearchBar: MarketsSearchBar,
val selectedSortBy: SortByTypeUM,
val sortByBottomSheet: TangemBottomSheetConfig,
val selectedInterval: TrendInterval,
val shouldAlwaysShowSearchBar: Boolean,
val onIntervalClick: (TrendInterval) -> Unit,
val onSortByButtonClick: () -> Unit,
val marketsNotificationUM: MarketsNotificationUM?,
val onSearchClicked: () -> Unit,
) {
val isInSearchMode
get() = searchBar.isActive
get() = marketsSearchBar.searchBarUM.isActive &&
marketsSearchBar.searchBarUM.query.isNotEmpty()
enum class TrendInterval(val text: TextReference) {
H24(resourceReference(R.string.markets_selector_interval_24h_title)),
@ -32,7 +33,12 @@ internal data class MarketsListUM(
}
}
enum class SortByTypeUM(val text: TextReference) {
internal data class MarketsSearchBar(
val searchBarUM: SearchBarUM,
val shouldAlwaysShowSearchBar: Boolean,
)
internal enum class SortByTypeUM(val text: TextReference) {
Rating(resourceReference(R.string.markets_sort_by_rating_title)),
Trending(resourceReference(R.string.markets_sort_by_trending_title)),
ExperiencedBuyers(resourceReference(R.string.markets_sort_by_experienced_buyers_title)),
@ -43,7 +49,7 @@ enum class SortByTypeUM(val text: TextReference) {
}
@Immutable
sealed class ListUM {
internal sealed class ListUM {
data class Content(
val items: ImmutableList<MarketsListItemUM>,

View file

@ -2,7 +2,7 @@ package com.tangem.features.feed.ui.market.list.state
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
data class SortByBottomSheetContentUM(
internal data class SortByBottomSheetContentUM(
val selectedOption: SortByTypeUM,
val onOptionClicked: (SortByTypeUM) -> Unit,
) : TangemBottomSheetConfigContent