Updated on 2026-08-14
This commit is contained in:
parent
febb2bda4c
commit
82ae40d9f7
3 changed files with 66 additions and 6 deletions
|
|
@ -28,6 +28,14 @@ internal enum class SwapMarketCategory(
|
|||
title = resourceReference(R.string.markets_sort_by_top_losers_title),
|
||||
order = TokenMarketListConfig.Order.TopLosers,
|
||||
),
|
||||
ExperiencedBuyers(
|
||||
title = resourceReference(R.string.markets_sort_by_experienced_buyers_title),
|
||||
order = TokenMarketListConfig.Order.Buyers,
|
||||
),
|
||||
Trending(
|
||||
title = resourceReference(R.string.markets_sort_by_trending_title),
|
||||
order = TokenMarketListConfig.Order.Trending,
|
||||
),
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
private const val MARKET_PULSE_ITEM_LIMIT = 5
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class MarketBlockDelegate @AssistedInject constructor(
|
||||
private val marketsListBatchFlowManagerFactory: MarketsListBatchFlowManager.Factory,
|
||||
|
|
@ -84,7 +86,7 @@ internal class MarketBlockDelegate @AssistedInject constructor(
|
|||
* When single-currency wallets aren't selectable here (e.g. swap), the wallet is always
|
||||
* multi-currency, so we skip the per-wallet logic entirely and return [baseMarketsStateFlow].
|
||||
*/
|
||||
val marketsStateFlow: Flow<SwapMarketState?> = if (!shouldShowSingleCurrencyWallets) {
|
||||
private val walletAwareMarketsStateFlow: Flow<SwapMarketState?> = if (!shouldShowSingleCurrencyWallets) {
|
||||
baseMarketsStateFlow
|
||||
} else {
|
||||
selectedWalletFlow
|
||||
|
|
@ -92,6 +94,10 @@ internal class MarketBlockDelegate @AssistedInject constructor(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
val marketsStateFlow: Flow<SwapMarketState?> = walletAwareMarketsStateFlow
|
||||
.map { it.limitMarketPulseItems() }
|
||||
.distinctUntilChanged()
|
||||
|
||||
private val defaultMarketsListManager by lazy {
|
||||
marketsListBatchFlowManagerFactory.create(
|
||||
batchFlowType = GetMarketsTokenListFlowUseCase.BatchFlowType.Main,
|
||||
|
|
@ -156,9 +162,8 @@ internal class MarketBlockDelegate @AssistedInject constructor(
|
|||
return combine(
|
||||
flow = defaultMarketsListManager.uiItems,
|
||||
flow2 = defaultMarketsListManager.isInInitialLoadingErrorState,
|
||||
flow3 = defaultMarketsListManager.totalCount,
|
||||
flow4 = selectedCategoryFlow,
|
||||
) { uiItems, isError, total, selectedCategory ->
|
||||
flow3 = selectedCategoryFlow,
|
||||
) { uiItems, isError, selectedCategory ->
|
||||
val categories = buildCategoriesUM(selectedCategory)
|
||||
when {
|
||||
isError -> SwapMarketState.LoadingError(
|
||||
|
|
@ -174,10 +179,10 @@ internal class MarketBlockDelegate @AssistedInject constructor(
|
|||
)
|
||||
else -> SwapMarketState.Content(
|
||||
items = uiItems,
|
||||
loadMore = { defaultMarketsListManager.loadMore() },
|
||||
loadMore = {},
|
||||
onItemClick = { item -> addToPortfolioItem(item) },
|
||||
visibleIdsChanged = { visibleDefaultMarketItemIds.value = it },
|
||||
total = total ?: uiItems.size,
|
||||
total = uiItems.size,
|
||||
marketsTitle = marketsTitle,
|
||||
shouldAssetsCount = false,
|
||||
categories = categories,
|
||||
|
|
@ -265,6 +270,13 @@ internal class MarketBlockDelegate @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun SwapMarketState?.limitMarketPulseItems(): SwapMarketState? {
|
||||
if (this !is SwapMarketState.Content || shouldAssetsCount) return this
|
||||
if (items.size <= MARKET_PULSE_ITEM_LIMIT) return this
|
||||
val limitedItems = items.take(MARKET_PULSE_ITEM_LIMIT).toImmutableList()
|
||||
return copy(items = limitedItems, total = limitedItems.size)
|
||||
}
|
||||
|
||||
private fun addToPortfolioItem(item: MarketsListItemUM) {
|
||||
val tokenMarket = defaultMarketsListManager.getTokenMarketById(item.id)
|
||||
?: searchMarketsListManager.getTokenMarketById(item.id) ?: return
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import io.mockk.every
|
|||
import io.mockk.mockk
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -116,6 +117,23 @@ internal class MarketBlockDelegateTest {
|
|||
assertThat((result as SwapMarketState.Content).items).containsExactly(item1, item2).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN more than 5 market items WHEN default flow emitted THEN only first 5 shown`() = runTest {
|
||||
// Arrange
|
||||
val items = (1..7).map { marketItem("token-$it") }
|
||||
defaultUiItems.value = items.toPersistentList()
|
||||
val delegate = createDelegate(wallet = MockUserWalletFactory.create())
|
||||
|
||||
// Act
|
||||
val result = lastMarketState(delegate)
|
||||
|
||||
// Assert
|
||||
assertThat(result).isInstanceOf(SwapMarketState.Content::class.java)
|
||||
val content = result as SwapMarketState.Content
|
||||
assertThat(content.items).containsExactlyElementsIn(items.take(5)).inOrder()
|
||||
assertThat(content.total).isEqualTo(5)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN single-currency wallet WHEN trending emitted THEN market block is hidden`() = runTest {
|
||||
// Arrange
|
||||
|
|
@ -188,6 +206,28 @@ internal class MarketBlockDelegateTest {
|
|||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN NODL wallet WHEN network token is beyond first 5 THEN block still shows it`() = runTest {
|
||||
// Arrange — 5 tokens on another network first, the wallet-network token only at position 6.
|
||||
val nodlWallet = MockUserWalletFactory.createSingleWalletWithToken()
|
||||
val otherNetworkItems = (1..5).map { marketItem("token-eth-$it") }
|
||||
val walletNetworkItem = marketItem("token-stellar")
|
||||
(1..5).forEach { tokenMarketsByRawId["token-eth-$it"] = tokenMarket(ETHEREUM_NETWORK_ID) }
|
||||
tokenMarketsByRawId["token-stellar"] = tokenMarket(STELLAR_NETWORK_ID)
|
||||
defaultUiItems.value = (otherNetworkItems + walletNetworkItem).toPersistentList()
|
||||
|
||||
every {
|
||||
singleAccountStatusListSupplier(nodlWallet.walletId)
|
||||
} returns flowOf(accountStatusList(STELLAR_NETWORK_ID))
|
||||
|
||||
// Act
|
||||
val result = lastMarketState(createDelegate(wallet = nodlWallet))
|
||||
|
||||
// Assert — network filtering runs on the full list before the 5-item cap, so it isn't dropped.
|
||||
assertThat(result).isInstanceOf(SwapMarketState.Content::class.java)
|
||||
assertThat((result as SwapMarketState.Content).items).containsExactly(walletNetworkItem)
|
||||
}
|
||||
|
||||
// region Helpers
|
||||
|
||||
private fun TestScope.lastMarketState(delegate: MarketBlockDelegate): SwapMarketState? {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue