Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-12 08:05:42 +01:00
parent 4aa267c951
commit 0548571089
41 changed files with 573 additions and 347 deletions

View file

@ -45,4 +45,14 @@ object EarnDomainModule {
fun provideGetEarnTokensBatchFlowUseCase(repository: EarnRepository): GetEarnTokensBatchFlowUseCase {
return GetEarnTokensBatchFlowUseCase(repository)
}
@Provides
fun provideGetEarnFilterUseCase(repository: EarnRepository): GetEarnFilterUseCase {
return GetEarnFilterUseCase(repository)
}
@Provides
fun provideSetEarnFilterUseCase(repository: EarnRepository): SetEarnFilterUseCase {
return SetEarnFilterUseCase(repository)
}
}

View file

@ -0,0 +1,17 @@
package com.tangem.data.earn.datastore
import com.tangem.datasource.local.datastore.RuntimeStateStore
import com.tangem.domain.earn.model.EarnFilter
import com.tangem.domain.earn.model.EarnFilterNetwork
import com.tangem.domain.earn.model.EarnFilterType
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
internal class EarnFilterStore @Inject constructor() :
RuntimeStateStore<EarnFilter> by RuntimeStateStore(
defaultValue = EarnFilter(
earnFilterNetwork = EarnFilterNetwork.AllNetworks(isSelected = true),
earnFilterType = EarnFilterType.ALL,
),
)

View file

@ -6,7 +6,7 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class EarnNetworksStore @Inject constructor() :
internal class EarnNetworksStore @Inject constructor() :
RuntimeStateStore<EarnNetworks?> by RuntimeStateStore(
defaultValue = null,
)

View file

@ -6,7 +6,7 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class EarnTopTokensStore @Inject constructor() :
internal class EarnTopTokensStore @Inject constructor() :
RuntimeStateStore<EarnTopToken?> by RuntimeStateStore(
defaultValue = null,
)

View file

@ -2,6 +2,7 @@ package com.tangem.data.earn.di
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.data.earn.DefaultEarnErrorResolver
import com.tangem.data.earn.datastore.EarnFilterStore
import com.tangem.data.earn.datastore.EarnNetworksStore
import com.tangem.data.earn.datastore.EarnTopTokensStore
import com.tangem.data.earn.repository.DefaultEarnRepository
@ -31,6 +32,7 @@ internal object EarnDataModule {
userWalletsListRepository: UserWalletsListRepository,
earnNetworksStore: EarnNetworksStore,
earnTopTokensStore: EarnTopTokensStore,
earnFilterStore: EarnFilterStore,
earnErrorResolver: EarnErrorResolver,
excludedBlockchains: ExcludedBlockchains,
): EarnRepository {
@ -42,6 +44,7 @@ internal object EarnDataModule {
earnTopTokensStore = earnTopTokensStore,
earnErrorResolver = earnErrorResolver,
excludedBlockchains = excludedBlockchains,
earnFilterStore = earnFilterStore,
)
}
}

View file

@ -6,6 +6,7 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.data.earn.converter.EarnTokenConverter
import com.tangem.data.earn.datastore.EarnFilterStore
import com.tangem.data.earn.datastore.EarnNetworksStore
import com.tangem.data.earn.datastore.EarnTopTokensStore
import com.tangem.data.earn.repository.batch.EarnTokensBatchFetcher
@ -14,6 +15,7 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.EarnResponse
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.earn.EarnErrorResolver
import com.tangem.domain.earn.model.EarnFilter
import com.tangem.domain.earn.model.EarnTokensBatchFlow
import com.tangem.domain.earn.model.EarnTokensBatchingContext
import com.tangem.domain.earn.repository.EarnRepository
@ -38,6 +40,7 @@ internal class DefaultEarnRepository(
private val userWalletsListRepository: UserWalletsListRepository,
private val earnNetworksStore: EarnNetworksStore,
private val earnTopTokensStore: EarnTopTokensStore,
private val earnFilterStore: EarnFilterStore,
private val earnErrorResolver: EarnErrorResolver,
private val excludedBlockchains: ExcludedBlockchains,
) : EarnRepository {
@ -123,6 +126,14 @@ internal class DefaultEarnRepository(
return earnTopTokensStore.get()
}
override fun observeEarnFilter(): Flow<EarnFilter> {
return earnFilterStore.get()
}
override suspend fun setEarnFilter(filter: EarnFilter) {
earnFilterStore.store(filter)
}
companion object {
internal const val FIRST_PAGE = 1
private const val INITIAL_BATCH_KEY = 0

View file

@ -0,0 +1,9 @@
package com.tangem.domain.earn.model
import kotlinx.serialization.Serializable
@Serializable
data class EarnFilter(
val earnFilterNetwork: EarnFilterNetwork,
val earnFilterType: EarnFilterType,
)

View file

@ -0,0 +1,27 @@
package com.tangem.domain.earn.model
import kotlinx.serialization.Serializable
@Serializable
sealed interface EarnFilterNetwork {
val isSelected: Boolean
@Serializable
data class AllNetworks(
override val isSelected: Boolean,
) : EarnFilterNetwork
@Serializable
data class MyNetworks(
override val isSelected: Boolean,
) : EarnFilterNetwork
@Serializable
data class Specific(
override val isSelected: Boolean,
val id: String,
val symbol: String,
val fullName: String,
) : EarnFilterNetwork
}

View file

@ -0,0 +1,7 @@
package com.tangem.domain.earn.model
enum class EarnFilterType {
ALL,
STAKING,
YIELD,
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.earn.repository
import com.tangem.domain.earn.model.EarnFilter
import com.tangem.domain.earn.model.EarnTokensBatchFlow
import com.tangem.domain.earn.model.EarnTokensBatchingContext
import com.tangem.domain.models.earn.EarnNetworks
@ -23,4 +24,8 @@ interface EarnRepository {
suspend fun fetchTopEarnTokens(limit: Int)
fun observeTopEarnTokens(): Flow<EarnTopToken?>
fun observeEarnFilter(): Flow<EarnFilter>
suspend fun setEarnFilter(filter: EarnFilter)
}

View file

@ -0,0 +1,12 @@
package com.tangem.domain.earn.usecase
import com.tangem.domain.earn.model.EarnFilter
import com.tangem.domain.earn.repository.EarnRepository
import kotlinx.coroutines.flow.Flow
class GetEarnFilterUseCase(private val repository: EarnRepository) {
operator fun invoke(): Flow<EarnFilter> {
return repository.observeEarnFilter()
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.domain.earn.usecase
import com.tangem.domain.earn.model.EarnFilter
import com.tangem.domain.earn.repository.EarnRepository
class SetEarnFilterUseCase(private val repository: EarnRepository) {
suspend operator fun invoke(filter: EarnFilter) {
repository.setEarnFilter(filter)
}
}

View file

@ -19,7 +19,7 @@ import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.features.feed.components.feed.FeedPortfolioRoute
import com.tangem.features.feed.components.feed.FeedBottomSheetRoute
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
import com.tangem.features.feed.model.earn.EarnModel
import com.tangem.features.feed.ui.earn.EarnContent
@ -35,7 +35,7 @@ internal class DefaultEarnComponent(
private val bottomSheetSlot = childSlot(
source = earnModel.bottomSheetNavigation,
serializer = FeedPortfolioRoute.serializer(),
serializer = null,
handleBackButton = false,
childFactory = ::bottomSheetChild,
)
@ -68,10 +68,10 @@ internal class DefaultEarnComponent(
}
private fun bottomSheetChild(
config: FeedPortfolioRoute,
config: FeedBottomSheetRoute,
componentContext: ComponentContext,
): ComposableBottomSheetComponent = when (config) {
is FeedPortfolioRoute.AddToPortfolio -> {
is FeedBottomSheetRoute.AddToPortfolio -> {
addToPortfolioComponentFactory.create(
context = childByContext(componentContext),
params = AddToPortfolioPreselectedDataComponent.Params(
@ -80,6 +80,14 @@ internal class DefaultEarnComponent(
),
)
}
is FeedBottomSheetRoute.NetworkFilter -> EarnNetworkFilterComponent(
context = childByContext(componentContext),
params = config.params,
)
is FeedBottomSheetRoute.TypeFilter -> EarnTypeFilterComponent(
context = childByContext(componentContext),
params = config.params,
)
}
@Serializable

View file

@ -0,0 +1,43 @@
package com.tangem.features.feed.components.earn
import androidx.compose.runtime.Composable
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.earn.model.EarnFilterNetwork
import com.tangem.features.feed.model.earn.filters.EarnNetworkFilterModel
import com.tangem.features.feed.ui.earn.components.EarnFilterByNetworkBottomSheet
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
internal class EarnNetworkFilterComponent @AssistedInject constructor(
@Assisted context: AppComponentContext,
@Assisted private val params: Params,
) : AppComponentContext by context, ComposableBottomSheetComponent {
private val model = getOrCreateModel<EarnNetworkFilterModel, Params>(params = params)
override fun dismiss() {
params.onDismiss()
}
@Composable
override fun BottomSheet() {
val state = model.state.collectAsStateWithLifecycle()
EarnFilterByNetworkBottomSheet(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = ::dismiss,
content = state.value,
),
)
}
data class Params(
val allFilters: List<EarnFilterNetwork>,
val onFilterSelected: (EarnFilterNetwork) -> Unit,
val onDismiss: () -> Unit,
)
}

View file

@ -0,0 +1,44 @@
package com.tangem.features.feed.components.earn
import androidx.compose.runtime.Composable
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.earn.model.EarnFilterType
import com.tangem.features.feed.model.earn.filters.EarnTypeFilterModel
import com.tangem.features.feed.ui.earn.components.EarnFilterByTypeBottomSheet
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
internal class EarnTypeFilterComponent @AssistedInject constructor(
@Assisted context: AppComponentContext,
@Assisted private val params: Params,
) : AppComponentContext by context, ComposableBottomSheetComponent {
private val model = getOrCreateModel<EarnTypeFilterModel, Params>(params = params)
override fun dismiss() {
params.onDismiss()
}
@Composable
override fun BottomSheet() {
val state = model.state.collectAsStateWithLifecycle()
EarnFilterByTypeBottomSheet(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = ::dismiss,
content = state.value,
),
)
}
data class Params(
val selectedFilter: EarnFilterType,
val onFilterSelected: (EarnFilterType) -> Unit,
val onDismiss: () -> Unit,
)
}

View file

@ -15,7 +15,9 @@ import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
import com.tangem.core.ui.decompose.EmptyComposableBottomSheetComponent
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent.Params
import com.tangem.features.feed.model.feed.FeedComponentModel
import com.tangem.features.feed.model.feed.FeedModelClickIntents
import com.tangem.features.feed.ui.feed.FeedList
@ -31,7 +33,7 @@ internal class DefaultFeedComponent(
private val bottomSheetSlot = childSlot(
source = feedComponentModel.bottomSheetNavigation,
serializer = FeedPortfolioRoute.serializer(),
serializer = null,
handleBackButton = false,
childFactory = ::bottomSheetChild,
)
@ -64,18 +66,20 @@ internal class DefaultFeedComponent(
}
private fun bottomSheetChild(
config: FeedPortfolioRoute,
config: FeedBottomSheetRoute,
componentContext: ComponentContext,
): ComposableBottomSheetComponent = when (config) {
is FeedPortfolioRoute.AddToPortfolio -> {
is FeedBottomSheetRoute.AddToPortfolio -> {
addToPortfolioComponentFactory.create(
context = childByContext(componentContext),
params = AddToPortfolioPreselectedDataComponent.Params(
params = Params(
tokenToAdd = config.tokenToAdd,
callback = feedComponentModel.addToPortfolioCallback,
),
)
}
is FeedBottomSheetRoute.NetworkFilter -> EmptyComposableBottomSheetComponent
is FeedBottomSheetRoute.TypeFilter -> EmptyComposableBottomSheetComponent
}
data class FeedParams(val feedClickIntents: FeedModelClickIntents)

View file

@ -0,0 +1,14 @@
package com.tangem.features.feed.components.feed
import com.tangem.features.feed.components.earn.EarnNetworkFilterComponent
import com.tangem.features.feed.components.earn.EarnTypeFilterComponent
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
internal sealed interface FeedBottomSheetRoute {
data class AddToPortfolio(val tokenToAdd: AddToPortfolioPreselectedDataComponent.TokenToAdd) : FeedBottomSheetRoute
data class NetworkFilter(val params: EarnNetworkFilterComponent.Params) : FeedBottomSheetRoute
data class TypeFilter(val params: EarnTypeFilterComponent.Params) : FeedBottomSheetRoute
}

View file

@ -1,11 +0,0 @@
package com.tangem.features.feed.components.feed
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
import kotlinx.serialization.Serializable
@Serializable
sealed interface FeedPortfolioRoute {
@Serializable
data class AddToPortfolio(val tokenToAdd: AddToPortfolioPreselectedDataComponent.TokenToAdd) : FeedPortfolioRoute
}

View file

@ -4,6 +4,8 @@ import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.feed.model.FeedEntryModel
import com.tangem.features.feed.model.earn.EarnModel
import com.tangem.features.feed.model.earn.filters.EarnNetworkFilterModel
import com.tangem.features.feed.model.earn.filters.EarnTypeFilterModel
import com.tangem.features.feed.model.feed.FeedComponentModel
import com.tangem.features.feed.model.market.details.MarketsTokenDetailsModel
import com.tangem.features.feed.model.market.list.MarketsListModel
@ -53,4 +55,14 @@ internal interface ModelModule {
@IntoMap
@ClassKey(FeedEntryModel::class)
fun provideFeedEntryModel(model: FeedEntryModel): Model
@Binds
@IntoMap
@ClassKey(EarnNetworkFilterModel::class)
fun provideEarnNetworkFilterModel(model: EarnNetworkFilterModel): Model
@Binds
@IntoMap
@ClassKey(EarnTypeFilterModel::class)
fun provideEarnTypeFilterModel(model: EarnTypeFilterModel): Model
}

View file

@ -5,14 +5,14 @@ import arrow.core.Either
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.common.R
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
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.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.earn.model.EarnFilter
import com.tangem.domain.earn.model.EarnFilterNetwork
import com.tangem.domain.earn.model.EarnFilterType
import com.tangem.domain.earn.usecase.*
import com.tangem.domain.markets.TokenMarketInfo
import com.tangem.domain.models.currency.CryptoCurrency
@ -20,17 +20,26 @@ import com.tangem.domain.models.earn.EarnNetworks
import com.tangem.domain.models.earn.EarnTokenWithCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.features.feed.components.earn.DefaultEarnComponent
import com.tangem.features.feed.components.feed.FeedPortfolioRoute
import com.tangem.features.feed.components.earn.EarnNetworkFilterComponent
import com.tangem.features.feed.components.earn.EarnTypeFilterComponent
import com.tangem.features.feed.components.feed.FeedBottomSheetRoute
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
import com.tangem.features.feed.model.earn.filters.state.EarnFilterNetworkConverter
import com.tangem.features.feed.model.earn.filters.state.EarnFilterNetworkUMConverter
import com.tangem.features.feed.model.earn.filters.state.EarnFilterTypeConverter
import com.tangem.features.feed.model.earn.filters.state.EarnFilterTypeUMConverter
import com.tangem.features.feed.model.earn.state.EarnStateController
import com.tangem.features.feed.model.earn.state.converter.EarnNetworksConverter
import com.tangem.features.feed.model.earn.state.transformers.*
import com.tangem.features.feed.model.earn.state.transformers.EarnFilterSelectedStateTransformer
import com.tangem.features.feed.model.earn.state.transformers.UpdateBestOpportunitiesStateTransformer
import com.tangem.features.feed.model.earn.state.transformers.UpdateEarnUMInitialStateTransformer
import com.tangem.features.feed.model.earn.state.transformers.UpdateMostlyUsedStateTransformer
import com.tangem.features.feed.model.earn.statemanager.EarnListBatchFlowManager
import com.tangem.features.feed.model.earn.statemanager.EarnListStateManager
import com.tangem.features.feed.ui.earn.state.*
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.EarnUM
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -46,13 +55,14 @@ internal class EarnModel @Inject constructor(
private val getEarnTokensBatchFlowUseCase: GetEarnTokensBatchFlowUseCase,
private val getTopEarnTokensUseCase: GetTopEarnTokensUseCase,
private val fetchTopEarnTokensUseCase: FetchTopEarnTokensUseCase,
private val getEarnFilterUseCase: GetEarnFilterUseCase,
private val setEarnFilterUseCase: SetEarnFilterUseCase,
private val appRouter: AppRouter,
private val stateController: EarnStateController,
) : Model() {
private val params = paramsContainer.require<DefaultEarnComponent.Params>()
private val earnNetworks = MutableStateFlow<EarnNetworks>(Either.Right(emptyList()))
private val earnNetworksConverter: EarnNetworksConverter by lazy { EarnNetworksConverter() }
private val earnListConfigProvider = Provider {
createEarnTokensListConfig(
selectedTypeFilter = stateController.value.selectedTypeFilter,
@ -61,17 +71,15 @@ internal class EarnModel @Inject constructor(
)
}
private val batchFlowManager by lazy {
EarnListBatchFlowManager(
getEarnTokensBatchFlowUseCase = getEarnTokensBatchFlowUseCase,
configProvider = earnListConfigProvider,
onItemClick = ::onEarnTokenClick,
modelScope = modelScope,
dispatchers = dispatchers,
)
}
private val batchFlowManager = EarnListBatchFlowManager(
getEarnTokensBatchFlowUseCase = getEarnTokensBatchFlowUseCase,
configProvider = earnListConfigProvider,
onItemClick = ::onEarnTokenClick,
modelScope = modelScope,
dispatchers = dispatchers,
)
val bottomSheetNavigation: SlotNavigation<FeedPortfolioRoute> = SlotNavigation()
val bottomSheetNavigation: SlotNavigation<FeedBottomSheetRoute> = SlotNavigation()
val addToPortfolioCallback = object : AddToPortfolioPreselectedDataComponent.Callback {
override fun onDismiss() = bottomSheetNavigation.dismiss()
@ -93,6 +101,7 @@ internal class EarnModel @Inject constructor(
updateInitialState()
fetchEarnNetworks()
fetchTopEarnTokens()
subscribeOnStoredFilters()
subscribeOnNetworks()
subscribeOnBatchFlow()
subscribeToMostlyUsed()
@ -117,9 +126,7 @@ internal class EarnModel @Inject constructor(
)
}.onEach { bestOpportunitiesState ->
stateController.update(UpdateBestOpportunitiesStateTransformer(bestOpportunitiesState))
}
.onStart { batchFlowManager.reload() }
.launchIn(modelScope)
}.launchIn(modelScope)
}
private fun subscribeToMostlyUsed() {
@ -142,6 +149,23 @@ internal class EarnModel @Inject constructor(
}
}
private fun subscribeOnStoredFilters() {
modelScope.launch(dispatchers.default) {
getEarnFilterUseCase()
.collect { filter ->
val typeFilterUM = EarnFilterTypeConverter().convert(filter.earnFilterType)
val networkFilterUM = EarnFilterNetworkConverter().convert(filter.earnFilterNetwork)
stateController.update(
EarnFilterSelectedStateTransformer(
filterType = typeFilterUM,
filterNetwork = networkFilterUM,
),
)
batchFlowManager.reload()
}
}
}
private fun fetchTopEarnTokens() {
modelScope.launch(dispatchers.default) {
fetchTopEarnTokensUseCase()
@ -154,142 +178,73 @@ internal class EarnModel @Inject constructor(
}
}
private fun createTypeFilterBottomSheetConfig(
selectedOption: EarnFilterTypeUM,
isShown: Boolean = false,
): TangemBottomSheetConfig {
return TangemBottomSheetConfig(
isShown = isShown,
onDismissRequest = ::hideTypeFilterBottomSheet,
content = EarnFilterByTypeBottomSheetContentUM(
selectedOption = selectedOption,
onOptionClick = ::onTypeFilterOptionSelected,
),
)
}
private fun createNetworkFilterBottomSheetConfig(
selectedNetwork: EarnFilterNetworkUM,
isShown: Boolean = false,
): TangemBottomSheetConfig {
val filters = buildList {
add(
EarnFilterNetworkUM.AllNetworks(
text = TextReference.Res(R.string.earn_filter_all_networks),
isSelected = false,
),
)
add(
EarnFilterNetworkUM.MyNetworks(
text = TextReference.Res(R.string.earn_filter_my_networks),
isSelected = false,
),
)
earnNetworks.value.onRight { networks ->
addAll(networks.map(earnNetworksConverter::convert))
}
}
val updatedNetworks = filters.map { filter ->
val shouldBeSelected = when (filter) {
is EarnFilterNetworkUM.AllNetworks -> selectedNetwork is EarnFilterNetworkUM.AllNetworks
is EarnFilterNetworkUM.MyNetworks -> selectedNetwork is EarnFilterNetworkUM.MyNetworks
is EarnFilterNetworkUM.Network ->
selectedNetwork is EarnFilterNetworkUM.Network && filter.id == selectedNetwork.id
}
if (filter.isSelected != shouldBeSelected) {
when (filter) {
is EarnFilterNetworkUM.AllNetworks -> filter.copy(isSelected = shouldBeSelected)
is EarnFilterNetworkUM.MyNetworks -> filter.copy(isSelected = shouldBeSelected)
is EarnFilterNetworkUM.Network -> filter.copy(isSelected = shouldBeSelected)
}
} else {
filter
}
}
return TangemBottomSheetConfig(
isShown = isShown,
onDismissRequest = ::hideNetworkFilterBottomSheet,
content = EarnFilterByNetworkBottomSheetContentUM(
selectedNetwork = selectedNetwork,
networks = persistentListOf(*updatedNetworks.toTypedArray()),
onOptionClick = ::onNetworkFilterOptionSelected,
),
)
}
/* start of clicks area */
private fun onTypeFilterClick() {
stateController.update(
EarnTypeFilterStateTransformer(
shouldShow = true,
filterByTypeBottomSheetConfig = ::createTypeFilterBottomSheetConfig,
),
)
}
private fun hideTypeFilterBottomSheet() {
stateController.update(
EarnTypeFilterStateTransformer(
shouldShow = false,
filterByTypeBottomSheetConfig = ::createTypeFilterBottomSheetConfig,
val currentState = state.value
bottomSheetNavigation.activate(
FeedBottomSheetRoute.TypeFilter(
params = EarnTypeFilterComponent.Params(
selectedFilter = EarnFilterTypeUMConverter().convert(currentState.selectedTypeFilter),
onFilterSelected = ::onTypeFilterOptionSelected,
onDismiss = { bottomSheetNavigation.dismiss() },
),
),
)
}
private fun onNetworkFilterClick() {
stateController.update(
EarnNetworkFilterStateTransformer(
shouldShow = true,
filterByNetworkBottomSheetConfig = ::createNetworkFilterBottomSheetConfig,
bottomSheetNavigation.activate(
FeedBottomSheetRoute.NetworkFilter(
params = EarnNetworkFilterComponent.Params(
allFilters = createNetworkFilters(),
onFilterSelected = ::onNetworkFilterOptionSelected,
onDismiss = { bottomSheetNavigation.dismiss() },
),
),
)
}
private fun hideNetworkFilterBottomSheet() {
stateController.update(
EarnNetworkFilterStateTransformer(
shouldShow = false,
filterByNetworkBottomSheetConfig = ::createNetworkFilterBottomSheetConfig,
),
)
}
private fun onTypeFilterOptionSelected(type: EarnFilterTypeUM) {
stateController.update(
EarnTypeFilterSelectedStateTransformer(
filter = type,
filterByTypeBottomSheetConfig = ::createTypeFilterBottomSheetConfig,
),
)
batchFlowManager.reload()
}
private fun onNetworkFilterOptionSelected(network: EarnFilterNetworkUM) {
stateController.update(
EarnNetworkFilterSelectedStateTransformer(
filter = network,
filterByNetworkBottomSheetConfig = ::createNetworkFilterBottomSheetConfig,
),
)
batchFlowManager.reload()
private fun createNetworkFilters(): List<EarnFilterNetwork> {
val selectedFilter = state.value.selectedNetworkFilter
return buildList {
add(
EarnFilterNetwork.AllNetworks(
isSelected = selectedFilter is EarnFilterNetworkUM.AllNetworks,
),
)
add(
EarnFilterNetwork.MyNetworks(
isSelected = selectedFilter is EarnFilterNetworkUM.MyNetworks,
),
)
earnNetworks.value.onRight { networks ->
networks.mapTo(this) { network ->
EarnFilterNetwork.Specific(
id = network.networkId,
isSelected = selectedFilter is EarnFilterNetworkUM.Network &&
selectedFilter.id == network.networkId,
symbol = network.symbol,
fullName = network.fullName,
)
}
}
}
}
private fun onClearFiltersClick() {
stateController.update(
ClearEarnUMFilterStateTransformer(
filterByTypeBottomSheetConfig = ::createTypeFilterBottomSheetConfig,
filterByNetworkBottomSheetConfig = ::createNetworkFilterBottomSheetConfig,
),
)
batchFlowManager.reload()
modelScope.launch(dispatchers.default) {
setEarnFilterUseCase(
EarnFilter(
earnFilterNetwork = EarnFilterNetwork.AllNetworks(isSelected = true),
earnFilterType = EarnFilterType.ALL,
),
)
}
}
private fun onEarnTokenClick(earnTokenWithCurrency: EarnTokenWithCurrency) {
bottomSheetNavigation.activate(
FeedPortfolioRoute.AddToPortfolio(
FeedBottomSheetRoute.AddToPortfolio(
tokenToAdd = AddToPortfolioPreselectedDataComponent.TokenToAdd(
network = TokenMarketInfo.Network(
networkId = earnTokenWithCurrency.earnToken.networkId,
@ -304,6 +259,30 @@ internal class EarnModel @Inject constructor(
),
)
}
private fun onTypeFilterOptionSelected(type: EarnFilterType) {
modelScope.launch(dispatchers.default) {
setEarnFilterUseCase(
EarnFilter(
earnFilterNetwork = EarnFilterNetworkUMConverter().convert(state.value.selectedNetworkFilter),
earnFilterType = type,
),
)
bottomSheetNavigation.dismiss()
}
}
private fun onNetworkFilterOptionSelected(filter: EarnFilterNetwork) {
modelScope.launch(dispatchers.default) {
setEarnFilterUseCase(
EarnFilter(
earnFilterNetwork = filter,
earnFilterType = EarnFilterTypeUMConverter().convert(state.value.selectedTypeFilter),
),
)
}
bottomSheetNavigation.dismiss()
}
/* end of clicks area */
private fun updateInitialState() {
@ -311,10 +290,6 @@ internal class EarnModel @Inject constructor(
UpdateEarnUMInitialStateTransformer(
onBackClick = params.onBackClick,
onNetworkFilterClick = ::onNetworkFilterClick,
filterByTypeBottomSheetConfig = createTypeFilterBottomSheetConfig(state.value.selectedTypeFilter),
filterByNetworkBottomSheetConfig = createNetworkFilterBottomSheetConfig(
selectedNetwork = state.value.selectedNetworkFilter,
),
onTypeFilterClick = ::onTypeFilterClick,
),
)

View file

@ -0,0 +1,37 @@
package com.tangem.features.feed.model.earn.filters
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.features.feed.components.earn.EarnNetworkFilterComponent
import com.tangem.features.feed.model.earn.filters.state.EarnFilterNetworkUMConverter
import com.tangem.features.feed.model.earn.filters.state.EarnFilterNetworkConverter
import com.tangem.features.feed.ui.earn.state.EarnFilterByNetworkBottomSheetContentUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
@Stable
@ModelScoped
internal class EarnNetworkFilterModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
paramsContainer: ParamsContainer,
) : Model() {
private val params = paramsContainer.require<EarnNetworkFilterComponent.Params>()
private val _state = MutableStateFlow(configureInitialState())
val state = _state.asStateFlow()
private fun configureInitialState(): EarnFilterByNetworkBottomSheetContentUM {
return EarnFilterByNetworkBottomSheetContentUM(
networks = params.allFilters
.map { EarnFilterNetworkConverter().convert(it) }
.toPersistentList(),
onOptionClick = { filterUM -> params.onFilterSelected(EarnFilterNetworkUMConverter().convert(filterUM)) },
)
}
}

View file

@ -0,0 +1,36 @@
package com.tangem.features.feed.model.earn.filters
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.features.feed.components.earn.EarnTypeFilterComponent
import com.tangem.features.feed.model.earn.filters.state.EarnFilterTypeConverter
import com.tangem.features.feed.model.earn.filters.state.EarnFilterTypeUMConverter
import com.tangem.features.feed.ui.earn.state.EarnFilterByTypeBottomSheetContentUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
@Stable
@ModelScoped
internal class EarnTypeFilterModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
paramsContainer: ParamsContainer,
) : Model() {
private val params = paramsContainer.require<EarnTypeFilterComponent.Params>()
private val _state = MutableStateFlow(configureInitialState())
val state = _state.asStateFlow()
private fun configureInitialState(): EarnFilterByTypeBottomSheetContentUM {
return EarnFilterByTypeBottomSheetContentUM(
selectedOption = EarnFilterTypeConverter().convert(params.selectedFilter),
onOptionClick = { filterTypeUM ->
params.onFilterSelected(EarnFilterTypeUMConverter().convert(filterTypeUM))
},
)
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.features.feed.model.earn.filters.state
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.domain.earn.model.EarnFilterNetwork
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
import com.tangem.utils.converter.Converter
internal class EarnFilterNetworkConverter : Converter<EarnFilterNetwork, EarnFilterNetworkUM> {
override fun convert(value: EarnFilterNetwork): EarnFilterNetworkUM {
return when (value) {
is EarnFilterNetwork.AllNetworks -> {
EarnFilterNetworkUM.AllNetworks(isSelected = value.isSelected)
}
is EarnFilterNetwork.MyNetworks -> {
EarnFilterNetworkUM.MyNetworks(isSelected = value.isSelected)
}
is EarnFilterNetwork.Specific -> {
EarnFilterNetworkUM.Network(
id = value.id,
text = value.fullName,
symbol = value.symbol,
iconRes = getActiveIconRes(Blockchain.fromNetworkId(value.id)?.id.orEmpty()),
isSelected = value.isSelected,
)
}
}
}
}

View file

@ -0,0 +1,21 @@
package com.tangem.features.feed.model.earn.filters.state
import com.tangem.domain.earn.model.EarnFilterNetwork
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
import com.tangem.utils.converter.Converter
internal class EarnFilterNetworkUMConverter : Converter<EarnFilterNetworkUM, EarnFilterNetwork> {
override fun convert(value: EarnFilterNetworkUM): EarnFilterNetwork {
return when (value) {
is EarnFilterNetworkUM.AllNetworks -> EarnFilterNetwork.AllNetworks(isSelected = value.isSelected)
is EarnFilterNetworkUM.MyNetworks -> EarnFilterNetwork.MyNetworks(isSelected = value.isSelected)
is EarnFilterNetworkUM.Network -> EarnFilterNetwork.Specific(
isSelected = value.isSelected,
id = value.id,
symbol = value.symbol,
fullName = value.text,
)
}
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.features.feed.model.earn.filters.state
import com.tangem.domain.earn.model.EarnFilterType
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
import com.tangem.utils.converter.Converter
internal class EarnFilterTypeConverter : Converter<EarnFilterType, EarnFilterTypeUM> {
override fun convert(value: EarnFilterType): EarnFilterTypeUM {
return when (value) {
EarnFilterType.ALL -> EarnFilterTypeUM.All
EarnFilterType.STAKING -> EarnFilterTypeUM.Staking
EarnFilterType.YIELD -> EarnFilterTypeUM.YieldMode
}
}
}

View file

@ -0,0 +1,16 @@
package com.tangem.features.feed.model.earn.filters.state
import com.tangem.domain.earn.model.EarnFilterType
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
import com.tangem.utils.converter.Converter
internal class EarnFilterTypeUMConverter : Converter<EarnFilterTypeUM, EarnFilterType> {
override fun convert(value: EarnFilterTypeUM): EarnFilterType {
return when (value) {
EarnFilterTypeUM.All -> EarnFilterType.ALL
EarnFilterTypeUM.Staking -> EarnFilterType.STAKING
EarnFilterTypeUM.YieldMode -> EarnFilterType.YIELD
}
}
}

View file

@ -1,9 +1,6 @@
package com.tangem.features.feed.model.earn.state
import com.tangem.common.R
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.feed.model.earn.state.transformers.EarnUMTransformer
import com.tangem.features.feed.ui.earn.state.*
import kotlinx.coroutines.flow.MutableStateFlow
@ -34,12 +31,7 @@ internal class EarnStateController @Inject constructor() {
mostlyUsed = EarnListUM.Loading,
bestOpportunities = EarnBestOpportunitiesUM.Loading,
selectedTypeFilter = EarnFilterTypeUM.All,
selectedNetworkFilter = EarnFilterNetworkUM.AllNetworks(
text = TextReference.Res(R.string.earn_filter_all_networks),
isSelected = true,
),
filterByTypeBottomSheet = TangemBottomSheetConfig.Empty,
filterByNetworkBottomSheet = TangemBottomSheetConfig.Empty,
selectedNetworkFilter = EarnFilterNetworkUM.AllNetworks(isSelected = true),
onBackClick = {},
onNetworkFilterClick = {},
onTypeFilterClick = {},

View file

@ -1,22 +0,0 @@
package com.tangem.features.feed.model.earn.state.converter
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.domain.models.earn.EarnNetwork
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
import com.tangem.utils.converter.Converter
internal class EarnNetworksConverter : Converter<EarnNetwork, EarnFilterNetworkUM.Network> {
override fun convert(value: EarnNetwork): EarnFilterNetworkUM.Network {
return EarnFilterNetworkUM.Network(
id = value.networkId,
text = TextReference.Str(value.fullName),
symbol = TextReference.Str(value.symbol),
iconRes = getActiveIconRes(Blockchain.fromNetworkId(value.networkId)?.id.orEmpty()),
isSelected = false,
)
}
}

View file

@ -1,28 +0,0 @@
package com.tangem.features.feed.model.earn.state.transformers
import com.tangem.common.R
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.TextReference
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.EarnUM
internal class ClearEarnUMFilterStateTransformer(
private val filterByTypeBottomSheetConfig: (EarnFilterTypeUM, Boolean) -> TangemBottomSheetConfig,
private val filterByNetworkBottomSheetConfig: (EarnFilterNetworkUM, Boolean) -> TangemBottomSheetConfig,
) : EarnUMTransformer {
override fun transform(prevState: EarnUM): EarnUM {
val defaultNetworksFilter = EarnFilterNetworkUM.AllNetworks(
text = TextReference.Res(R.string.earn_filter_all_networks),
isSelected = true,
)
return prevState.copy(
selectedTypeFilter = EarnFilterTypeUM.All,
selectedNetworkFilter = defaultNetworksFilter,
filterByTypeBottomSheet = filterByTypeBottomSheetConfig(EarnFilterTypeUM.All, false),
filterByNetworkBottomSheet = filterByNetworkBottomSheetConfig(defaultNetworksFilter, false),
)
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.feed.model.earn.state.transformers
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.EarnUM
internal class EarnFilterSelectedStateTransformer(
private val filterType: EarnFilterTypeUM,
private val filterNetwork: EarnFilterNetworkUM,
) : EarnUMTransformer {
override fun transform(prevState: EarnUM): EarnUM {
return prevState.copy(
selectedTypeFilter = filterType,
selectedNetworkFilter = filterNetwork,
)
}
}

View file

@ -1,18 +1,13 @@
package com.tangem.features.feed.model.earn.state.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
import com.tangem.features.feed.ui.earn.state.EarnUM
internal class EarnNetworkFilterSelectedStateTransformer(
private val filter: EarnFilterNetworkUM,
private val filterByNetworkBottomSheetConfig: (EarnFilterNetworkUM, Boolean) -> TangemBottomSheetConfig,
) : EarnUMTransformer {
override fun transform(prevState: EarnUM): EarnUM {
return prevState.copy(
selectedNetworkFilter = filter,
filterByNetworkBottomSheet = filterByNetworkBottomSheetConfig(filter, false),
)
return prevState.copy(selectedNetworkFilter = filter)
}
}

View file

@ -1,21 +0,0 @@
package com.tangem.features.feed.model.earn.state.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.features.feed.ui.earn.state.EarnFilterNetworkUM
import com.tangem.features.feed.ui.earn.state.EarnUM
internal class EarnNetworkFilterStateTransformer(
private val shouldShow: Boolean,
private val filterByNetworkBottomSheetConfig: (EarnFilterNetworkUM, Boolean) -> TangemBottomSheetConfig,
) : EarnUMTransformer {
override fun transform(prevState: EarnUM): EarnUM {
return if (shouldShow) {
prevState.copy(
filterByNetworkBottomSheet = filterByNetworkBottomSheetConfig(prevState.selectedNetworkFilter, true),
)
} else {
prevState.copy(filterByNetworkBottomSheet = prevState.filterByNetworkBottomSheet.copy(isShown = false))
}
}
}

View file

@ -1,18 +0,0 @@
package com.tangem.features.feed.model.earn.state.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
import com.tangem.features.feed.ui.earn.state.EarnUM
internal class EarnTypeFilterSelectedStateTransformer(
private val filter: EarnFilterTypeUM,
private val filterByTypeBottomSheetConfig: (EarnFilterTypeUM, Boolean) -> TangemBottomSheetConfig,
) : EarnUMTransformer {
override fun transform(prevState: EarnUM): EarnUM {
return prevState.copy(
selectedTypeFilter = filter,
filterByTypeBottomSheet = filterByTypeBottomSheetConfig(filter, false),
)
}
}

View file

@ -1,21 +0,0 @@
package com.tangem.features.feed.model.earn.state.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.features.feed.ui.earn.state.EarnFilterTypeUM
import com.tangem.features.feed.ui.earn.state.EarnUM
internal class EarnTypeFilterStateTransformer(
private val shouldShow: Boolean,
private val filterByTypeBottomSheetConfig: (EarnFilterTypeUM, Boolean) -> TangemBottomSheetConfig,
) : EarnUMTransformer {
override fun transform(prevState: EarnUM): EarnUM {
return if (shouldShow) {
prevState.copy(
filterByTypeBottomSheet = filterByTypeBottomSheetConfig(prevState.selectedTypeFilter, true),
)
} else {
prevState.copy(filterByTypeBottomSheet = prevState.filterByTypeBottomSheet.copy(isShown = false))
}
}
}

View file

@ -1,12 +1,9 @@
package com.tangem.features.feed.model.earn.state.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.features.feed.ui.earn.state.EarnUM
internal class UpdateEarnUMInitialStateTransformer(
private val onBackClick: () -> Unit,
private val filterByTypeBottomSheetConfig: TangemBottomSheetConfig,
private val filterByNetworkBottomSheetConfig: TangemBottomSheetConfig,
private val onNetworkFilterClick: () -> Unit,
private val onTypeFilterClick: () -> Unit,
) : EarnUMTransformer {
@ -14,8 +11,6 @@ internal class UpdateEarnUMInitialStateTransformer(
override fun transform(prevState: EarnUM): EarnUM {
return prevState.copy(
onBackClick = onBackClick,
filterByNetworkBottomSheet = filterByNetworkBottomSheetConfig,
filterByTypeBottomSheet = filterByTypeBottomSheetConfig,
onNetworkFilterClick = onNetworkFilterClick,
onTypeFilterClick = onTypeFilterClick,
)

View file

@ -29,7 +29,7 @@ import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.news.usecase.FetchTrendingNewsUseCase
import com.tangem.domain.news.usecase.ManageTrendingNewsUseCase
import com.tangem.features.feed.components.feed.DefaultFeedComponent
import com.tangem.features.feed.components.feed.FeedPortfolioRoute
import com.tangem.features.feed.components.feed.FeedBottomSheetRoute
import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioPreselectedDataComponent
import com.tangem.features.feed.entry.featuretoggle.FeedFeatureToggle
import com.tangem.features.feed.impl.R
@ -89,7 +89,7 @@ internal class FeedComponentModel @Inject constructor(
dispatchers = dispatchers,
)
val bottomSheetNavigation: SlotNavigation<FeedPortfolioRoute> = SlotNavigation()
val bottomSheetNavigation: SlotNavigation<FeedBottomSheetRoute> = SlotNavigation()
val addToPortfolioCallback = object : AddToPortfolioPreselectedDataComponent.Callback {
override fun onDismiss() = bottomSheetNavigation.dismiss()
@ -398,7 +398,7 @@ internal class FeedComponentModel @Inject constructor(
private fun handleEarnTokenClick(earnTokenWithCurrency: EarnTokenWithCurrency) {
bottomSheetNavigation.activate(
FeedPortfolioRoute.AddToPortfolio(
FeedBottomSheetRoute.AddToPortfolio(
tokenToAdd = AddToPortfolioPreselectedDataComponent.TokenToAdd(
network = TokenMarketInfo.Network(
networkId = earnTokenWithCurrency.earnToken.networkId,

View file

@ -24,7 +24,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
@ -37,7 +36,9 @@ 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.features.feed.ui.earn.components.*
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.*
import kotlinx.collections.immutable.persistentListOf
@ -50,9 +51,6 @@ internal fun EarnContent(state: EarnUM, modifier: Modifier = Modifier) {
val bottomBarHeight = with(density) { WindowInsets.systemBars.getBottom(this).toDp() }
val listState = rememberLazyListState()
EarnFilterByTypeBottomSheet(config = state.filterByTypeBottomSheet)
EarnFilterByNetworkBottomSheet(config = state.filterByNetworkBottomSheet)
if (state.bestOpportunities is EarnBestOpportunitiesUM.Content) {
PaginationHandler(
listState = listState,
@ -89,7 +87,11 @@ internal fun EarnContent(state: EarnUM, modifier: Modifier = Modifier) {
SpacerH(12.dp)
BestOpportunitiesFilters(
state = state.bestOpportunities,
selectedNetworkFilterText = state.selectedNetworkFilterText,
selectedNetworkFilterText = when (state.selectedNetworkFilter) {
is EarnFilterNetworkUM.AllNetworks -> TextReference.Res(R.string.earn_filter_all_networks)
is EarnFilterNetworkUM.MyNetworks -> TextReference.Res(R.string.earn_filter_my_networks)
is EarnFilterNetworkUM.Network -> TextReference.Str(state.selectedNetworkFilter.text)
},
selectedTypeFilterText = state.selectedTypeFilterText,
onNetworkFilterClick = state.onNetworkFilterClick,
onTypeFilterClick = state.onTypeFilterClick,
@ -573,12 +575,7 @@ private fun previewEarnUM(
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,
selectedNetworkFilter = EarnFilterNetworkUM.AllNetworks(isSelected = true),
onBackClick = {},
onNetworkFilterClick = {},
onTypeFilterClick = {},

View file

@ -28,9 +28,8 @@ 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.TextReference
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
@ -106,7 +105,11 @@ private fun LazyListScope.allMyNetworksList(
showDivider = index != allMyNetworks.lastIndex,
) {
InputRowChecked(
text = item.text,
text = when (item) {
is EarnFilterNetworkUM.AllNetworks -> TextReference.Res(R.string.earn_filter_all_networks)
is EarnFilterNetworkUM.MyNetworks -> TextReference.Res(R.string.earn_filter_my_networks)
is EarnFilterNetworkUM.Network -> TextReference.Str(item.text)
},
checked = item.isSelected,
)
}
@ -170,13 +173,13 @@ private fun LazyListScope.specificNetworksList(
Image(
modifier = Modifier.size(22.dp),
imageVector = ImageVector.vectorResource(item.iconRes),
contentDescription = item.symbol.resolveReference(),
contentDescription = item.symbol,
)
},
text = {
RowText(
mainText = item.text.resolveReference(),
secondText = item.symbol.resolveReference(),
mainText = item.text,
secondText = item.symbol,
accentMainText = true,
accentSecondText = false,
)
@ -208,30 +211,20 @@ private fun Preview() {
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.AllNetworks(isSelected = true),
EarnFilterNetworkUM.MyNetworks(isSelected = false),
EarnFilterNetworkUM.Network(
id = "ethereum",
text = stringReference("Ethereum"),
symbol = stringReference("ETH"),
text = "Ethereum",
symbol = "ETH",
iconRes = R.drawable.img_btc_22,
isSelected = false,
),
EarnFilterNetworkUM.Network(
id = "polygon",
text = stringReference("Polygon"),
symbol = stringReference("MATIC"),
text = "Polygon",
symbol = "MATIC",
iconRes = R.drawable.img_btc_22,
isSelected = false,
),

View file

@ -4,7 +4,6 @@ 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

View file

@ -1,29 +1,25 @@
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 iconRes: Int,
override val isSelected: Boolean,
val id: String,
val text: String,
val symbol: String,
val iconRes: Int,
) : EarnFilterNetworkUM()
}

View file

@ -1,7 +1,6 @@
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
@Immutable
@ -10,16 +9,11 @@ internal data class EarnUM(
val bestOpportunities: EarnBestOpportunitiesUM,
val selectedTypeFilter: EarnFilterTypeUM,
val selectedNetworkFilter: EarnFilterNetworkUM,
val filterByTypeBottomSheet: TangemBottomSheetConfig,
val filterByNetworkBottomSheet: TangemBottomSheetConfig,
val onBackClick: () -> Unit,
val onNetworkFilterClick: () -> Unit,
val onTypeFilterClick: () -> Unit,
) {
val selectedNetworkFilterText: TextReference
get() = selectedNetworkFilter.text
val selectedTypeFilterText: TextReference
get() = selectedTypeFilter.text
}