Updated on 2026-08-14
This commit is contained in:
parent
ed89b4bcd0
commit
533c036819
28 changed files with 334 additions and 162 deletions
|
|
@ -8,7 +8,6 @@ import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
|||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -129,13 +128,11 @@ object MarketsDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetStakingNotificationMaxApyUseCase(
|
||||
settingsRepository: SettingsRepository,
|
||||
fun provideShouldShowYieldModeMarketPromoUseCase(
|
||||
promoRepository: PromoRepository,
|
||||
marketsTokenRepository: MarketsTokenRepository,
|
||||
): GetStakingNotificationMaxApyUseCase {
|
||||
return GetStakingNotificationMaxApyUseCase(
|
||||
settingsRepository = settingsRepository,
|
||||
): ShouldShowYieldModeMarketPromoUseCase {
|
||||
return ShouldShowYieldModeMarketPromoUseCase(
|
||||
promoRepository = promoRepository,
|
||||
marketsTokenRepository = marketsTokenRepository,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ data class TokenMarketListResponse(
|
|||
@Json(name = "market_cap") val marketCap: BigDecimal?,
|
||||
@Json(name = "is_under_market_cap_limit") val isUnderMarketCapLimit: Boolean?,
|
||||
@Json(name = "staking_opportunities") val stakingOpportunities: List<StakingOpportunities>?,
|
||||
@Json(name = "max_yield_apy") val maxYieldApy: BigDecimal?,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ object PreferencesKeys {
|
|||
|
||||
val SHOULD_SHOW_MARKETS_TOOLTIP_KEY by lazy { booleanPreferencesKey(name = "shouldShowMarketsTooltip") }
|
||||
|
||||
val MARKETS_STAKING_NOTIFICATION_HIDE_CLICKED_KEY by lazy {
|
||||
booleanPreferencesKey(name = "marketsStakingNotificationHideClicked")
|
||||
val MARKETS_YIELD_SUPPLY_NOTIFICATION_HIDE_CLICKED_KEY by lazy {
|
||||
booleanPreferencesKey(name = "marketsYieldSupplyNotificationHideClicked")
|
||||
}
|
||||
|
||||
val WALLET_FIRST_USAGE_DATE_KEY by lazy { longPreferencesKey(name = "walletFirstUsageDate") }
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -20,6 +20,7 @@ import com.tangem.datasource.api.markets.TangemTechMarketsApi
|
|||
import com.tangem.datasource.api.markets.models.response.TokenMarketExchangesResponse
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
|
|
@ -28,9 +29,8 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.pagination.*
|
||||
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
|
|
@ -43,7 +43,6 @@ internal class DefaultMarketsTokenRepository(
|
|||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val tokenExchangesStore: RuntimeStateStore<List<TokenMarketExchangesResponse.Exchange>>,
|
||||
private val maxApyStore: RuntimeStateStore<BigDecimal?>,
|
||||
private val networkFactory: NetworkFactory,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : MarketsTokenRepository {
|
||||
|
|
@ -95,8 +94,6 @@ internal class DefaultMarketsTokenRepository(
|
|||
|
||||
val tokenMarketListWithMaxApy = TokenMarketListConverter.convert(res)
|
||||
|
||||
maxApyStore.store(tokenMarketListWithMaxApy.maxApy)
|
||||
|
||||
return BatchFetchResult.Success(
|
||||
data = tokenMarketListWithMaxApy.tokens,
|
||||
last = last,
|
||||
|
|
@ -294,8 +291,24 @@ internal class DefaultMarketsTokenRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getMaxApy(): Flow<BigDecimal?> {
|
||||
return maxApyStore.get()
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ internal fun TokenMarketListConfig.Order.toRequestParam(): String = when (this)
|
|||
TokenMarketListConfig.Order.TopGainers -> "gainers"
|
||||
TokenMarketListConfig.Order.TopLosers -> "losers"
|
||||
TokenMarketListConfig.Order.Staking -> "staking"
|
||||
TokenMarketListConfig.Order.YieldSupply -> "yield"
|
||||
}
|
||||
|
||||
internal fun PriceChangeInterval.toRequestParam(): String = when (this) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ internal object TokenMarketListConverter : Converter<TokenMarketListResponse, To
|
|||
monthChangePercent = token.priceChangePercentage?.day30?.movePointLeft(2),
|
||||
),
|
||||
tokenCharts = TokenMarket.Charts(h24 = null, week = null, month = null),
|
||||
stakingRate = stakingRate,
|
||||
yieldRate = stakingRate ?: token.maxYieldApy?.movePointLeft(2),
|
||||
updateTimestamp = value.timestamp,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ internal object MarketsDataModule {
|
|||
cacheRegistry = cacheRegistry,
|
||||
tokenExchangesStore = RuntimeStateStore(defaultValue = emptyList()),
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
maxApyStore = RuntimeStateStore(defaultValue = null),
|
||||
networkFactory = networkFactory,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,16 +90,16 @@ internal class DefaultPromoRepository(
|
|||
appPreferencesStore.store(PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), false)
|
||||
}
|
||||
|
||||
override fun isMarketsStakingNotificationHideClicked(): Flow<Boolean> {
|
||||
override fun isMarketsYieldSupplyNotificationHideClicked(): Flow<Boolean> {
|
||||
return appPreferencesStore.get(
|
||||
key = PreferencesKeys.MARKETS_STAKING_NOTIFICATION_HIDE_CLICKED_KEY,
|
||||
key = PreferencesKeys.MARKETS_YIELD_SUPPLY_NOTIFICATION_HIDE_CLICKED_KEY,
|
||||
default = false,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setMarketsStakingNotificationHideClicked() {
|
||||
override suspend fun setMarketsYieldSupplyNotificationHideClicked() {
|
||||
appPreferencesStore.store(
|
||||
key = PreferencesKeys.MARKETS_STAKING_NOTIFICATION_HIDE_CLICKED_KEY,
|
||||
key = PreferencesKeys.MARKETS_YIELD_SUPPLY_NOTIFICATION_HIDE_CLICKED_KEY,
|
||||
value = true,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ data class TokenMarket(
|
|||
val isUnderMarketCapLimit: Boolean,
|
||||
val tokenQuotesShort: TokenQuotesShort,
|
||||
val tokenCharts: Charts,
|
||||
val stakingRate: BigDecimal?,
|
||||
val yieldRate: BigDecimal?,
|
||||
val updateTimestamp: Long?,
|
||||
private val imageHost: String,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ data class TokenMarketListConfig(
|
|||
) {
|
||||
|
||||
enum class Order {
|
||||
ByRating, Trending, Buyers, TopGainers, TopLosers, Staking
|
||||
ByRating, Trending, Buyers, TopGainers, TopLosers, Staking, YieldSupply,
|
||||
}
|
||||
|
||||
enum class Interval {
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.domain.markets
|
||||
|
||||
import android.icu.util.Calendar
|
||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import java.math.BigDecimal
|
||||
|
||||
class GetStakingNotificationMaxApyUseCase(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val promoRepository: PromoRepository,
|
||||
private val marketsTokenRepository: MarketsTokenRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): Flow<BigDecimal?> {
|
||||
val hideClickedFlow = promoRepository.isMarketsStakingNotificationHideClicked()
|
||||
val walletFirstUsageDate = settingsRepository.getWalletFirstUsageDate()
|
||||
val currentDate = Calendar.getInstance().timeInMillis
|
||||
|
||||
return combine(
|
||||
flow = hideClickedFlow,
|
||||
flow2 = marketsTokenRepository.getMaxApy(),
|
||||
) { hideClicked, maxApy ->
|
||||
val showStakingNotification = if (!hideClicked && walletFirstUsageDate != 0L) {
|
||||
currentDate - walletFirstUsageDate > TWO_WEEKS_IN_MILLIS
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
maxApy.takeIf { showStakingNotification }
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TWO_WEEKS_IN_MILLIS = 14 * 24 * 60 * 60 * 1000L
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package com.tangem.domain.markets.repositories
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.math.BigDecimal
|
||||
|
||||
interface MarketsTokenRepository {
|
||||
|
||||
|
|
@ -56,5 +55,5 @@ interface MarketsTokenRepository {
|
|||
*/
|
||||
suspend fun getTokenExchanges(tokenId: CryptoCurrency.RawID): List<TokenMarketExchange>
|
||||
|
||||
suspend fun getMaxApy(): Flow<BigDecimal?>
|
||||
suspend fun showYieldModePromo(appCurrency: AppCurrency, interval: TokenMarketListConfig.Interval): Boolean
|
||||
}
|
||||
|
|
@ -16,9 +16,9 @@ interface PromoRepository {
|
|||
|
||||
suspend fun setNeverToShowTokenPromo(promoId: PromoId)
|
||||
|
||||
fun isMarketsStakingNotificationHideClicked(): Flow<Boolean>
|
||||
fun isMarketsYieldSupplyNotificationHideClicked(): Flow<Boolean>
|
||||
|
||||
suspend fun setMarketsStakingNotificationHideClicked()
|
||||
suspend fun setMarketsYieldSupplyNotificationHideClicked()
|
||||
|
||||
suspend fun isMoonpayPromoActive(): Boolean
|
||||
// endregion
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ internal class MarketsTokenItemConverter(
|
|||
trendType = value.getTrendType(),
|
||||
chartData = value.getChartData(),
|
||||
isUnder100kMarketCap = value.isUnderMarketCapLimit,
|
||||
stakingRate = value.stakingRate?.format { percent() }?.let {
|
||||
stakingRate = value.yieldRate?.format { percent() }?.let {
|
||||
resourceReference(R.string.markets_apy_placeholder, wrappedList(it))
|
||||
},
|
||||
updateTimestamp = value.updateTimestamp,
|
||||
|
|
|
|||
|
|
@ -338,6 +338,7 @@ internal class FeedComponentModel @Inject constructor(
|
|||
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
|
||||
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
|
||||
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
|
||||
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ internal class FeedMarketsBatchFlowManager(
|
|||
TokenMarketListConfig.Order.TopGainers -> SortByTypeUM.TopGainers
|
||||
TokenMarketListConfig.Order.TopLosers -> SortByTypeUM.TopLosers
|
||||
TokenMarketListConfig.Order.Staking -> SortByTypeUM.Staking
|
||||
TokenMarketListConfig.Order.YieldSupply -> SortByTypeUM.YieldSupply
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ enum class SortByTypeUM(val text: TextReference) {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ internal sealed class MarketsListAnalyticsEvent(
|
|||
SortByTypeUM.TopGainers -> "Gainers"
|
||||
SortByTypeUM.TopLosers -> "Losers"
|
||||
SortByTypeUM.Staking -> "Staking"
|
||||
SortByTypeUM.YieldSupply -> "Yield Supply"
|
||||
},
|
||||
"Period" to when (interval) {
|
||||
MarketsListUM.TrendInterval.H24 -> "24h"
|
||||
|
|
@ -32,12 +33,11 @@ internal sealed class MarketsListAnalyticsEvent(
|
|||
},
|
||||
),
|
||||
)
|
||||
class YieldModePromoShown : MarketsListAnalyticsEvent(event = "Notice - Yield Mode Promo")
|
||||
|
||||
class StakingPromoShown : MarketsListAnalyticsEvent(event = "Notice - Staking Promo")
|
||||
class YieldModePromoClosed : MarketsListAnalyticsEvent(event = "Yield Mode Promo Closed")
|
||||
|
||||
class StakingPromoClosed : MarketsListAnalyticsEvent(event = "Staking Promo Closed")
|
||||
|
||||
class StakingMoreInfoClicked : MarketsListAnalyticsEvent(event = "Staking More Info")
|
||||
class YieldModeMoreInfoClicked : MarketsListAnalyticsEvent(event = "Yield Mode More Info")
|
||||
|
||||
data class TokenSearched(val tokenFound: Boolean) : MarketsListAnalyticsEvent(
|
||||
event = "Token Searched",
|
||||
|
|
|
|||
|
|
@ -10,19 +10,20 @@ 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.GetStakingNotificationMaxApyUseCase
|
||||
import com.tangem.domain.markets.ShouldShowYieldModeMarketPromoUseCase
|
||||
import com.tangem.domain.markets.TokenMarket
|
||||
import com.tangem.domain.markets.TokenMarketListConfig
|
||||
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.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent
|
||||
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.ui.state.ListUM
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListItemUM
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListUM.TrendInterval
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.SortByTypeUM
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -31,7 +32,6 @@ import com.tangem.utils.coroutines.saveIn
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val UPDATE_QUOTES_TIMER_MILLIS = 60000L
|
||||
|
|
@ -45,7 +45,7 @@ internal class MarketsListModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
getStakingNotificationMaxApyUseCase: GetStakingNotificationMaxApyUseCase,
|
||||
shouldShowYieldModeMarketPromoUseCase: ShouldShowYieldModeMarketPromoUseCase,
|
||||
private val promoRepository: PromoRepository,
|
||||
private val getUserCountryUseCase: GetUserCountryUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
|
|
@ -69,8 +69,6 @@ internal class MarketsListModel @Inject constructor(
|
|||
visibleItemsChanged = { visibleItemIds.value = it },
|
||||
onRetryButtonClicked = { activeListManager.reload() },
|
||||
onTokenClick = { onTokenUIClicked(it) },
|
||||
onStakingNotificationClick = { analyticsEventHandler.send(MarketsListAnalyticsEvent.StakingMoreInfoClicked()) },
|
||||
onStakingNotificationCloseClick = { onStakingNotificationCloseClick() },
|
||||
onShowTokensUnder100kClicked = { analyticsEventHandler.send(MarketsListAnalyticsEvent.ShowTokens()) },
|
||||
)
|
||||
|
||||
|
|
@ -112,53 +110,62 @@ internal class MarketsListModel @Inject constructor(
|
|||
marketsListUMStateManager.isInSearchStateFlow.flatMapLatest { isInSearchMode ->
|
||||
if (isInSearchMode) {
|
||||
combine(
|
||||
searchMarketsListManager.uiItems,
|
||||
searchMarketsListManager.isInInitialLoadingErrorState,
|
||||
searchMarketsListManager.isSearchNotFoundState,
|
||||
getStakingNotificationMaxApyUseCase(),
|
||||
getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, stakingMaxApy, userCountry ->
|
||||
flow = searchMarketsListManager.uiItems,
|
||||
flow2 = searchMarketsListManager.isInInitialLoadingErrorState,
|
||||
flow3 = searchMarketsListManager.isSearchNotFoundState,
|
||||
flow4 = shouldShowYieldModeMarketPromoUseCase(
|
||||
appCurrency = currentAppCurrency.value,
|
||||
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
|
||||
),
|
||||
flow5 = getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, isYieldModePromo, userCountry ->
|
||||
MarketsItemsData(
|
||||
items = uiItems,
|
||||
isInErrorState = isInInitialLoadingErrorState,
|
||||
isSearchNotFound = isSearchNotFoundState,
|
||||
stakingNotificationMaxApy = stakingMaxApy,
|
||||
shouldShowYieldModePromo = isYieldModePromo,
|
||||
userCountry = userCountry,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
combine(
|
||||
mainMarketsListManager.uiItems,
|
||||
mainMarketsListManager.isInInitialLoadingErrorState,
|
||||
getStakingNotificationMaxApyUseCase(),
|
||||
getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, stakingNotificationMaxApy, userCountry ->
|
||||
flow = mainMarketsListManager.uiItems,
|
||||
flow2 = mainMarketsListManager.isInInitialLoadingErrorState,
|
||||
flow3 = shouldShowYieldModeMarketPromoUseCase(
|
||||
appCurrency = currentAppCurrency.value,
|
||||
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
|
||||
),
|
||||
flow4 = getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, shouldShowYieldModePromo, userCountry ->
|
||||
MarketsItemsData(
|
||||
items = uiItems,
|
||||
isInErrorState = isInInitialLoadingErrorState,
|
||||
isSearchNotFound = false,
|
||||
stakingNotificationMaxApy = stakingNotificationMaxApy,
|
||||
shouldShowYieldModePromo = shouldShowYieldModePromo,
|
||||
userCountry = userCountry,
|
||||
)
|
||||
}
|
||||
}
|
||||
}.collect { marketsItemsData ->
|
||||
val stakingNotificationMaxApy = marketsItemsData.stakingNotificationMaxApy?.takeUnless {
|
||||
marketsItemsData.userCountry.getOrNull().needApplyFCARestrictions()
|
||||
}
|
||||
|
||||
if (marketsListUMStateManager.state.value.stakingNotificationMaxApy == null &&
|
||||
stakingNotificationMaxApy != null
|
||||
) {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.StakingPromoShown())
|
||||
val shouldShowYieldModePromo = marketsItemsData.shouldShowYieldModePromo
|
||||
if (marketsListUMStateManager.state.value.marketsNotificationUM == null && shouldShowYieldModePromo) {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoShown())
|
||||
}
|
||||
|
||||
marketsListUMStateManager.onUiItemsChanged(
|
||||
uiItems = marketsItemsData.items,
|
||||
isInErrorState = marketsItemsData.isInErrorState,
|
||||
isSearchNotFound = marketsItemsData.isSearchNotFound,
|
||||
stakingNotificationMaxApy = marketsItemsData.stakingNotificationMaxApy?.takeUnless {
|
||||
marketsItemsData.userCountry.getOrNull().needApplyFCARestrictions()
|
||||
marketsNotificationUM = if (shouldShowYieldModePromo) {
|
||||
MarketsNotificationUM.YieldSupplyPromo(
|
||||
onClick = {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModeMoreInfoClicked())
|
||||
marketsListUMStateManager.selectedSortByType = SortByTypeUM.YieldSupply
|
||||
},
|
||||
onCloseClick = { onYieldModeNotificationCloseClick() },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -266,6 +273,14 @@ internal class MarketsListModel @Inject constructor(
|
|||
mainMarketsListManager.reload()
|
||||
}
|
||||
|
||||
fun TrendInterval.toBatchRequestInterval(): TokenMarketListConfig.Interval {
|
||||
return when (this) {
|
||||
TrendInterval.H24 -> TokenMarketListConfig.Interval.H24
|
||||
TrendInterval.D7 -> TokenMarketListConfig.Interval.WEEK
|
||||
TrendInterval.M1 -> TokenMarketListConfig.Interval.MONTH
|
||||
}
|
||||
}
|
||||
|
||||
private fun initAnalytics() {
|
||||
containerBottomSheetState.onEach { bottomSheetState ->
|
||||
if (bottomSheetState == BottomSheetState.EXPANDED) {
|
||||
|
|
@ -302,10 +317,10 @@ internal class MarketsListModel @Inject constructor(
|
|||
}.saveIn(updateQuotesJob)
|
||||
}
|
||||
|
||||
private fun onStakingNotificationCloseClick() {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.StakingPromoClosed())
|
||||
private fun onYieldModeNotificationCloseClick() {
|
||||
analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoClosed())
|
||||
modelScope.launch {
|
||||
promoRepository.setMarketsStakingNotificationHideClicked()
|
||||
promoRepository.setMarketsYieldSupplyNotificationHideClicked()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +328,7 @@ internal class MarketsListModel @Inject constructor(
|
|||
val items: ImmutableList<MarketsListItemUM>,
|
||||
val isInErrorState: Boolean,
|
||||
val isSearchNotFound: Boolean,
|
||||
val stakingNotificationMaxApy: BigDecimal?,
|
||||
val shouldShowYieldModePromo: Boolean,
|
||||
val userCountry: Either<UserCountryError, UserCountry>,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ internal class MarketsTokenItemConverter(
|
|||
trendType = value.getTrendType(),
|
||||
chartData = value.getChartData(),
|
||||
isUnder100kMarketCap = value.isUnderMarketCapLimit,
|
||||
stakingRate = value.stakingRate?.format { percent() }?.let {
|
||||
stakingRate = value.yieldRate?.format { percent() }?.let {
|
||||
resourceReference(R.string.markets_apy_placeholder, wrappedList(it))
|
||||
},
|
||||
updateTimestamp = value.updateTimestamp,
|
||||
|
|
|
|||
|
|
@ -343,6 +343,7 @@ internal class MarketsListBatchFlowManager(
|
|||
SortByTypeUM.TopGainers -> TokenMarketListConfig.Order.TopGainers
|
||||
SortByTypeUM.TopLosers -> TokenMarketListConfig.Order.TopLosers
|
||||
SortByTypeUM.Staking -> TokenMarketListConfig.Order.Staking
|
||||
SortByTypeUM.YieldSupply -> TokenMarketListConfig.Order.YieldSupply
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.ui.event.triggeredEvent
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
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.utils.Provider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -16,7 +17,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Stable
|
||||
@Suppress("LongParameterList")
|
||||
|
|
@ -26,8 +26,6 @@ internal class MarketsListUMStateManager(
|
|||
private val visibleItemsChanged: (itemsKeys: List<CryptoCurrency.RawID>) -> Unit,
|
||||
private val onRetryButtonClicked: () -> Unit,
|
||||
private val onTokenClick: (MarketsListItemUM) -> Unit,
|
||||
private val onStakingNotificationClick: () -> Unit,
|
||||
private val onStakingNotificationCloseClick: () -> Unit,
|
||||
private val onShowTokensUnder100kClicked: () -> Unit,
|
||||
) {
|
||||
|
||||
|
|
@ -92,25 +90,25 @@ internal class MarketsListUMStateManager(
|
|||
isInErrorState: Boolean,
|
||||
isSearchNotFound: Boolean,
|
||||
uiItems: ImmutableList<MarketsListItemUM>,
|
||||
stakingNotificationMaxApy: BigDecimal?,
|
||||
marketsNotificationUM: MarketsNotificationUM?,
|
||||
) {
|
||||
state.update {
|
||||
state.update { currentState ->
|
||||
when {
|
||||
isInErrorState -> {
|
||||
it.copy(
|
||||
currentState.copy(
|
||||
list = ListUM.LoadingError(onRetryClicked = onRetryButtonClicked),
|
||||
)
|
||||
}
|
||||
isSearchNotFound -> {
|
||||
it.copy(list = ListUM.SearchNothingFound)
|
||||
currentState.copy(list = ListUM.SearchNothingFound)
|
||||
}
|
||||
uiItems.isEmpty() -> {
|
||||
it.copy(list = ListUM.Loading)
|
||||
currentState.copy(list = ListUM.Loading)
|
||||
}
|
||||
else -> {
|
||||
it.updateItems(
|
||||
currentState.updateItems(
|
||||
newItems = uiItems,
|
||||
stakingNotificationMaxApy = stakingNotificationMaxApy,
|
||||
marketsNotificationUM = marketsNotificationUM,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -119,7 +117,7 @@ internal class MarketsListUMStateManager(
|
|||
|
||||
private fun MarketsListUM.updateItems(
|
||||
newItems: ImmutableList<MarketsListItemUM>,
|
||||
stakingNotificationMaxApy: BigDecimal?,
|
||||
marketsNotificationUM: MarketsNotificationUM?,
|
||||
): MarketsListUM {
|
||||
val currentState = this
|
||||
|
||||
|
|
@ -131,7 +129,7 @@ internal class MarketsListUMStateManager(
|
|||
.copy(
|
||||
showUnder100kTokensNotificationWasHidden = currentState.showUnder100kButtonAlreadyPressed(),
|
||||
),
|
||||
stakingNotificationMaxApy = stakingNotificationMaxApy,
|
||||
marketsNotificationUM = marketsNotificationUM,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -225,12 +223,7 @@ internal class MarketsListUMStateManager(
|
|||
onOptionClicked = ::onBottomSheetOptionClicked,
|
||||
),
|
||||
),
|
||||
stakingNotificationMaxApy = null,
|
||||
onStakingNotificationClick = {
|
||||
onStakingNotificationClick()
|
||||
selectedSortByType = SortByTypeUM.Staking
|
||||
},
|
||||
onStakingNotificationCloseClick = onStakingNotificationCloseClick,
|
||||
marketsNotificationUM = null,
|
||||
)
|
||||
|
||||
private fun onBottomSheetOptionClicked(sortByTypeUM: SortByTypeUM) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import androidx.compose.ui.platform.LocalDensity
|
|||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -38,19 +37,17 @@ import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
|
|||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.keyboardAsState
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
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.MarketsListSortByBottomSheet
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.components.StakingInMarketsPromoNotification
|
||||
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.state.ListUM
|
||||
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListUM
|
||||
|
|
@ -58,7 +55,6 @@ import com.tangem.features.markets.tokenlist.impl.ui.state.SortByBottomSheetCont
|
|||
import com.tangem.features.markets.tokenlist.impl.ui.state.SortByTypeUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
private const val SHOW_MORE_KEY = "privacyPolicy"
|
||||
|
||||
|
|
@ -180,18 +176,21 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
|
|||
)
|
||||
}
|
||||
|
||||
val marketsNotification = state.marketsNotificationUM
|
||||
AnimatedVisibility(
|
||||
state.isInSearchMode.not() &&
|
||||
state.stakingNotificationMaxApy != null &&
|
||||
state.selectedSortBy != SortByTypeUM.Staking,
|
||||
state.selectedSortBy != SortByTypeUM.YieldSupply,
|
||||
) {
|
||||
val showMore = stringResourceSafe(R.string.common_show_more)
|
||||
|
||||
when (marketsNotification) {
|
||||
is MarketsNotificationUM.YieldSupplyPromo -> {
|
||||
val description = stringResourceSafe(
|
||||
R.string.markets_staking_banner_description_placeholder,
|
||||
R.string.markets_yield_supply_banner_description,
|
||||
showMore,
|
||||
)
|
||||
|
||||
val clickableDescription = buildAnnotatedString {
|
||||
val clickableDescription = annotatedReference {
|
||||
append(description.substringBefore(showMore))
|
||||
|
||||
pushStringAnnotation(SHOW_MORE_KEY, "")
|
||||
|
|
@ -199,20 +198,17 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
|
|||
pop()
|
||||
}
|
||||
|
||||
StakingInMarketsPromoNotification(
|
||||
config = NotificationConfig(
|
||||
iconResId = R.drawable.img_staking_in_market_notification,
|
||||
title = resourceReference(
|
||||
R.string.markets_staking_banner_title,
|
||||
wrappedList(state.stakingNotificationMaxApy.format { percent() }),
|
||||
),
|
||||
subtitle = annotatedReference(clickableDescription),
|
||||
onClick = state.onStakingNotificationClick,
|
||||
onCloseClick = state.onStakingNotificationCloseClick,
|
||||
YieldSupplyInMarketsPromoNotification(
|
||||
config = marketsNotification.config.copy(
|
||||
subtitle = clickableDescription,
|
||||
),
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val strokeWidth = TangemTheme.dimens.size0_5
|
||||
|
|
@ -420,9 +416,10 @@ private fun Preview() {
|
|||
onDismissRequest = {},
|
||||
content = SortByBottomSheetContentUM(selectedOption = SortByTypeUM.Rating) {},
|
||||
),
|
||||
stakingNotificationMaxApy = BigDecimal(0.12345),
|
||||
onStakingNotificationClick = {},
|
||||
onStakingNotificationCloseClick = {},
|
||||
marketsNotificationUM = MarketsNotificationUM.YieldSupplyPromo(
|
||||
onClick = {},
|
||||
onCloseClick = {},
|
||||
),
|
||||
),
|
||||
onHeaderSizeChange = {},
|
||||
bottomSheetState = BottomSheetState.EXPANDED,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
package com.tangem.features.markets.tokenlist.impl.ui.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.notifications.CloseableIconButton
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
private val bgColor = Color(0x2684B0D7)
|
||||
private val borderColor = Color(0x2684B0D7)
|
||||
|
||||
@Composable
|
||||
fun YieldSupplyInMarketsPromoNotification(config: NotificationConfig, modifier: Modifier = Modifier) {
|
||||
var textHeightDp by remember { mutableStateOf(0.dp) }
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
width = 1.dp,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
color = borderColor,
|
||||
)
|
||||
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(bgColor)
|
||||
.clickable { config.onClick?.invoke() },
|
||||
) {
|
||||
PromoImage(
|
||||
iconRes = config.iconResId,
|
||||
modifier = Modifier.height(textHeightDp),
|
||||
)
|
||||
PromoText(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
onSizeChange = { textHeightDp = it },
|
||||
)
|
||||
CloseableIconButton(
|
||||
onClick = config.onCloseClick,
|
||||
modifier = Modifier.align(alignment = Alignment.TopEnd),
|
||||
iconTint = TangemTheme.colors.icon.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PromoImage(@DrawableRes iconRes: Int, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier.padding(vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = iconRes),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier
|
||||
.requiredWidth(80.dp)
|
||||
.wrapContentHeight(Alignment.CenterVertically, unbounded = true),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PromoText(title: TextReference?, subtitle: TextReference, onSizeChange: (Dp) -> Unit) {
|
||||
val density = LocalDensity.current
|
||||
|
||||
Box(
|
||||
modifier = Modifier.onSizeChanged {
|
||||
with(density) { onSizeChange(it.height.toDp()) }
|
||||
},
|
||||
) {
|
||||
TextsBlock(
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
modifier = Modifier
|
||||
.wrapContentHeight()
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(start = 80.dp, top = 12.dp, end = 12.dp, bottom = 12.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextsBlock(title: TextReference?, subtitle: TextReference, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier) {
|
||||
val titleText = title?.resolveReference()
|
||||
|
||||
if (titleText != null) {
|
||||
Text(
|
||||
text = titleText,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.button,
|
||||
)
|
||||
|
||||
SpacerH(height = TangemTheme.dimens.spacing2)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = subtitle.resolveAnnotatedReference(),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun RingPromoNotification_Preview() {
|
||||
TangemThemePreview {
|
||||
YieldSupplyInMarketsPromoNotification(
|
||||
config = NotificationConfig(
|
||||
title = stringReference("Activate Yield Mode"),
|
||||
subtitle = stringReference("Power up your assets while supplying them with instant access. Show more"),
|
||||
iconResId = R.drawable.img_yield_supply_in_market_notification,
|
||||
onCloseClick = { },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
|
@ -8,8 +8,8 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.tokenlist.impl.model.MarketsNotificationUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal data class MarketsListUM(
|
||||
val list: ListUM,
|
||||
|
|
@ -19,9 +19,7 @@ internal data class MarketsListUM(
|
|||
val selectedInterval: TrendInterval,
|
||||
val onIntervalClick: (TrendInterval) -> Unit,
|
||||
val onSortByButtonClick: () -> Unit,
|
||||
val stakingNotificationMaxApy: BigDecimal?,
|
||||
val onStakingNotificationClick: () -> Unit,
|
||||
val onStakingNotificationCloseClick: () -> Unit,
|
||||
val marketsNotificationUM: MarketsNotificationUM?,
|
||||
) {
|
||||
val isInSearchMode
|
||||
get() = searchBar.isActive
|
||||
|
|
@ -40,6 +38,7 @@ enum class SortByTypeUM(val text: TextReference) {
|
|||
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.yield_module_earn_sheet_title)),
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue