diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index ed8c132108..ae10eb765b 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -469,7 +469,13 @@
Send funds using only
Best opportunities
All networks
+ My networks
All types
+ Networks
+ Clear filter
+ Filter by
+ No results
+ The list is temporarily empty as it’s being refreshed. Check back in a moment.
Mostly used
Earn
Hi support team, I\'ve encountered an error with code: %s
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/earn/EarnModel.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/earn/EarnModel.kt
index f1471cf802..2717a8708d 100644
--- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/earn/EarnModel.kt
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/model/earn/EarnModel.kt
@@ -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()
+ // TODO [REDACTED_TASK_KEY] remove mocks
+ private val mockNetworks: ImmutableList = 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
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,
+ ),
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt
index 657d7c312d..63753d95a1 100644
--- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/EarnContent.kt
@@ -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
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnFilterByNetworkBottomSheet.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnFilterByNetworkBottomSheet.kt
new file mode 100644
index 0000000000..6b31102b92
--- /dev/null
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnFilterByNetworkBottomSheet.kt
@@ -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(
+ 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() +
+ content.networks.filterIsInstance()
+ }
+ val specificNetworks = remember(content) { content.networks.filterIsInstance() }
+
+ 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,
+ 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,
+ 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 = {},
+ ),
+ ),
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnFilterByTypeBottomSheet.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnFilterByTypeBottomSheet.kt
new file mode 100644
index 0000000000..7790ff977e
--- /dev/null
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/components/EarnFilterByTypeBottomSheet.kt
@@ -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(
+ 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 = {},
+ ),
+ ),
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterByNetworkBottomSheetContentUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterByNetworkBottomSheetContentUM.kt
new file mode 100644
index 0000000000..101b80fbce
--- /dev/null
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterByNetworkBottomSheetContentUM.kt
@@ -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,
+ val onOptionClick: (EarnFilterNetworkUM) -> Unit,
+) : TangemBottomSheetConfigContent
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterByTypeBottomSheetContentUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterByTypeBottomSheetContentUM.kt
new file mode 100644
index 0000000000..25de36afa0
--- /dev/null
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterByTypeBottomSheetContentUM.kt
@@ -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
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterNetworkUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterNetworkUM.kt
new file mode 100644
index 0000000000..1fd414edf4
--- /dev/null
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterNetworkUM.kt
@@ -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()
+}
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterTypeUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterTypeUM.kt
new file mode 100644
index 0000000000..0738da510c
--- /dev/null
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnFilterTypeUM.kt
@@ -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)),
+}
\ No newline at end of file
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt
index ff28635572..358cab5ee9 100644
--- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnListUM.kt
@@ -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) : EarnBestOpportunitiesUM
+ data class Error(val onRetryClicked: () -> Unit) : EarnBestOpportunitiesUM
+}
+
@Immutable
internal data class EarnListItemUM(
val network: TextReference,
diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnUM.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnUM.kt
index 8425666307..a0b6870d0a 100644
--- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnUM.kt
+++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/earn/state/EarnUM.kt
@@ -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,
- val typeFilters: ImmutableList,
+ 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,
-)
\ No newline at end of file
+ val selectedNetworkFilterText: TextReference
+ get() = selectedNetworkFilter.text
+
+ val selectedTypeFilterText: TextReference
+ get() = selectedTypeFilter.text
+}
\ No newline at end of file