Updated on 2026-08-14
This commit is contained in:
parent
18d4a01642
commit
bced1ca48d
11 changed files with 845 additions and 119 deletions
|
|
@ -469,7 +469,13 @@
|
|||
<string name="domain_receive_assets_onboarding_title">Send funds using only</string>
|
||||
<string name="earn_best_opportunities">Best opportunities</string>
|
||||
<string name="earn_filter_all_networks">All networks</string>
|
||||
<string name="earn_filter_my_networks">My networks</string>
|
||||
<string name="earn_filter_all_types">All types</string>
|
||||
<string name="earn_filter_networks">Networks</string>
|
||||
<string name="earn_clear_filter">Clear filter</string>
|
||||
<string name="earn_filter_by">Filter by</string>
|
||||
<string name="earn_no_results">No results</string>
|
||||
<string name="earn_empty">The list is temporarily empty as it’s being refreshed. Check back in a moment.</string>
|
||||
<string name="earn_mostly_used">Mostly used</string>
|
||||
<string name="earn_title">Earn</string>
|
||||
<string name="email_preface_wc_error">Hi support team, I\'ve encountered an error with code: %s</string>
|
||||
|
|
|
|||
|
|
@ -4,13 +4,24 @@ import androidx.compose.runtime.Stable
|
|||
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.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.features.feed.components.earn.DefaultEarnComponent
|
||||
import com.tangem.features.feed.ui.earn.state.EarnBestOpportunitiesUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterByNetworkBottomSheetContentUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterByTypeBottomSheetContentUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnListUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
|
|
@ -22,18 +33,213 @@ internal class EarnModel @Inject constructor(
|
|||
|
||||
private val params = paramsContainer.require<DefaultEarnComponent.Params>()
|
||||
|
||||
// TODO [REDACTED_TASK_KEY] remove mocks
|
||||
private val mockNetworks: ImmutableList<EarnFilterNetworkUM> = persistentListOf(
|
||||
EarnFilterNetworkUM.AllNetworks(
|
||||
text = resourceReference(R.string.earn_filter_all_networks),
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.MyNetworks(
|
||||
text = resourceReference(R.string.earn_filter_my_networks),
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "ethereum",
|
||||
text = stringReference("Ethereum"),
|
||||
symbol = stringReference("ETH"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/ethereum.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "polygon",
|
||||
text = stringReference("Polygon"),
|
||||
symbol = stringReference("MATIC"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/matic-network.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "base",
|
||||
text = stringReference("Base"),
|
||||
symbol = stringReference("BASE"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/base.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "avalanche",
|
||||
text = stringReference("Avalance"),
|
||||
symbol = stringReference("AVAX"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/avalanche-2.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "cardano",
|
||||
text = stringReference("Cardano"),
|
||||
symbol = stringReference("ADA"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/cardano.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "bsc",
|
||||
text = stringReference("Bitcoin Smart Chain"),
|
||||
symbol = stringReference("BSC"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/binancecoin.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "bitcoin",
|
||||
text = stringReference("Bitcoin"),
|
||||
symbol = stringReference("BTC"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/bitcoin.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "solana",
|
||||
text = stringReference("Solana"),
|
||||
symbol = stringReference("SOL"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/solana.png",
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "ton",
|
||||
text = stringReference("Ton"),
|
||||
symbol = stringReference("TON"),
|
||||
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/the-open-network.png",
|
||||
isSelected = false,
|
||||
),
|
||||
)
|
||||
|
||||
val state: StateFlow<EarnUM>
|
||||
field = MutableStateFlow(createInitialState())
|
||||
|
||||
private fun createInitialState(): EarnUM = EarnUM(
|
||||
mostlyUsed = EarnListUM.Loading,
|
||||
bestOpportunities = EarnListUM.Loading,
|
||||
selectedNetworkFilter = null,
|
||||
selectedTypeFilter = null,
|
||||
networkFilters = persistentListOf(),
|
||||
typeFilters = persistentListOf(),
|
||||
onBackClick = params.onBackClick,
|
||||
onNetworkFilterClick = { },
|
||||
onTypeFilterClick = { },
|
||||
)
|
||||
private fun createInitialState(): EarnUM {
|
||||
val defaultNetworkFilter = mockNetworks.first()
|
||||
val defaultTypeFilter = EarnFilterTypeUM.All
|
||||
|
||||
return EarnUM(
|
||||
mostlyUsed = EarnListUM.Loading,
|
||||
bestOpportunities = EarnBestOpportunitiesUM.Loading,
|
||||
selectedTypeFilter = defaultTypeFilter,
|
||||
selectedNetworkFilter = defaultNetworkFilter,
|
||||
filterByTypeBottomSheet = createTypeFilterBottomSheetConfig(defaultTypeFilter),
|
||||
filterByNetworkBottomSheet = createNetworkFilterBottomSheetConfig(defaultNetworkFilter),
|
||||
onBackClick = params.onBackClick,
|
||||
onNetworkFilterClick = ::onNetworkFilterClick,
|
||||
onTypeFilterClick = ::onTypeFilterClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createTypeFilterBottomSheetConfig(
|
||||
selectedOption: EarnFilterTypeUM,
|
||||
isShown: Boolean = false,
|
||||
): TangemBottomSheetConfig {
|
||||
return TangemBottomSheetConfig(
|
||||
isShown = isShown,
|
||||
onDismissRequest = ::hideTypeFilterBottomSheet,
|
||||
content = EarnFilterByTypeBottomSheetContentUM(
|
||||
selectedOption = selectedOption,
|
||||
onOptionClick = ::onTypeFilterOptionClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createNetworkFilterBottomSheetConfig(
|
||||
selectedNetwork: EarnFilterNetworkUM,
|
||||
isShown: Boolean = false,
|
||||
): TangemBottomSheetConfig {
|
||||
val updatedNetworks = mockNetworks.map { network ->
|
||||
when {
|
||||
network is EarnFilterNetworkUM.AllNetworks && selectedNetwork is EarnFilterNetworkUM.AllNetworks ->
|
||||
network.copy(isSelected = true)
|
||||
network is EarnFilterNetworkUM.MyNetworks && selectedNetwork is EarnFilterNetworkUM.MyNetworks ->
|
||||
network.copy(isSelected = true)
|
||||
network is EarnFilterNetworkUM.Network && selectedNetwork is EarnFilterNetworkUM.Network &&
|
||||
network.id == selectedNetwork.id ->
|
||||
network.copy(isSelected = true)
|
||||
else -> network
|
||||
}
|
||||
}
|
||||
|
||||
return TangemBottomSheetConfig(
|
||||
isShown = isShown,
|
||||
onDismissRequest = ::hideNetworkFilterBottomSheet,
|
||||
content = EarnFilterByNetworkBottomSheetContentUM(
|
||||
selectedNetwork = selectedNetwork,
|
||||
networks = persistentListOf(*updatedNetworks.toTypedArray()),
|
||||
onOptionClick = ::onNetworkFilterOptionClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onTypeFilterClick() {
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
filterByTypeBottomSheet = createTypeFilterBottomSheetConfig(
|
||||
selectedOption = currentState.selectedTypeFilter,
|
||||
isShown = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onNetworkFilterClick() {
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
filterByNetworkBottomSheet = createNetworkFilterBottomSheetConfig(
|
||||
selectedNetwork = currentState.selectedNetworkFilter,
|
||||
isShown = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideTypeFilterBottomSheet() {
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
filterByTypeBottomSheet = currentState.filterByTypeBottomSheet.copy(isShown = false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideNetworkFilterBottomSheet() {
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
filterByNetworkBottomSheet = currentState.filterByNetworkBottomSheet.copy(isShown = false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onTypeFilterOptionClick(type: EarnFilterTypeUM) {
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
selectedTypeFilter = type,
|
||||
filterByTypeBottomSheet = createTypeFilterBottomSheetConfig(selectedOption = type),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onNetworkFilterOptionClick(network: EarnFilterNetworkUM) {
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
selectedNetworkFilter = network,
|
||||
filterByNetworkBottomSheet = createNetworkFilterBottomSheetConfig(selectedNetwork = network),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [REDACTED_TASK_KEY] remove
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun onClearFiltersClick() {
|
||||
val defaultNetworkFilter = mockNetworks.first()
|
||||
val defaultTypeFilter = EarnFilterTypeUM.All
|
||||
state.update { currentState ->
|
||||
currentState.copy(
|
||||
selectedTypeFilter = defaultTypeFilter,
|
||||
selectedNetworkFilter = defaultNetworkFilter,
|
||||
filterByTypeBottomSheet = createTypeFilterBottomSheetConfig(selectedOption = defaultTypeFilter),
|
||||
filterByNetworkBottomSheet = createNetworkFilterBottomSheetConfig(
|
||||
selectedNetwork = defaultNetworkFilter,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.feed.ui.earn
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -9,12 +10,16 @@ import androidx.compose.foundation.lazy.LazyListScope
|
|||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
|
|
@ -37,10 +42,16 @@ import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
|||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.feed.ui.earn.components.EarnFilterByNetworkBottomSheet
|
||||
import com.tangem.features.feed.ui.earn.components.EarnFilterByTypeBottomSheet
|
||||
import com.tangem.features.feed.ui.earn.components.EarnItemPlaceholder
|
||||
import com.tangem.features.feed.ui.earn.components.EarnListItem
|
||||
import com.tangem.features.feed.ui.earn.components.MostlyUsedPlaceholder
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnBestOpportunitiesUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnListItemUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnListUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnUM
|
||||
|
|
@ -51,6 +62,10 @@ internal fun EarnContent(state: EarnUM, modifier: Modifier = Modifier) {
|
|||
val background = LocalMainBottomSheetColor.current.value
|
||||
val density = LocalDensity.current
|
||||
val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
EarnFilterByTypeBottomSheet(config = state.filterByTypeBottomSheet)
|
||||
EarnFilterByNetworkBottomSheet(config = state.filterByNetworkBottomSheet)
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
|
|
@ -79,8 +94,8 @@ internal fun EarnContent(state: EarnUM, modifier: Modifier = Modifier) {
|
|||
SpacerH(12.dp)
|
||||
BestOpportunitiesFilters(
|
||||
state = state.bestOpportunities,
|
||||
selectedNetworkFilter = state.selectedNetworkFilter,
|
||||
selectedTypeFilter = state.selectedTypeFilter,
|
||||
selectedNetworkFilterText = state.selectedNetworkFilterText,
|
||||
selectedTypeFilterText = state.selectedTypeFilterText,
|
||||
onNetworkFilterClick = state.onNetworkFilterClick,
|
||||
onTypeFilterClick = state.onTypeFilterClick,
|
||||
)
|
||||
|
|
@ -94,40 +109,42 @@ internal fun EarnContent(state: EarnUM, modifier: Modifier = Modifier) {
|
|||
|
||||
@Composable
|
||||
private fun MostlyUsedContent(state: EarnListUM) {
|
||||
when (state) {
|
||||
is EarnListUM.Loading -> {
|
||||
MostlyUsedPlaceholder()
|
||||
}
|
||||
is EarnListUM.Content -> {
|
||||
LazyRow(
|
||||
contentPadding = PaddingValues(
|
||||
horizontal = 16.dp,
|
||||
vertical = 12.dp,
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
items(
|
||||
items = state.items,
|
||||
key = { "${it.tokenName}-${it.network}" },
|
||||
) { item ->
|
||||
MostlyUsedCard(
|
||||
item = item,
|
||||
onClick = item.onItemClick,
|
||||
)
|
||||
}
|
||||
AnimatedContent(state) { st ->
|
||||
when (st) {
|
||||
is EarnListUM.Loading -> {
|
||||
MostlyUsedPlaceholder()
|
||||
}
|
||||
}
|
||||
is EarnListUM.Error -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
is EarnListUM.Content -> {
|
||||
LazyRow(
|
||||
contentPadding = PaddingValues(
|
||||
horizontal = 16.dp,
|
||||
vertical = 12.dp,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
UnableToLoadData(onRetryClick = state.onRetryClicked)
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
items(
|
||||
items = st.items,
|
||||
key = { "${it.tokenName}-${it.network}" },
|
||||
) { item ->
|
||||
MostlyUsedCard(
|
||||
item = item,
|
||||
onClick = item.onItemClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is EarnListUM.Error -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = 16.dp,
|
||||
vertical = 12.dp,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
UnableToLoadData(onRetryClick = st.onRetryClicked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -184,40 +201,46 @@ private fun MostlyUsedCard(item: EarnListItemUM, onClick: () -> Unit, modifier:
|
|||
|
||||
@Composable
|
||||
private fun BestOpportunitiesFilters(
|
||||
state: EarnListUM,
|
||||
selectedNetworkFilter: EarnFilterUM?,
|
||||
selectedTypeFilter: EarnFilterUM?,
|
||||
state: EarnBestOpportunitiesUM,
|
||||
selectedNetworkFilterText: TextReference,
|
||||
selectedTypeFilterText: TextReference,
|
||||
onNetworkFilterClick: () -> Unit,
|
||||
onTypeFilterClick: () -> Unit,
|
||||
) {
|
||||
when (state) {
|
||||
is EarnListUM.Loading -> {
|
||||
FilterButtonsShimmer()
|
||||
}
|
||||
is EarnListUM.Content -> {
|
||||
FilterButtons(
|
||||
selectedNetworkFilter = selectedNetworkFilter,
|
||||
selectedTypeFilter = selectedTypeFilter,
|
||||
isEnabled = true,
|
||||
onNetworkFilterClick = onNetworkFilterClick,
|
||||
onTypeFilterClick = onTypeFilterClick,
|
||||
)
|
||||
}
|
||||
is EarnListUM.Error -> {
|
||||
FilterButtons(
|
||||
selectedNetworkFilter = selectedNetworkFilter,
|
||||
selectedTypeFilter = selectedTypeFilter,
|
||||
isEnabled = false,
|
||||
onNetworkFilterClick = onNetworkFilterClick,
|
||||
onTypeFilterClick = onTypeFilterClick,
|
||||
)
|
||||
AnimatedContent(state) { st ->
|
||||
when (st) {
|
||||
is EarnBestOpportunitiesUM.Loading -> {
|
||||
FilterButtonsShimmer()
|
||||
}
|
||||
is EarnBestOpportunitiesUM.EmptyFiltered,
|
||||
is EarnBestOpportunitiesUM.Content,
|
||||
-> {
|
||||
FilterButtons(
|
||||
selectedNetworkFilterText = selectedNetworkFilterText,
|
||||
selectedTypeFilterText = selectedTypeFilterText,
|
||||
isEnabled = true,
|
||||
onNetworkFilterClick = onNetworkFilterClick,
|
||||
onTypeFilterClick = onTypeFilterClick,
|
||||
)
|
||||
}
|
||||
is EarnBestOpportunitiesUM.Empty,
|
||||
is EarnBestOpportunitiesUM.Error,
|
||||
-> {
|
||||
FilterButtons(
|
||||
selectedNetworkFilterText = selectedNetworkFilterText,
|
||||
selectedTypeFilterText = selectedTypeFilterText,
|
||||
isEnabled = false,
|
||||
onNetworkFilterClick = onNetworkFilterClick,
|
||||
onTypeFilterClick = onTypeFilterClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.bestOpportunitiesItems(state: EarnListUM) {
|
||||
private fun LazyListScope.bestOpportunitiesItems(state: EarnBestOpportunitiesUM) {
|
||||
when (state) {
|
||||
is EarnListUM.Loading -> {
|
||||
is EarnBestOpportunitiesUM.Loading -> {
|
||||
val lastIndex = PLACEHOLDER_ITEMS_COUNT - 1
|
||||
items(
|
||||
count = PLACEHOLDER_ITEMS_COUNT,
|
||||
|
|
@ -233,7 +256,19 @@ private fun LazyListScope.bestOpportunitiesItems(state: EarnListUM) {
|
|||
)
|
||||
}
|
||||
}
|
||||
is EarnListUM.Content -> {
|
||||
is EarnBestOpportunitiesUM.Empty -> {
|
||||
item(key = "best_opportunities_empty") {
|
||||
SpacerH(12.dp)
|
||||
BestOpportunitiesEmpty()
|
||||
}
|
||||
}
|
||||
is EarnBestOpportunitiesUM.EmptyFiltered -> {
|
||||
item(key = "best_opportunities_empty_filtered") {
|
||||
SpacerH(12.dp)
|
||||
BestOpportunitiesEmptyFiltered(onClearFilterClick = state.onClearFilterClick)
|
||||
}
|
||||
}
|
||||
is EarnBestOpportunitiesUM.Content -> {
|
||||
if (state.items.isNotEmpty()) {
|
||||
val lastIndex = state.items.lastIndex
|
||||
itemsIndexed(
|
||||
|
|
@ -252,7 +287,7 @@ private fun LazyListScope.bestOpportunitiesItems(state: EarnListUM) {
|
|||
}
|
||||
}
|
||||
}
|
||||
is EarnListUM.Error -> {
|
||||
is EarnBestOpportunitiesUM.Error -> {
|
||||
item(key = "best_opportunities_error") {
|
||||
SpacerH(12.dp)
|
||||
Box(
|
||||
|
|
@ -275,8 +310,8 @@ private fun LazyListScope.bestOpportunitiesItems(state: EarnListUM) {
|
|||
|
||||
@Composable
|
||||
private fun FilterButtons(
|
||||
selectedNetworkFilter: EarnFilterUM?,
|
||||
selectedTypeFilter: EarnFilterUM?,
|
||||
selectedNetworkFilterText: TextReference,
|
||||
selectedTypeFilterText: TextReference,
|
||||
isEnabled: Boolean,
|
||||
onNetworkFilterClick: () -> Unit,
|
||||
onTypeFilterClick: () -> Unit,
|
||||
|
|
@ -287,8 +322,7 @@ private fun FilterButtons(
|
|||
) {
|
||||
SecondarySmallButton(
|
||||
config = SmallButtonConfig(
|
||||
text = selectedNetworkFilter?.name
|
||||
?: resourceReference(R.string.earn_filter_all_networks),
|
||||
text = selectedNetworkFilterText,
|
||||
onClick = onNetworkFilterClick,
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_chevron_24),
|
||||
isEnabled = isEnabled,
|
||||
|
|
@ -299,8 +333,7 @@ private fun FilterButtons(
|
|||
|
||||
SecondarySmallButton(
|
||||
config = SmallButtonConfig(
|
||||
text = selectedTypeFilter?.name
|
||||
?: resourceReference(R.string.earn_filter_all_types),
|
||||
text = selectedTypeFilterText,
|
||||
onClick = onTypeFilterClick,
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_chevron_24),
|
||||
isEnabled = isEnabled,
|
||||
|
|
@ -326,6 +359,66 @@ private fun FilterButtonsShimmer(modifier: Modifier = Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BestOpportunitiesEmpty(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
)
|
||||
.padding(vertical = 32.dp, horizontal = 12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
painter = painterResource(R.drawable.ic_empty_64),
|
||||
contentDescription = null,
|
||||
tint = Color.Unspecified,
|
||||
)
|
||||
SpacerH(24.dp)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 32.dp),
|
||||
text = stringResourceSafe(R.string.earn_empty),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BestOpportunitiesEmptyFiltered(onClearFilterClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
)
|
||||
.padding(vertical = 32.dp, horizontal = 12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.earn_no_results),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
SpacerH(12.dp)
|
||||
SecondarySmallButton(
|
||||
config = SmallButtonConfig(
|
||||
text = resourceReference(R.string.earn_clear_filter),
|
||||
onClick = onClearFilterClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SectionHeader(title: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
|
|
@ -348,7 +441,7 @@ private fun EarnContentPreview() {
|
|||
LocalMainBottomSheetColor provides remember { mutableStateOf(background) },
|
||||
) {
|
||||
EarnContent(
|
||||
state = EarnUM(
|
||||
state = previewEarnUM(
|
||||
mostlyUsed = EarnListUM.Content(
|
||||
items = persistentListOf(
|
||||
previewEarnListItemUM(),
|
||||
|
|
@ -359,7 +452,7 @@ private fun EarnContentPreview() {
|
|||
),
|
||||
),
|
||||
),
|
||||
bestOpportunities = EarnListUM.Content(
|
||||
bestOpportunities = EarnBestOpportunitiesUM.Content(
|
||||
items = persistentListOf(
|
||||
previewEarnListItemUM(
|
||||
tokenName = "Cosmos Hub",
|
||||
|
|
@ -373,13 +466,6 @@ private fun EarnContentPreview() {
|
|||
),
|
||||
),
|
||||
),
|
||||
selectedNetworkFilter = null,
|
||||
selectedTypeFilter = null,
|
||||
networkFilters = persistentListOf(),
|
||||
typeFilters = persistentListOf(),
|
||||
onBackClick = {},
|
||||
onNetworkFilterClick = {},
|
||||
onTypeFilterClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -396,16 +482,9 @@ private fun EarnContentLoadingPreview() {
|
|||
LocalMainBottomSheetColor provides remember { mutableStateOf(background) },
|
||||
) {
|
||||
EarnContent(
|
||||
state = EarnUM(
|
||||
state = previewEarnUM(
|
||||
mostlyUsed = EarnListUM.Loading,
|
||||
bestOpportunities = EarnListUM.Loading,
|
||||
selectedNetworkFilter = null,
|
||||
selectedTypeFilter = null,
|
||||
networkFilters = persistentListOf(),
|
||||
typeFilters = persistentListOf(),
|
||||
onBackClick = {},
|
||||
onNetworkFilterClick = {},
|
||||
onTypeFilterClick = {},
|
||||
bestOpportunities = EarnBestOpportunitiesUM.Loading,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -422,7 +501,7 @@ private fun EarnContentErrorPreview() {
|
|||
LocalMainBottomSheetColor provides remember { mutableStateOf(background) },
|
||||
) {
|
||||
EarnContent(
|
||||
state = EarnUM(
|
||||
state = previewEarnUM(
|
||||
mostlyUsed = EarnListUM.Content(
|
||||
items = persistentListOf(
|
||||
previewEarnListItemUM(),
|
||||
|
|
@ -433,14 +512,35 @@ private fun EarnContentErrorPreview() {
|
|||
),
|
||||
),
|
||||
),
|
||||
bestOpportunities = EarnListUM.Error(onRetryClicked = {}),
|
||||
selectedNetworkFilter = null,
|
||||
selectedTypeFilter = null,
|
||||
networkFilters = persistentListOf(),
|
||||
typeFilters = persistentListOf(),
|
||||
onBackClick = {},
|
||||
onNetworkFilterClick = {},
|
||||
onTypeFilterClick = {},
|
||||
bestOpportunities = EarnBestOpportunitiesUM.Error(onRetryClicked = {}),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun EarnContentEmptyPreview() {
|
||||
TangemThemePreview {
|
||||
val background = TangemTheme.colors.background.tertiary
|
||||
CompositionLocalProvider(
|
||||
LocalMainBottomSheetColor provides remember { mutableStateOf(background) },
|
||||
) {
|
||||
EarnContent(
|
||||
state = previewEarnUM(
|
||||
mostlyUsed = EarnListUM.Content(
|
||||
items = persistentListOf(
|
||||
previewEarnListItemUM(),
|
||||
previewEarnListItemUM(
|
||||
tokenName = "Cosmos",
|
||||
symbol = "ATOM",
|
||||
network = "Cosmos",
|
||||
),
|
||||
),
|
||||
),
|
||||
bestOpportunities = EarnBestOpportunitiesUM.Empty,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -469,4 +569,22 @@ private fun previewEarnListItemUM(
|
|||
onItemClick = {},
|
||||
)
|
||||
|
||||
private fun previewEarnUM(
|
||||
mostlyUsed: EarnListUM = EarnListUM.Loading,
|
||||
bestOpportunities: EarnBestOpportunitiesUM = EarnBestOpportunitiesUM.Loading,
|
||||
): EarnUM = EarnUM(
|
||||
mostlyUsed = mostlyUsed,
|
||||
bestOpportunities = bestOpportunities,
|
||||
selectedTypeFilter = EarnFilterTypeUM.All,
|
||||
selectedNetworkFilter = EarnFilterNetworkUM.AllNetworks(
|
||||
text = resourceReference(R.string.earn_filter_all_networks),
|
||||
isSelected = true,
|
||||
),
|
||||
filterByTypeBottomSheet = TangemBottomSheetConfig.Empty,
|
||||
filterByNetworkBottomSheet = TangemBottomSheetConfig.Empty,
|
||||
onBackClick = {},
|
||||
onNetworkFilterClick = {},
|
||||
onTypeFilterClick = {},
|
||||
)
|
||||
|
||||
private const val PLACEHOLDER_ITEMS_COUNT = 8
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
package com.tangem.features.feed.ui.earn.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.currency.icon.CoinIcon
|
||||
import com.tangem.core.ui.components.inputrow.InputRowChecked
|
||||
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
|
||||
import com.tangem.core.ui.components.rows.RowContentContainer
|
||||
import com.tangem.core.ui.components.rows.RowText
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.feed.impl.R
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterByNetworkBottomSheetContentUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun EarnFilterByNetworkBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet<EarnFilterByNetworkBottomSheetContentUM>(
|
||||
config = config,
|
||||
titleText = resourceReference(R.string.earn_filter_by),
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
content = { Content(it) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(content: EarnFilterByNetworkBottomSheetContentUM) {
|
||||
val allMyNetworks = remember(content) {
|
||||
content.networks.filterIsInstance<EarnFilterNetworkUM.AllNetworks>() +
|
||||
content.networks.filterIsInstance<EarnFilterNetworkUM.MyNetworks>()
|
||||
}
|
||||
val specificNetworks = remember(content) { content.networks.filterIsInstance<EarnFilterNetworkUM.Network>() }
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
) {
|
||||
allMyNetworksList(
|
||||
allMyNetworks = allMyNetworks,
|
||||
onOptionClicked = content.onOptionClick,
|
||||
)
|
||||
|
||||
if (specificNetworks.isNotEmpty()) {
|
||||
networksHeader()
|
||||
|
||||
specificNetworksList(
|
||||
specificNetworks = specificNetworks,
|
||||
onOptionClicked = content.onOptionClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.allMyNetworksList(
|
||||
allMyNetworks: List<EarnFilterNetworkUM>,
|
||||
onOptionClicked: (EarnFilterNetworkUM) -> Unit,
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = allMyNetworks,
|
||||
key = { _, item ->
|
||||
when (item) {
|
||||
is EarnFilterNetworkUM.AllNetworks -> "all_networks"
|
||||
is EarnFilterNetworkUM.MyNetworks -> "my_networks"
|
||||
is EarnFilterNetworkUM.Network -> item.id
|
||||
}
|
||||
},
|
||||
) { index, item ->
|
||||
DividerContainer(
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = allMyNetworks.lastIndex,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable { onOptionClicked(item) },
|
||||
showDivider = index != allMyNetworks.lastIndex,
|
||||
) {
|
||||
InputRowChecked(
|
||||
text = item.text,
|
||||
checked = item.isSelected,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.networksHeader() {
|
||||
item(key = "networks_header") {
|
||||
SpacerH(TangemTheme.dimens.spacing16)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = RoundedCornerShape(
|
||||
topStart = 16.dp,
|
||||
topEnd = 16.dp,
|
||||
),
|
||||
)
|
||||
.padding(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 12.dp,
|
||||
bottom = 4.dp,
|
||||
),
|
||||
text = stringResourceSafe(id = R.string.earn_filter_networks),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.specificNetworksList(
|
||||
specificNetworks: List<EarnFilterNetworkUM.Network>,
|
||||
onOptionClicked: (EarnFilterNetworkUM) -> Unit,
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = specificNetworks,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
DividerContainer(
|
||||
modifier = Modifier
|
||||
.height(52.dp)
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index + 1,
|
||||
lastIndex = specificNetworks.lastIndex + 1,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable { onOptionClicked(item) },
|
||||
showDivider = false,
|
||||
) {
|
||||
RowContentContainer(
|
||||
modifier = Modifier
|
||||
.heightIn(52.dp)
|
||||
.padding(horizontal = 12.dp),
|
||||
icon = {
|
||||
CoinIcon(
|
||||
modifier = Modifier.size(22.dp),
|
||||
url = item.iconUrl,
|
||||
alpha = 1f,
|
||||
colorFilter = null,
|
||||
fallbackResId = R.drawable.ic_custom_token_44,
|
||||
)
|
||||
},
|
||||
text = {
|
||||
RowText(
|
||||
mainText = item.text.resolveReference(),
|
||||
secondText = item.symbol.resolveReference(),
|
||||
accentMainText = true,
|
||||
accentSecondText = false,
|
||||
)
|
||||
},
|
||||
action = {
|
||||
if (item.isSelected) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_check_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, heightDp = 800)
|
||||
@Preview(widthDp = 360, heightDp = 800, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview(
|
||||
alwaysShowBottomSheets = true,
|
||||
) {
|
||||
Box(Modifier.background(TangemTheme.colors.background.secondary)) {
|
||||
EarnFilterByNetworkBottomSheet(
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = EarnFilterByNetworkBottomSheetContentUM(
|
||||
selectedNetwork = EarnFilterNetworkUM.AllNetworks(
|
||||
text = resourceReference(R.string.earn_filter_all_networks),
|
||||
isSelected = true,
|
||||
),
|
||||
networks = persistentListOf(
|
||||
EarnFilterNetworkUM.AllNetworks(
|
||||
text = resourceReference(R.string.earn_filter_all_networks),
|
||||
isSelected = true,
|
||||
),
|
||||
EarnFilterNetworkUM.MyNetworks(
|
||||
text = stringReference("My network"),
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "ethereum",
|
||||
text = stringReference("Ethereum"),
|
||||
symbol = stringReference("ETH"),
|
||||
iconUrl = null,
|
||||
isSelected = false,
|
||||
),
|
||||
EarnFilterNetworkUM.Network(
|
||||
id = "polygon",
|
||||
text = stringReference("Polygon"),
|
||||
symbol = stringReference("MATIC"),
|
||||
iconUrl = null,
|
||||
isSelected = false,
|
||||
),
|
||||
),
|
||||
onOptionClick = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.tangem.features.feed.ui.earn.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.inputrow.InputRowChecked
|
||||
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
|
||||
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.feed.impl.R
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterByTypeBottomSheetContentUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
|
||||
|
||||
@Composable
|
||||
internal fun EarnFilterByTypeBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet<EarnFilterByTypeBottomSheetContentUM>(
|
||||
config = config,
|
||||
titleText = resourceReference(R.string.earn_filter_by),
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
content = { Content(it) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(content: EarnFilterByTypeBottomSheetContentUM) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
) {
|
||||
EarnFilterTypeUM.entries.forEachIndexed { index, type ->
|
||||
DividerContainer(
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = EarnFilterTypeUM.entries.lastIndex,
|
||||
addDefaultPadding = false,
|
||||
)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable { content.onOptionClick(type) },
|
||||
showDivider = index != EarnFilterTypeUM.entries.lastIndex,
|
||||
) {
|
||||
InputRowChecked(
|
||||
text = type.text,
|
||||
checked = type == content.selectedOption,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, heightDp = 640)
|
||||
@Preview(widthDp = 360, heightDp = 640, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview(
|
||||
alwaysShowBottomSheets = true,
|
||||
) {
|
||||
Box(Modifier.background(TangemTheme.colors.background.secondary)) {
|
||||
EarnFilterByTypeBottomSheet(
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = EarnFilterByTypeBottomSheetContentUM(
|
||||
selectedOption = EarnFilterTypeUM.All,
|
||||
onOptionClick = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.feed.ui.earn.state
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
internal data class EarnFilterByNetworkBottomSheetContentUM(
|
||||
val selectedNetwork: EarnFilterNetworkUM,
|
||||
val networks: ImmutableList<EarnFilterNetworkUM>,
|
||||
val onOptionClick: (EarnFilterNetworkUM) -> Unit,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.features.feed.ui.earn.state
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
|
||||
internal data class EarnFilterByTypeBottomSheetContentUM(
|
||||
val selectedOption: EarnFilterTypeUM,
|
||||
val onOptionClick: (EarnFilterTypeUM) -> Unit,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.features.feed.ui.earn.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
internal sealed class EarnFilterNetworkUM {
|
||||
|
||||
abstract val text: TextReference
|
||||
abstract val isSelected: Boolean
|
||||
|
||||
data class AllNetworks(
|
||||
override val text: TextReference,
|
||||
override val isSelected: Boolean,
|
||||
) : EarnFilterNetworkUM()
|
||||
|
||||
data class MyNetworks(
|
||||
override val text: TextReference,
|
||||
override val isSelected: Boolean,
|
||||
) : EarnFilterNetworkUM()
|
||||
|
||||
data class Network(
|
||||
val id: String,
|
||||
override val text: TextReference,
|
||||
val symbol: TextReference,
|
||||
val iconUrl: String?,
|
||||
override val isSelected: Boolean,
|
||||
) : EarnFilterNetworkUM()
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.features.feed.ui.earn.state
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
|
||||
internal enum class EarnFilterTypeUM(val text: TextReference) {
|
||||
All(resourceReference(R.string.earn_filter_all_types)),
|
||||
Staking(resourceReference(R.string.common_staking)),
|
||||
YieldMode(resourceReference(R.string.markets_sort_by_yield_mode_title)),
|
||||
}
|
||||
|
|
@ -12,6 +12,15 @@ internal sealed interface EarnListUM {
|
|||
data class Error(val onRetryClicked: () -> Unit) : EarnListUM
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed interface EarnBestOpportunitiesUM {
|
||||
data object Loading : EarnBestOpportunitiesUM
|
||||
data object Empty : EarnBestOpportunitiesUM
|
||||
data class EmptyFiltered(val onClearFilterClick: () -> Unit) : EarnBestOpportunitiesUM
|
||||
data class Content(val items: ImmutableList<EarnListItemUM>) : EarnBestOpportunitiesUM
|
||||
data class Error(val onRetryClicked: () -> Unit) : EarnBestOpportunitiesUM
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal data class EarnListItemUM(
|
||||
val network: TextReference,
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
package com.tangem.features.feed.ui.earn.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal data class EarnUM(
|
||||
val mostlyUsed: EarnListUM,
|
||||
val bestOpportunities: EarnListUM,
|
||||
val selectedNetworkFilter: EarnFilterUM?,
|
||||
val selectedTypeFilter: EarnFilterUM?,
|
||||
val networkFilters: ImmutableList<EarnFilterUM>,
|
||||
val typeFilters: ImmutableList<EarnFilterUM>,
|
||||
val bestOpportunities: EarnBestOpportunitiesUM,
|
||||
val selectedTypeFilter: EarnFilterTypeUM,
|
||||
val selectedNetworkFilter: EarnFilterNetworkUM,
|
||||
val filterByTypeBottomSheet: TangemBottomSheetConfig,
|
||||
val filterByNetworkBottomSheet: TangemBottomSheetConfig,
|
||||
val onBackClick: () -> Unit,
|
||||
val onNetworkFilterClick: () -> Unit,
|
||||
val onTypeFilterClick: () -> Unit,
|
||||
)
|
||||
) {
|
||||
|
||||
@Immutable
|
||||
internal data class EarnFilterUM(
|
||||
val id: String,
|
||||
val name: TextReference,
|
||||
val isSelected: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
val selectedNetworkFilterText: TextReference
|
||||
get() = selectedNetworkFilter.text
|
||||
|
||||
val selectedTypeFilterText: TextReference
|
||||
get() = selectedTypeFilter.text
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue