Updated on 2026-08-14
This commit is contained in:
parent
64693f66ca
commit
43f27a2f33
26 changed files with 21 additions and 370 deletions
|
|
@ -353,8 +353,6 @@ internal class FeedComponentModel @Inject constructor(
|
|||
SortByTypeUM.ExperiencedBuyers,
|
||||
SortByTypeUM.TopGainers,
|
||||
SortByTypeUM.TopLosers,
|
||||
SortByTypeUM.Staking,
|
||||
SortByTypeUM.YieldSupply,
|
||||
-> {
|
||||
analyticsEventHandler.send(
|
||||
FeedAnalyticsEvent.TokenListOpened(
|
||||
|
|
@ -439,8 +437,6 @@ internal class FeedComponentModel @Inject constructor(
|
|||
SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers
|
||||
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
|
||||
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
|
||||
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
|
||||
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -341,8 +341,6 @@ internal class FeedMarketsBatchFlowManager(
|
|||
TokenMarketListConfig.Order.Buyers -> SortByTypeUM.ExperiencedBuyers
|
||||
TokenMarketListConfig.Order.TopGainers -> SortByTypeUM.TopGainers
|
||||
TokenMarketListConfig.Order.TopLosers -> SortByTypeUM.TopLosers
|
||||
TokenMarketListConfig.Order.Staking -> SortByTypeUM.Staking
|
||||
TokenMarketListConfig.Order.YieldSupply -> SortByTypeUM.YieldSupply
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.features.feed.model.market.list
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -12,20 +11,11 @@ import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
|||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
|
||||
import com.tangem.domain.markets.ShouldShowYieldModeMarketPromoUseCase
|
||||
import com.tangem.domain.markets.TokenMarketListConfig
|
||||
import com.tangem.domain.markets.toSerializableParam
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.settings.usercountry.models.UserCountryError
|
||||
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
||||
import com.tangem.features.feed.components.market.list.DefaultMarketsTokenListComponent
|
||||
import com.tangem.features.feed.model.market.list.analytics.MarketsListAnalyticsEvent
|
||||
import com.tangem.features.feed.model.market.list.state.ListUM
|
||||
import com.tangem.features.feed.model.market.list.state.MarketsListUM
|
||||
import com.tangem.features.feed.model.market.list.state.MarketsNotificationUM
|
||||
import com.tangem.features.feed.model.market.list.state.SortByTypeUM
|
||||
import com.tangem.features.feed.model.market.list.statemanager.MarketsListBatchFlowManager
|
||||
import com.tangem.features.feed.model.market.list.statemanager.MarketsListUMStateManager
|
||||
|
|
@ -49,11 +39,8 @@ internal class MarketsListModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
shouldShowYieldModeMarketPromoUseCase: ShouldShowYieldModeMarketPromoUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
private val promoRepository: PromoRepository,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getUserCountryUseCase: GetUserCountryUseCase,
|
||||
) : Model() {
|
||||
|
||||
private val updateQuotesJob = JobHolder()
|
||||
|
|
@ -126,61 +113,30 @@ internal class MarketsListModel @Inject constructor(
|
|||
flow = searchMarketsListManager.uiItems,
|
||||
flow2 = searchMarketsListManager.isInInitialLoadingErrorState,
|
||||
flow3 = searchMarketsListManager.isSearchNotFoundState,
|
||||
flow4 = shouldShowYieldModeMarketPromoUseCase(
|
||||
appCurrency = currentAppCurrency.value,
|
||||
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
|
||||
).conflate(),
|
||||
flow5 = getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, isYieldModePromo, userCountry ->
|
||||
) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState ->
|
||||
MarketsItemsData(
|
||||
items = uiItems,
|
||||
isInErrorState = isInInitialLoadingErrorState,
|
||||
isSearchNotFound = isSearchNotFoundState,
|
||||
shouldShowYieldModePromo = isYieldModePromo,
|
||||
userCountry = userCountry,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
combine(
|
||||
flow = mainMarketsListManager.uiItems,
|
||||
flow2 = mainMarketsListManager.isInInitialLoadingErrorState,
|
||||
flow3 = shouldShowYieldModeMarketPromoUseCase(
|
||||
appCurrency = currentAppCurrency.value,
|
||||
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
|
||||
).conflate(),
|
||||
flow4 = getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, shouldShowYieldModePromo, userCountry ->
|
||||
) { uiItems, isInInitialLoadingErrorState ->
|
||||
MarketsItemsData(
|
||||
items = uiItems,
|
||||
isInErrorState = isInInitialLoadingErrorState,
|
||||
isSearchNotFound = false,
|
||||
shouldShowYieldModePromo = shouldShowYieldModePromo,
|
||||
userCountry = userCountry,
|
||||
)
|
||||
}
|
||||
}
|
||||
}.collect { marketsItemsData ->
|
||||
val isApplyFCARestrictions = marketsItemsData.userCountry.getOrNull().needApplyFCARestrictions()
|
||||
val shouldShowYieldModePromo = marketsItemsData.shouldShowYieldModePromo && !isApplyFCARestrictions
|
||||
if (marketsListUMStateManager.state.value.marketsNotificationUM == null && shouldShowYieldModePromo) {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoShown())
|
||||
}
|
||||
|
||||
marketsListUMStateManager.onUiItemsChanged(
|
||||
uiItems = marketsItemsData.items,
|
||||
isInErrorState = marketsItemsData.isInErrorState,
|
||||
isSearchNotFound = marketsItemsData.isSearchNotFound,
|
||||
marketsNotificationUM = if (shouldShowYieldModePromo) {
|
||||
MarketsNotificationUM.YieldSupplyPromo(
|
||||
onClick = {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModeMoreInfoClicked())
|
||||
marketsListUMStateManager.selectedSortByType = SortByTypeUM.YieldSupply
|
||||
},
|
||||
onCloseClick = { onYieldModeNotificationCloseClick() },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -282,14 +238,6 @@ internal class MarketsListModel @Inject constructor(
|
|||
mainMarketsListManager.reload()
|
||||
}
|
||||
|
||||
private fun MarketsListUM.TrendInterval.toBatchRequestInterval(): TokenMarketListConfig.Interval {
|
||||
return when (this) {
|
||||
MarketsListUM.TrendInterval.H24 -> TokenMarketListConfig.Interval.H24
|
||||
MarketsListUM.TrendInterval.D7 -> TokenMarketListConfig.Interval.WEEK
|
||||
MarketsListUM.TrendInterval.M1 -> TokenMarketListConfig.Interval.MONTH
|
||||
}
|
||||
}
|
||||
|
||||
private fun initAnalytics() {
|
||||
searchMarketsListManager
|
||||
.isSearchNotFoundState
|
||||
|
|
@ -331,18 +279,9 @@ internal class MarketsListModel @Inject constructor(
|
|||
}.saveIn(updateQuotesJob)
|
||||
}
|
||||
|
||||
private fun onYieldModeNotificationCloseClick() {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoClosed())
|
||||
modelScope.launch {
|
||||
promoRepository.setMarketsYieldSupplyNotificationHideClicked()
|
||||
}
|
||||
}
|
||||
|
||||
private class MarketsItemsData(
|
||||
val items: ImmutableList<MarketsListItemUM>,
|
||||
val isInErrorState: Boolean,
|
||||
val isSearchNotFound: Boolean,
|
||||
val shouldShowYieldModePromo: Boolean,
|
||||
val userCountry: Either<UserCountryError, UserCountry>,
|
||||
)
|
||||
}
|
||||
|
|
@ -23,8 +23,6 @@ internal sealed class MarketsListAnalyticsEvent(
|
|||
SortByTypeUM.ExperiencedBuyers -> "Buyers"
|
||||
SortByTypeUM.TopGainers -> "Gainers"
|
||||
SortByTypeUM.TopLosers -> "Losers"
|
||||
SortByTypeUM.Staking -> "Staking"
|
||||
SortByTypeUM.YieldSupply -> "Yield Supply"
|
||||
},
|
||||
"Period" to when (interval) {
|
||||
MarketsListUM.TrendInterval.H24 -> "24h"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ internal data class MarketsListUM(
|
|||
val selectedInterval: TrendInterval,
|
||||
val onIntervalClick: (TrendInterval) -> Unit,
|
||||
val onSortByButtonClick: () -> Unit,
|
||||
val marketsNotificationUM: MarketsNotificationUM?,
|
||||
val onSearchClicked: () -> Unit,
|
||||
) {
|
||||
val isInSearchMode
|
||||
|
|
@ -43,8 +42,6 @@ internal enum class SortByTypeUM(val text: TextReference) {
|
|||
ExperiencedBuyers(resourceReference(R.string.markets_sort_by_experienced_buyers_title)),
|
||||
TopGainers(resourceReference(R.string.markets_sort_by_top_gainers_title)),
|
||||
TopLosers(resourceReference(R.string.markets_sort_by_top_losers_title)),
|
||||
Staking(resourceReference(R.string.common_staking)),
|
||||
YieldSupply(resourceReference(R.string.markets_sort_by_yield_mode_title)),
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
package com.tangem.features.feed.model.market.list.state
|
||||
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.feed.impl.R
|
||||
|
||||
internal sealed class MarketsNotificationUM(val config: NotificationConfig) {
|
||||
|
||||
data class YieldSupplyPromo(
|
||||
val onClick: () -> Unit,
|
||||
val onCloseClick: () -> Unit,
|
||||
) : MarketsNotificationUM(
|
||||
config = NotificationConfig(
|
||||
iconResId = R.drawable.img_yield_supply_in_market_notification,
|
||||
title = resourceReference(R.string.markets_yield_supply_banner_title),
|
||||
subtitle = TextReference.EMPTY,
|
||||
onClick = onClick,
|
||||
onCloseClick = onCloseClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -24,8 +24,10 @@ import com.tangem.utils.coroutines.saveIn
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private const val LOG_EVENTS = true
|
||||
|
||||
|
|
@ -305,8 +307,6 @@ internal class MarketsListBatchFlowManager(
|
|||
SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers
|
||||
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
|
||||
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
|
||||
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
|
||||
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,6 @@ internal class MarketsListUMStateManager(
|
|||
isInErrorState: Boolean,
|
||||
isSearchNotFound: Boolean,
|
||||
uiItems: ImmutableList<MarketsListItemUM>,
|
||||
marketsNotificationUM: MarketsNotificationUM?,
|
||||
) {
|
||||
state.update { marketsListUM ->
|
||||
when {
|
||||
|
|
@ -115,19 +114,13 @@ internal class MarketsListUMStateManager(
|
|||
marketsListUM.copy(list = ListUM.Loading)
|
||||
}
|
||||
else -> {
|
||||
marketsListUM.updateItems(
|
||||
newItems = uiItems,
|
||||
marketsNotificationUM = marketsNotificationUM,
|
||||
)
|
||||
marketsListUM.updateItems(newItems = uiItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MarketsListUM.updateItems(
|
||||
newItems: ImmutableList<MarketsListItemUM>,
|
||||
marketsNotificationUM: MarketsNotificationUM?,
|
||||
): MarketsListUM {
|
||||
private fun MarketsListUM.updateItems(newItems: ImmutableList<MarketsListItemUM>): MarketsListUM {
|
||||
val currentState = this
|
||||
|
||||
if (isInSearchMode.not() || currentState.showUnder100kButtonAlreadyPressed()) {
|
||||
|
|
@ -139,7 +132,6 @@ internal class MarketsListUMStateManager(
|
|||
shouldShowUnder100kTokensNotificationWasHidden = currentState
|
||||
.showUnder100kButtonAlreadyPressed(),
|
||||
),
|
||||
marketsNotificationUM = marketsNotificationUM,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +235,6 @@ internal class MarketsListUMStateManager(
|
|||
onOptionClicked = ::onBottomSheetOptionClicked,
|
||||
),
|
||||
),
|
||||
marketsNotificationUM = null,
|
||||
onSearchClicked = {
|
||||
analyticsEventHandler.send(FeedAnalyticsEvent.TokenSearchedClicked())
|
||||
changeSearchBarIsActive(true)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.features.feed.ui.feed.preview
|
|||
|
||||
import com.tangem.common.ui.charts.state.MarketChartRawData
|
||||
import com.tangem.common.ui.markets.models.MarketsListItemUM
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ArticleConfigUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.label.entity.LabelLeadingContentUM
|
||||
|
|
@ -15,6 +14,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.features.feed.model.market.list.state.SortByTypeUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnListItemUM
|
||||
import com.tangem.features.feed.ui.earn.state.EarnListUM
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ArticleConfigUM
|
||||
import com.tangem.features.feed.ui.feed.state.*
|
||||
import kotlinx.collections.immutable.*
|
||||
|
||||
|
|
@ -77,8 +77,6 @@ internal object FeedListPreviewDataProvider {
|
|||
items = items,
|
||||
isSelected = false,
|
||||
),
|
||||
SortByTypeUM.Staking to MarketChartUM.Loading,
|
||||
SortByTypeUM.TopLosers to MarketChartUM.Loading,
|
||||
)
|
||||
|
||||
val ratingChart = if (includeErrorState) {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
|
|||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.keyboardAsState
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -42,12 +44,10 @@ import com.tangem.features.feed.impl.R
|
|||
import com.tangem.features.feed.model.market.list.state.*
|
||||
import com.tangem.features.feed.ui.market.list.components.MarketsListLazyColumn
|
||||
import com.tangem.features.feed.ui.market.list.components.MarketsListSortByBottomSheet
|
||||
import com.tangem.features.feed.ui.market.list.components.YieldSupplyInMarketsPromoNotification
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
private const val SHOW_MORE_KEY = "privacyPolicy"
|
||||
private const val DELAY_FOR_FOCUS_REQUEST = 500L
|
||||
|
||||
@Composable
|
||||
|
|
@ -152,40 +152,6 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
|
|||
onSortByClick = state.onSortByButtonClick,
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
state.list !is ListUM.LoadingError && state.isInSearchMode.not() &&
|
||||
state.selectedSortBy != SortByTypeUM.YieldSupply,
|
||||
) {
|
||||
val wrappedNotification = remember(state.list) { state.marketsNotificationUM }
|
||||
val showMore = stringResourceSafe(R.string.common_show_more)
|
||||
|
||||
when (wrappedNotification) {
|
||||
is MarketsNotificationUM.YieldSupplyPromo -> {
|
||||
val description = stringResourceSafe(
|
||||
R.string.markets_yield_supply_banner_description,
|
||||
showMore,
|
||||
)
|
||||
|
||||
val clickableDescription = annotatedReference {
|
||||
append(description.substringBefore(showMore))
|
||||
|
||||
pushStringAnnotation(SHOW_MORE_KEY, "")
|
||||
appendColored(showMore, TangemTheme.colors.text.accent)
|
||||
pop()
|
||||
}
|
||||
|
||||
YieldSupplyInMarketsPromoNotification(
|
||||
config = wrappedNotification.config.copy(
|
||||
subtitle = clickableDescription,
|
||||
),
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val strokeWidth = TangemTheme.dimens.size0_5
|
||||
|
|
@ -376,10 +342,6 @@ private fun Preview() {
|
|||
onDismissRequest = {},
|
||||
content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {},
|
||||
),
|
||||
marketsNotificationUM = MarketsNotificationUM.YieldSupplyPromo(
|
||||
onClick = {},
|
||||
onCloseClick = {},
|
||||
),
|
||||
onSearchClicked = {},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue