Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-18 18:16:55 +01:00
parent 64693f66ca
commit 43f27a2f33
26 changed files with 21 additions and 370 deletions

View file

@ -4,7 +4,6 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.markets.* import com.tangem.domain.markets.*
import com.tangem.domain.markets.repositories.MarketsTokenRepository import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@ -83,16 +82,4 @@ object MarketsDomainModule {
fun provideGetTokenExchangesUseCase(marketsTokenRepository: MarketsTokenRepository): GetTokenExchangesUseCase { fun provideGetTokenExchangesUseCase(marketsTokenRepository: MarketsTokenRepository): GetTokenExchangesUseCase {
return GetTokenExchangesUseCase(marketsTokenRepository = marketsTokenRepository) return GetTokenExchangesUseCase(marketsTokenRepository = marketsTokenRepository)
} }
@Provides
@Singleton
fun provideShouldShowYieldModeMarketPromoUseCase(
promoRepository: PromoRepository,
marketsTokenRepository: MarketsTokenRepository,
): ShouldShowYieldModeMarketPromoUseCase {
return ShouldShowYieldModeMarketPromoUseCase(
promoRepository = promoRepository,
marketsTokenRepository = marketsTokenRepository,
)
}
} }

View file

@ -79,10 +79,6 @@ object PreferencesKeys {
val SHOULD_SHOW_MARKETS_TOOLTIP_KEY by lazy { booleanPreferencesKey(name = "shouldShowMarketsTooltip") } val SHOULD_SHOW_MARKETS_TOOLTIP_KEY by lazy { booleanPreferencesKey(name = "shouldShowMarketsTooltip") }
val MARKETS_YIELD_SUPPLY_NOTIFICATION_HIDE_CLICKED_KEY by lazy {
booleanPreferencesKey(name = "marketsYieldSupplyNotificationHideClicked")
}
val WALLET_FIRST_USAGE_DATE_KEY by lazy { longPreferencesKey(name = "walletFirstUsageDate") } val WALLET_FIRST_USAGE_DATE_KEY by lazy { longPreferencesKey(name = "walletFirstUsageDate") }
val IS_WALLET_NAMES_MIGRATION_DONE_KEY by lazy { booleanPreferencesKey(name = "isWalletNamesMigrationDone") } val IS_WALLET_NAMES_MIGRATION_DONE_KEY by lazy { booleanPreferencesKey(name = "isWalletNamesMigrationDone") }

View file

@ -19,7 +19,6 @@ import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.markets.TangemTechMarketsApi import com.tangem.datasource.api.markets.TangemTechMarketsApi
import com.tangem.datasource.api.markets.models.response.TokenMarketExchangesResponse import com.tangem.datasource.api.markets.models.response.TokenMarketExchangesResponse
import com.tangem.datasource.local.datastore.RuntimeStateStore import com.tangem.datasource.local.datastore.RuntimeStateStore
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.getSyncStrict import com.tangem.domain.common.wallets.getSyncStrict
import com.tangem.domain.markets.* import com.tangem.domain.markets.*
@ -31,7 +30,6 @@ import com.tangem.pagination.*
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
@ -294,26 +292,6 @@ internal class DefaultMarketsTokenRepository(
} }
} }
override suspend fun showYieldModePromo(
appCurrency: AppCurrency,
interval: TokenMarketListConfig.Interval,
): Boolean = try {
val hasYieldSupplyTokens = marketsApi.getCoinsList(
currency = appCurrency.code,
interval = interval.toRequestParam(),
order = TokenMarketListConfig.Order.YieldSupply.toRequestParam(),
offset = 0,
limit = 40,
timestamp = null,
search = null,
).getOrThrow().tokens.isNotEmpty()
hasYieldSupplyTokens
} catch (error: Exception) {
Timber.e(error)
false
}
inline fun <T> catchListErrorAndSendEvent(block: () -> T): T { inline fun <T> catchListErrorAndSendEvent(block: () -> T): T {
return catchErrorAndSendEvent(block, ::createListErrorEvent) return catchErrorAndSendEvent(block, ::createListErrorEvent)
} }

View file

@ -15,8 +15,6 @@ internal fun TokenMarketListConfig.Order.toRequestParam(): String = when (this)
TokenMarketListConfig.Order.Buyers -> "buyers" TokenMarketListConfig.Order.Buyers -> "buyers"
TokenMarketListConfig.Order.TopGainers -> "gainers" TokenMarketListConfig.Order.TopGainers -> "gainers"
TokenMarketListConfig.Order.TopLosers -> "losers" TokenMarketListConfig.Order.TopLosers -> "losers"
TokenMarketListConfig.Order.Staking -> "staking"
TokenMarketListConfig.Order.YieldSupply -> "yield"
} }
internal fun PriceChangeInterval.toRequestParam(): String = when (this) { internal fun PriceChangeInterval.toRequestParam(): String = when (this) {

View file

@ -96,20 +96,6 @@ internal class DefaultPromoRepository(
appPreferencesStore.store(PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), false) appPreferencesStore.store(PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), false)
} }
override fun isMarketsYieldSupplyNotificationHideClicked(): Flow<Boolean> {
return appPreferencesStore.get(
key = PreferencesKeys.MARKETS_YIELD_SUPPLY_NOTIFICATION_HIDE_CLICKED_KEY,
default = false,
)
}
override suspend fun setMarketsYieldSupplyNotificationHideClicked() {
appPreferencesStore.store(
key = PreferencesKeys.MARKETS_YIELD_SUPPLY_NOTIFICATION_HIDE_CLICKED_KEY,
value = true,
)
}
override suspend fun isMoonpayPromoActive(): Boolean { override suspend fun isMoonpayPromoActive(): Boolean {
val banner = runCatching(dispatchers.io) { val banner = runCatching(dispatchers.io) {
val response = promoBannerStore.getSyncOrNull(MOONPAY_NAME) ?: run { val response = promoBannerStore.getSyncOrNull(MOONPAY_NAME) ?: run {

View file

@ -9,7 +9,7 @@ data class TokenMarketListConfig(
) { ) {
enum class Order { enum class Order {
ByRating, Trending, Buyers, TopGainers, TopLosers, Staking, YieldSupply, ByRating, Trending, Buyers, TopGainers, TopLosers
} }
enum class Interval { enum class Interval {

View file

@ -1,24 +0,0 @@
package com.tangem.domain.markets
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.promo.PromoRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
class ShouldShowYieldModeMarketPromoUseCase(
private val promoRepository: PromoRepository,
private val marketsTokenRepository: MarketsTokenRepository,
) {
operator fun invoke(appCurrency: AppCurrency, interval: TokenMarketListConfig.Interval): Flow<Boolean> {
val hideClickedFlow = promoRepository.isMarketsYieldSupplyNotificationHideClicked()
return hideClickedFlow.map { hideClicked ->
!hideClicked && marketsTokenRepository.showYieldModePromo(
appCurrency = appCurrency,
interval = interval,
)
}
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.domain.markets.repositories package com.tangem.domain.markets.repositories
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.* import com.tangem.domain.markets.*
import com.tangem.domain.models.account.DerivationIndex import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
@ -54,6 +53,4 @@ interface MarketsTokenRepository {
* @param tokenId token id * @param tokenId token id
*/ */
suspend fun getTokenExchanges(tokenId: CryptoCurrency.RawID): List<TokenMarketExchange> suspend fun getTokenExchanges(tokenId: CryptoCurrency.RawID): List<TokenMarketExchange>
suspend fun showYieldModePromo(appCurrency: AppCurrency, interval: TokenMarketListConfig.Interval): Boolean
} }

View file

@ -16,10 +16,6 @@ interface PromoRepository {
suspend fun setNeverToShowTokenPromo(promoId: PromoId) suspend fun setNeverToShowTokenPromo(promoId: PromoId)
fun isMarketsYieldSupplyNotificationHideClicked(): Flow<Boolean>
suspend fun setMarketsYieldSupplyNotificationHideClicked()
suspend fun isMoonpayPromoActive(): Boolean suspend fun isMoonpayPromoActive(): Boolean
// endregion // endregion

View file

@ -353,8 +353,6 @@ internal class FeedComponentModel @Inject constructor(
SortByTypeUM.ExperiencedBuyers, SortByTypeUM.ExperiencedBuyers,
SortByTypeUM.TopGainers, SortByTypeUM.TopGainers,
SortByTypeUM.TopLosers, SortByTypeUM.TopLosers,
SortByTypeUM.Staking,
SortByTypeUM.YieldSupply,
-> { -> {
analyticsEventHandler.send( analyticsEventHandler.send(
FeedAnalyticsEvent.TokenListOpened( FeedAnalyticsEvent.TokenListOpened(
@ -439,8 +437,6 @@ internal class FeedComponentModel @Inject constructor(
SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
} }
} }

View file

@ -341,8 +341,6 @@ internal class FeedMarketsBatchFlowManager(
TokenMarketListConfig.Order.Buyers -> SortByTypeUM.ExperiencedBuyers TokenMarketListConfig.Order.Buyers -> SortByTypeUM.ExperiencedBuyers
TokenMarketListConfig.Order.TopGainers -> SortByTypeUM.TopGainers TokenMarketListConfig.Order.TopGainers -> SortByTypeUM.TopGainers
TokenMarketListConfig.Order.TopLosers -> SortByTypeUM.TopLosers TokenMarketListConfig.Order.TopLosers -> SortByTypeUM.TopLosers
TokenMarketListConfig.Order.Staking -> SortByTypeUM.Staking
TokenMarketListConfig.Order.YieldSupply -> SortByTypeUM.YieldSupply
} }
} }
} }

View file

@ -1,7 +1,6 @@
package com.tangem.features.feed.model.market.list package com.tangem.features.feed.model.market.list
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import arrow.core.Either
import arrow.core.getOrElse import arrow.core.getOrElse
import com.tangem.common.ui.markets.models.MarketsListItemUM import com.tangem.common.ui.markets.models.MarketsListItemUM
import com.tangem.core.analytics.api.AnalyticsEventHandler 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.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase 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.markets.toSerializableParam
import com.tangem.domain.models.currency.CryptoCurrency 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.components.market.list.DefaultMarketsTokenListComponent
import com.tangem.features.feed.model.market.list.analytics.MarketsListAnalyticsEvent 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.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.state.SortByTypeUM
import com.tangem.features.feed.model.market.list.statemanager.MarketsListBatchFlowManager import com.tangem.features.feed.model.market.list.statemanager.MarketsListBatchFlowManager
import com.tangem.features.feed.model.market.list.statemanager.MarketsListUMStateManager import com.tangem.features.feed.model.market.list.statemanager.MarketsListUMStateManager
@ -49,11 +39,8 @@ internal class MarketsListModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider, override val dispatchers: CoroutineDispatcherProvider,
getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase, getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
shouldShowYieldModeMarketPromoUseCase: ShouldShowYieldModeMarketPromoUseCase,
paramsContainer: ParamsContainer, paramsContainer: ParamsContainer,
private val promoRepository: PromoRepository,
private val analyticsEventHandler: AnalyticsEventHandler, private val analyticsEventHandler: AnalyticsEventHandler,
private val getUserCountryUseCase: GetUserCountryUseCase,
) : Model() { ) : Model() {
private val updateQuotesJob = JobHolder() private val updateQuotesJob = JobHolder()
@ -126,61 +113,30 @@ internal class MarketsListModel @Inject constructor(
flow = searchMarketsListManager.uiItems, flow = searchMarketsListManager.uiItems,
flow2 = searchMarketsListManager.isInInitialLoadingErrorState, flow2 = searchMarketsListManager.isInInitialLoadingErrorState,
flow3 = searchMarketsListManager.isSearchNotFoundState, flow3 = searchMarketsListManager.isSearchNotFoundState,
flow4 = shouldShowYieldModeMarketPromoUseCase( ) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState ->
appCurrency = currentAppCurrency.value,
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
).conflate(),
flow5 = getUserCountryUseCase.invoke(),
) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, isYieldModePromo, userCountry ->
MarketsItemsData( MarketsItemsData(
items = uiItems, items = uiItems,
isInErrorState = isInInitialLoadingErrorState, isInErrorState = isInInitialLoadingErrorState,
isSearchNotFound = isSearchNotFoundState, isSearchNotFound = isSearchNotFoundState,
shouldShowYieldModePromo = isYieldModePromo,
userCountry = userCountry,
) )
} }
} else { } else {
combine( combine(
flow = mainMarketsListManager.uiItems, flow = mainMarketsListManager.uiItems,
flow2 = mainMarketsListManager.isInInitialLoadingErrorState, flow2 = mainMarketsListManager.isInInitialLoadingErrorState,
flow3 = shouldShowYieldModeMarketPromoUseCase( ) { uiItems, isInInitialLoadingErrorState ->
appCurrency = currentAppCurrency.value,
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
).conflate(),
flow4 = getUserCountryUseCase.invoke(),
) { uiItems, isInInitialLoadingErrorState, shouldShowYieldModePromo, userCountry ->
MarketsItemsData( MarketsItemsData(
items = uiItems, items = uiItems,
isInErrorState = isInInitialLoadingErrorState, isInErrorState = isInInitialLoadingErrorState,
isSearchNotFound = false, isSearchNotFound = false,
shouldShowYieldModePromo = shouldShowYieldModePromo,
userCountry = userCountry,
) )
} }
} }
}.collect { marketsItemsData -> }.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( marketsListUMStateManager.onUiItemsChanged(
uiItems = marketsItemsData.items, uiItems = marketsItemsData.items,
isInErrorState = marketsItemsData.isInErrorState, isInErrorState = marketsItemsData.isInErrorState,
isSearchNotFound = marketsItemsData.isSearchNotFound, 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() 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() { private fun initAnalytics() {
searchMarketsListManager searchMarketsListManager
.isSearchNotFoundState .isSearchNotFoundState
@ -331,18 +279,9 @@ internal class MarketsListModel @Inject constructor(
}.saveIn(updateQuotesJob) }.saveIn(updateQuotesJob)
} }
private fun onYieldModeNotificationCloseClick() {
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoClosed())
modelScope.launch {
promoRepository.setMarketsYieldSupplyNotificationHideClicked()
}
}
private class MarketsItemsData( private class MarketsItemsData(
val items: ImmutableList<MarketsListItemUM>, val items: ImmutableList<MarketsListItemUM>,
val isInErrorState: Boolean, val isInErrorState: Boolean,
val isSearchNotFound: Boolean, val isSearchNotFound: Boolean,
val shouldShowYieldModePromo: Boolean,
val userCountry: Either<UserCountryError, UserCountry>,
) )
} }

View file

@ -23,8 +23,6 @@ internal sealed class MarketsListAnalyticsEvent(
SortByTypeUM.ExperiencedBuyers -> "Buyers" SortByTypeUM.ExperiencedBuyers -> "Buyers"
SortByTypeUM.TopGainers -> "Gainers" SortByTypeUM.TopGainers -> "Gainers"
SortByTypeUM.TopLosers -> "Losers" SortByTypeUM.TopLosers -> "Losers"
SortByTypeUM.Staking -> "Staking"
SortByTypeUM.YieldSupply -> "Yield Supply"
}, },
"Period" to when (interval) { "Period" to when (interval) {
MarketsListUM.TrendInterval.H24 -> "24h" MarketsListUM.TrendInterval.H24 -> "24h"

View file

@ -19,7 +19,6 @@ internal data class MarketsListUM(
val selectedInterval: TrendInterval, val selectedInterval: TrendInterval,
val onIntervalClick: (TrendInterval) -> Unit, val onIntervalClick: (TrendInterval) -> Unit,
val onSortByButtonClick: () -> Unit, val onSortByButtonClick: () -> Unit,
val marketsNotificationUM: MarketsNotificationUM?,
val onSearchClicked: () -> Unit, val onSearchClicked: () -> Unit,
) { ) {
val isInSearchMode val isInSearchMode
@ -43,8 +42,6 @@ internal enum class SortByTypeUM(val text: TextReference) {
ExperiencedBuyers(resourceReference(R.string.markets_sort_by_experienced_buyers_title)), ExperiencedBuyers(resourceReference(R.string.markets_sort_by_experienced_buyers_title)),
TopGainers(resourceReference(R.string.markets_sort_by_top_gainers_title)), TopGainers(resourceReference(R.string.markets_sort_by_top_gainers_title)),
TopLosers(resourceReference(R.string.markets_sort_by_top_losers_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 @Immutable

View file

@ -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,
),
)
}

View file

@ -24,8 +24,10 @@ import com.tangem.utils.coroutines.saveIn
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
private const val LOG_EVENTS = true private const val LOG_EVENTS = true
@ -305,8 +307,6 @@ internal class MarketsListBatchFlowManager(
SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
} }
} }

View file

@ -99,7 +99,6 @@ internal class MarketsListUMStateManager(
isInErrorState: Boolean, isInErrorState: Boolean,
isSearchNotFound: Boolean, isSearchNotFound: Boolean,
uiItems: ImmutableList<MarketsListItemUM>, uiItems: ImmutableList<MarketsListItemUM>,
marketsNotificationUM: MarketsNotificationUM?,
) { ) {
state.update { marketsListUM -> state.update { marketsListUM ->
when { when {
@ -115,19 +114,13 @@ internal class MarketsListUMStateManager(
marketsListUM.copy(list = ListUM.Loading) marketsListUM.copy(list = ListUM.Loading)
} }
else -> { else -> {
marketsListUM.updateItems( marketsListUM.updateItems(newItems = uiItems)
newItems = uiItems,
marketsNotificationUM = marketsNotificationUM,
)
} }
} }
} }
} }
private fun MarketsListUM.updateItems( private fun MarketsListUM.updateItems(newItems: ImmutableList<MarketsListItemUM>): MarketsListUM {
newItems: ImmutableList<MarketsListItemUM>,
marketsNotificationUM: MarketsNotificationUM?,
): MarketsListUM {
val currentState = this val currentState = this
if (isInSearchMode.not() || currentState.showUnder100kButtonAlreadyPressed()) { if (isInSearchMode.not() || currentState.showUnder100kButtonAlreadyPressed()) {
@ -139,7 +132,6 @@ internal class MarketsListUMStateManager(
shouldShowUnder100kTokensNotificationWasHidden = currentState shouldShowUnder100kTokensNotificationWasHidden = currentState
.showUnder100kButtonAlreadyPressed(), .showUnder100kButtonAlreadyPressed(),
), ),
marketsNotificationUM = marketsNotificationUM,
) )
} }
@ -243,7 +235,6 @@ internal class MarketsListUMStateManager(
onOptionClicked = ::onBottomSheetOptionClicked, onOptionClicked = ::onBottomSheetOptionClicked,
), ),
), ),
marketsNotificationUM = null,
onSearchClicked = { onSearchClicked = {
analyticsEventHandler.send(FeedAnalyticsEvent.TokenSearchedClicked()) analyticsEventHandler.send(FeedAnalyticsEvent.TokenSearchedClicked())
changeSearchBarIsActive(true) changeSearchBarIsActive(true)

View file

@ -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.charts.state.MarketChartRawData
import com.tangem.common.ui.markets.models.MarketsListItemUM 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.R
import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.label.entity.LabelLeadingContentUM 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.model.market.list.state.SortByTypeUM
import com.tangem.features.feed.ui.earn.state.EarnListItemUM 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.EarnListUM
import com.tangem.features.feed.ui.feed.components.articles.ArticleConfigUM
import com.tangem.features.feed.ui.feed.state.* import com.tangem.features.feed.ui.feed.state.*
import kotlinx.collections.immutable.* import kotlinx.collections.immutable.*
@ -77,8 +77,6 @@ internal object FeedListPreviewDataProvider {
items = items, items = items,
isSelected = false, isSelected = false,
), ),
SortByTypeUM.Staking to MarketChartUM.Loading,
SortByTypeUM.TopLosers to MarketChartUM.Loading,
) )
val ratingChart = if (includeErrorState) { val ratingChart = if (includeErrorState) {

View file

@ -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.fields.entity.SearchBarUM
import com.tangem.core.ui.components.keyboardAsState import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.event.consumedEvent 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.LocalMainBottomSheetColor
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview 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.model.market.list.state.*
import com.tangem.features.feed.ui.market.list.components.MarketsListLazyColumn 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.MarketsListSortByBottomSheet
import com.tangem.features.feed.ui.market.list.components.YieldSupplyInMarketsPromoNotification
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
private const val SHOW_MORE_KEY = "privacyPolicy"
private const val DELAY_FOR_FOCUS_REQUEST = 500L private const val DELAY_FOR_FOCUS_REQUEST = 500L
@Composable @Composable
@ -152,40 +152,6 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
onSortByClick = state.onSortByButtonClick, 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 val strokeWidth = TangemTheme.dimens.size0_5
@ -376,10 +342,6 @@ private fun Preview() {
onDismissRequest = {}, onDismissRequest = {},
content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {}, content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {},
), ),
marketsNotificationUM = MarketsNotificationUM.YieldSupplyPromo(
onClick = {},
onCloseClick = {},
),
onSearchClicked = {}, onSearchClicked = {},
), ),
) )

View file

@ -23,8 +23,6 @@ internal sealed class MarketsListAnalyticsEvent(
SortByTypeUM.ExperiencedBuyers -> "Buyers" SortByTypeUM.ExperiencedBuyers -> "Buyers"
SortByTypeUM.TopGainers -> "Gainers" SortByTypeUM.TopGainers -> "Gainers"
SortByTypeUM.TopLosers -> "Losers" SortByTypeUM.TopLosers -> "Losers"
SortByTypeUM.Staking -> "Staking"
SortByTypeUM.YieldSupply -> "Yield Supply"
}, },
"Period" to when (interval) { "Period" to when (interval) {
MarketsListUM.TrendInterval.H24 -> "24h" MarketsListUM.TrendInterval.H24 -> "24h"

View file

@ -10,15 +10,12 @@ import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
import com.tangem.domain.markets.ShouldShowYieldModeMarketPromoUseCase
import com.tangem.domain.markets.TokenMarket import com.tangem.domain.markets.TokenMarket
import com.tangem.domain.markets.TokenMarketListConfig import com.tangem.domain.markets.TokenMarketListConfig
import com.tangem.domain.models.currency.CryptoCurrency 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.GetUserCountryUseCase
import com.tangem.domain.settings.usercountry.models.UserCountry import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.settings.usercountry.models.UserCountryError import com.tangem.domain.settings.usercountry.models.UserCountryError
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
import com.tangem.features.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent import com.tangem.features.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListUMStateManager import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListUMStateManager
@ -46,8 +43,6 @@ internal class MarketsListModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider, override val dispatchers: CoroutineDispatcherProvider,
getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase, getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
shouldShowYieldModeMarketPromoUseCase: ShouldShowYieldModeMarketPromoUseCase,
private val promoRepository: PromoRepository,
private val getUserCountryUseCase: GetUserCountryUseCase, private val getUserCountryUseCase: GetUserCountryUseCase,
private val analyticsEventHandler: AnalyticsEventHandler, private val analyticsEventHandler: AnalyticsEventHandler,
) : Model() { ) : Model() {
@ -118,17 +113,12 @@ internal class MarketsListModel @Inject constructor(
flow = searchMarketsListManager.uiItems, flow = searchMarketsListManager.uiItems,
flow2 = searchMarketsListManager.isInInitialLoadingErrorState, flow2 = searchMarketsListManager.isInInitialLoadingErrorState,
flow3 = searchMarketsListManager.isSearchNotFoundState, flow3 = searchMarketsListManager.isSearchNotFoundState,
flow4 = shouldShowYieldModeMarketPromoUseCase( flow4 = getUserCountryUseCase.invoke(),
appCurrency = currentAppCurrency.value, ) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, userCountry ->
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
).conflate(),
flow5 = getUserCountryUseCase.invoke(),
) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, isYieldModePromo, userCountry ->
MarketsItemsData( MarketsItemsData(
items = uiItems, items = uiItems,
isInErrorState = isInInitialLoadingErrorState, isInErrorState = isInInitialLoadingErrorState,
isSearchNotFound = isSearchNotFoundState, isSearchNotFound = isSearchNotFoundState,
shouldShowYieldModePromo = isYieldModePromo,
userCountry = userCountry, userCountry = userCountry,
) )
} }
@ -136,43 +126,21 @@ internal class MarketsListModel @Inject constructor(
combine( combine(
flow = mainMarketsListManager.uiItems, flow = mainMarketsListManager.uiItems,
flow2 = mainMarketsListManager.isInInitialLoadingErrorState, flow2 = mainMarketsListManager.isInInitialLoadingErrorState,
flow3 = shouldShowYieldModeMarketPromoUseCase( flow3 = getUserCountryUseCase.invoke(),
appCurrency = currentAppCurrency.value, ) { uiItems, isInInitialLoadingErrorState, userCountry ->
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
).conflate(),
flow4 = getUserCountryUseCase.invoke(),
) { uiItems, isInInitialLoadingErrorState, shouldShowYieldModePromo, userCountry ->
MarketsItemsData( MarketsItemsData(
items = uiItems, items = uiItems,
isInErrorState = isInInitialLoadingErrorState, isInErrorState = isInInitialLoadingErrorState,
isSearchNotFound = false, isSearchNotFound = false,
shouldShowYieldModePromo = shouldShowYieldModePromo,
userCountry = userCountry, userCountry = userCountry,
) )
} }
} }
}.collect { marketsItemsData -> }.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( marketsListUMStateManager.onUiItemsChanged(
uiItems = marketsItemsData.items, uiItems = marketsItemsData.items,
isInErrorState = marketsItemsData.isInErrorState, isInErrorState = marketsItemsData.isInErrorState,
isSearchNotFound = marketsItemsData.isSearchNotFound, isSearchNotFound = marketsItemsData.isSearchNotFound,
marketsNotificationUM = if (shouldShowYieldModePromo) {
MarketsNotificationUM.YieldSupplyPromo(
onClick = {
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModeMoreInfoClicked())
marketsListUMStateManager.selectedSortByType = SortByTypeUM.YieldSupply
},
onCloseClick = { onYieldModeNotificationCloseClick() },
)
} else {
null
},
) )
} }
} }
@ -327,18 +295,10 @@ internal class MarketsListModel @Inject constructor(
}.saveIn(updateQuotesJob) }.saveIn(updateQuotesJob)
} }
private fun onYieldModeNotificationCloseClick() {
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoClosed())
modelScope.launch {
promoRepository.setMarketsYieldSupplyNotificationHideClicked()
}
}
private class MarketsItemsData( private class MarketsItemsData(
val items: ImmutableList<MarketsListItemUM>, val items: ImmutableList<MarketsListItemUM>,
val isInErrorState: Boolean, val isInErrorState: Boolean,
val isSearchNotFound: Boolean, val isSearchNotFound: Boolean,
val shouldShowYieldModePromo: Boolean,
val userCountry: Either<UserCountryError, UserCountry>, val userCountry: Either<UserCountryError, UserCountry>,
) )
} }

View file

@ -1,22 +0,0 @@
package com.tangem.features.markets.tokenlist.impl.model
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.markets.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,
),
)
}

View file

@ -347,8 +347,6 @@ internal class MarketsListBatchFlowManager(
SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers SortByTypeUM.ExperiencedBuyers -> TokenMarketListConfig.Order.Buyers
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
} }
} }

View file

@ -8,7 +8,6 @@ import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.markets.impl.R import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.model.MarketsNotificationUM
import com.tangem.features.markets.tokenlist.impl.ui.state.* import com.tangem.features.markets.tokenlist.impl.ui.state.*
import com.tangem.utils.Provider import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@ -94,7 +93,6 @@ internal class MarketsListUMStateManager(
isInErrorState: Boolean, isInErrorState: Boolean,
isSearchNotFound: Boolean, isSearchNotFound: Boolean,
uiItems: ImmutableList<MarketsListItemUM>, uiItems: ImmutableList<MarketsListItemUM>,
marketsNotificationUM: MarketsNotificationUM?,
) { ) {
state.update { currentState -> state.update { currentState ->
when { when {
@ -110,19 +108,13 @@ internal class MarketsListUMStateManager(
currentState.copy(list = ListUM.Loading) currentState.copy(list = ListUM.Loading)
} }
else -> { else -> {
currentState.updateItems( currentState.updateItems(newItems = uiItems)
newItems = uiItems,
marketsNotificationUM = marketsNotificationUM,
)
} }
} }
} }
} }
private fun MarketsListUM.updateItems( private fun MarketsListUM.updateItems(newItems: ImmutableList<MarketsListItemUM>): MarketsListUM {
newItems: ImmutableList<MarketsListItemUM>,
marketsNotificationUM: MarketsNotificationUM?,
): MarketsListUM {
val currentState = this val currentState = this
if (isInSearchMode.not() || currentState.showUnder100kButtonAlreadyPressed()) { if (isInSearchMode.not() || currentState.showUnder100kButtonAlreadyPressed()) {
@ -133,7 +125,6 @@ internal class MarketsListUMStateManager(
.copy( .copy(
wasUnder100kTokensNotificationHidden = currentState.showUnder100kButtonAlreadyPressed(), wasUnder100kTokensNotificationHidden = currentState.showUnder100kButtonAlreadyPressed(),
), ),
marketsNotificationUM = marketsNotificationUM,
) )
} }
@ -255,6 +246,5 @@ internal class MarketsListUMStateManager(
onOptionClicked = ::onBottomSheetOptionClicked, onOptionClicked = ::onBottomSheetOptionClicked,
), ),
), ),
marketsNotificationUM = null,
) )
} }

View file

@ -38,16 +38,16 @@ import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.keyboardAsState import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.event.consumedEvent 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.LocalMainBottomSheetColor
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.markets.impl.R import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.model.MarketsNotificationUM
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListLazyColumn import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListLazyColumn
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListSortByBottomSheet import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListSortByBottomSheet
import com.tangem.features.markets.tokenlist.impl.ui.components.YieldSupplyInMarketsPromoNotification
import com.tangem.features.markets.tokenlist.impl.ui.preview.MarketChartListItemPreviewDataProvider import com.tangem.features.markets.tokenlist.impl.ui.preview.MarketChartListItemPreviewDataProvider
import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListUM import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListUM
@ -56,8 +56,6 @@ import com.tangem.features.markets.tokenlist.impl.ui.state.SortByTypeUM
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
private const val SHOW_MORE_KEY = "privacyPolicy"
@Composable @Composable
internal fun MarketsList( internal fun MarketsList(
state: MarketsListUM, state: MarketsListUM,
@ -175,40 +173,6 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
onSortByClick = state.onSortByButtonClick, onSortByClick = state.onSortByButtonClick,
) )
} }
val marketsNotificationUM = state.marketsNotificationUM
AnimatedVisibility(
state.list !is ListUM.LoadingError &&
state.isInSearchMode.not() && state.selectedSortBy != SortByTypeUM.YieldSupply,
) {
val showMore = stringResourceSafe(R.string.common_show_more)
when (marketsNotificationUM) {
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 = marketsNotificationUM.config.copy(
subtitle = clickableDescription,
),
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
)
}
else -> { /* no-op */
}
}
}
} }
} }
val strokeWidth = TangemTheme.dimens.size0_5 val strokeWidth = TangemTheme.dimens.size0_5
@ -416,10 +380,6 @@ private fun Preview() {
onDismissRequest = {}, onDismissRequest = {},
content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {}, content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {},
), ),
marketsNotificationUM = MarketsNotificationUM.YieldSupplyPromo(
onClick = {},
onCloseClick = {},
),
), ),
onHeaderSizeChange = {}, onHeaderSizeChange = {},
bottomSheetState = BottomSheetState.EXPANDED, bottomSheetState = BottomSheetState.EXPANDED,

View file

@ -8,7 +8,6 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.markets.impl.R import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.model.MarketsNotificationUM
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
internal data class MarketsListUM( internal data class MarketsListUM(
@ -19,7 +18,6 @@ internal data class MarketsListUM(
val selectedInterval: TrendInterval, val selectedInterval: TrendInterval,
val onIntervalClick: (TrendInterval) -> Unit, val onIntervalClick: (TrendInterval) -> Unit,
val onSortByButtonClick: () -> Unit, val onSortByButtonClick: () -> Unit,
val marketsNotificationUM: MarketsNotificationUM?,
) { ) {
val isInSearchMode val isInSearchMode
get() = searchBar.isActive get() = searchBar.isActive
@ -37,8 +35,6 @@ enum class SortByTypeUM(val text: TextReference) {
ExperiencedBuyers(resourceReference(R.string.markets_sort_by_experienced_buyers_title)), ExperiencedBuyers(resourceReference(R.string.markets_sort_by_experienced_buyers_title)),
TopGainers(resourceReference(R.string.markets_sort_by_top_gainers_title)), TopGainers(resourceReference(R.string.markets_sort_by_top_gainers_title)),
TopLosers(resourceReference(R.string.markets_sort_by_top_losers_title)), TopLosers(resourceReference(R.string.markets_sort_by_top_losers_title)),
Staking(resourceReference(R.string.common_staking)),
YieldSupply(resourceReference(R.string.yield_module_earn_sheet_title)),
} }
@Immutable @Immutable