From a9fbfc8a5301ef2e64505b2a7b54b817272d89e4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 8 Apr 2026 13:34:48 +0400 Subject: [PATCH] Updated on 2026-08-14 --- ...ccountCryptoPortfolioItemStateConverter.kt | 45 +++- .../tokenlist/state/TokensListItemUM.kt | 6 + .../wallets/usecase/GetWalletsUseCase.kt | 12 +- .../converter/ChooseTokenListItemConverter.kt | 37 +-- .../impl/model/ChooseTokenModel.kt | 54 ++--- .../choosetoken/impl/ui/ChooseTokenScreen.kt | 215 ++++++++++++++---- .../swap/choosetoken/impl/ui/ChooseTokenUM.kt | 10 +- 7 files changed, 272 insertions(+), 107 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/account/AccountCryptoPortfolioItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/account/AccountCryptoPortfolioItemStateConverter.kt index 1955e4b9a0..9780c3831c 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/account/AccountCryptoPortfolioItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/account/AccountCryptoPortfolioItemStateConverter.kt @@ -27,6 +27,8 @@ class AccountCryptoPortfolioItemStateConverter( private val priceChangeLce: Lce? = null, private val onItemClick: ((Account.CryptoPortfolio) -> Unit)? = null, private val onItemLongClick: ((Account.CryptoPortfolio) -> Unit)? = null, + private val fiatAmountStateProvider: ((TotalFiatBalance) -> FiatAmountState?)? = null, + private val subtitle2StateProvider: ((Lce) -> Subtitle2State?)? = null, ) : Converter { override fun convert(value: TotalFiatBalance): TokenItemState { @@ -40,11 +42,11 @@ class AccountCryptoPortfolioItemStateConverter( private fun Account.CryptoPortfolio.mapToContentState( fiatBalance: TotalFiatBalance.Loaded, ): TokenItemState.Content { - val subtitle2State = priceChangeLce?.fold( - ifLoading = { priceChange -> priceChange?.toSubtitle2State() ?: Subtitle2State.Loading }, - ifError = { null }, - ifContent = { priceChange -> priceChange.toSubtitle2State() }, - ) + val subtitle2State = if (priceChangeLce != null && subtitle2StateProvider != null) { + subtitle2StateProvider(priceChangeLce) + } else { + createSubtitle2State(priceChangeLce) + } return TokenItemState.Content( id = account.accountId.toItemId(), iconState = AccountIconItemStateConverter().convert(this), @@ -59,11 +61,8 @@ class AccountCryptoPortfolioItemStateConverter( ), isAvailable = false, ), - fiatAmountState = FiatAmountState.Content( - text = fiatBalance.amount - .format { fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol) }, - isFlickering = fiatBalance.source == StatusSource.CACHE, - ), + fiatAmountState = fiatAmountStateProvider?.invoke(fiatBalance) + ?: createFiatAmountState(fiatBalance, appCurrency), subtitle2State = subtitle2State, onItemClick = onItemClick?.let { onItemClick -> { onItemClick(account) } }, onItemLongClick = onItemLongClick?.let { onItemLongClick -> { onItemLongClick(account) } }, @@ -127,4 +126,30 @@ class AccountCryptoPortfolioItemStateConverter( type = this.value.getPriceChangeType(), isFlickering = this.source.isFlickering(), ) + + private fun createFiatAmountState(fiatBalance: TotalFiatBalance, appCurrency: AppCurrency): FiatAmountState { + return when (fiatBalance) { + TotalFiatBalance.Failed, + TotalFiatBalance.Loading, + -> FiatAmountState.Empty + + is TotalFiatBalance.Loaded -> FiatAmountState.Content( + text = fiatBalance.amount.format { + fiat( + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ) + }, + isFlickering = fiatBalance.source == StatusSource.CACHE, + ) + } + } + + private fun createSubtitle2State(priceChangeLce: Lce?): Subtitle2State? { + return priceChangeLce?.fold( + ifLoading = { priceChange -> priceChange?.toSubtitle2State() ?: Subtitle2State.Loading }, + ifError = { null }, + ifContent = { priceChange -> priceChange.toSubtitle2State() }, + ) + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt index c09e64697b..f5c2277c35 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt @@ -55,6 +55,12 @@ sealed interface TokensListItemUM { is PortfolioItemContentUM.Tokens -> content.tokens is PortfolioItemContentUM.Empty -> persistentListOf() } + + val tokensItemsList: List + get() = when (content) { + is PortfolioItemContentUM.Tokens -> content.tokens.filterIsInstance() + is PortfolioItemContentUM.Empty -> emptyList() + } } data class Text(override val id: Any, val text: TextReference) : TokensListItemUM diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsUseCase.kt index 1a436c9f93..355ce124c1 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetWalletsUseCase.kt @@ -3,9 +3,9 @@ package com.tangem.domain.wallets.usecase import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.models.wallet.isMultiCurrency import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import java.util.LinkedHashMap /** * Use case for getting list of user wallets @@ -22,9 +22,13 @@ class GetWalletsUseCase( operator fun invoke(): Flow> = userWalletsListRepository.userWallets.map { requireNotNull(it) } @Throws(IllegalArgumentException::class) - fun invokeAsMap(): Flow> = userWalletsListRepository.userWallets - .map { requireNotNull(it) } - .map { wallets -> + fun invokeAsMap(isOnlyMultiCurrency: Boolean = true): Flow> = invoke() + .map { list -> + val wallets = if (isOnlyMultiCurrency) { + list.filter { wallet -> wallet.isMultiCurrency } + } else { + list + } wallets.associateByTo( destination = linkedMapOf(), keySelector = { wallet -> wallet.walletId }, diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt index a130a0eabf..ee77c4eeec 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/converter/ChooseTokenListItemConverter.kt @@ -6,9 +6,12 @@ import com.tangem.common.ui.tokens.TokenConverterParams import com.tangem.common.ui.tokens.TokenItemGrouping.toGroupedItems import com.tangem.common.ui.tokens.TokenItemGrouping.toUngroupedItems import com.tangem.common.ui.tokens.TokenItemStateConverter +import com.tangem.core.ui.components.icons.IconTint +import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.filterCryptoPortfolio @@ -17,6 +20,7 @@ import com.tangem.domain.models.tokenlist.TokenList import com.tangem.feature.swap.choosetoken.impl.model.ClickIntents import com.tangem.feature.swap.choosetoken.impl.model.isSearchingState import com.tangem.feature.swap.models.TokenListUMData +import com.tangem.feature.swap.presentation.R import kotlinx.collections.immutable.toPersistentList internal class ChooseTokenListItemConverter( @@ -57,10 +61,9 @@ internal class ChooseTokenListItemConverter( if (accountItems.isEmpty()) { return TokenListUMData.EmptyList } - val accountsList = accountItems.toPersistentList() return TokenListUMData.AccountList( - tokensList = accountsList, - totalTokensCount = accountsList.size, + tokensList = accountItems.toPersistentList(), + totalTokensCount = accountItems.sumOf { portfolio -> portfolio.tokensItemsList.size }, ) } @@ -77,11 +80,19 @@ internal class ChooseTokenListItemConverter( clickIntents.onAccountExpandClick(clickedAccount) } } + val fiatAmountStateProvider: ((TotalFiatBalance) -> FiatAmountState?) = if (isSearchingState) { + { _ -> FiatAmountState.Empty } + } else { + { _ -> FiatAmountState.Icon(R.drawable.ic_chewron_down_20, IconTint.Informative) } + } + val converter = AccountCryptoPortfolioItemStateConverter( appCurrency = appCurrency, account = account, onItemClick = onItemClick.takeIf { !isSearchingState }, priceChangeLce = this.priceChangeLce, + fiatAmountStateProvider = fiatAmountStateProvider, + subtitle2StateProvider = { _ -> null }, ) val accountItem = converter.convert(tokenList.totalFiatBalance) val tokenConverter = tokenStatusConverter(this) @@ -100,18 +111,14 @@ internal class ChooseTokenListItemConverter( return when (tokenList) { is TokenList.Empty -> TokenListUMData.EmptyList - is TokenList.GroupedByNetwork -> tokenList.toGroupedItems(tokenConverter).let { grouped -> - TokenListUMData.TokenList( - tokensList = grouped.toPersistentList(), - totalTokensCount = grouped.size, - ) - } - is TokenList.Ungrouped -> tokenList.toUngroupedItems(tokenConverter).let { ungrouped -> - TokenListUMData.TokenList( - tokensList = ungrouped.toPersistentList(), - totalTokensCount = ungrouped.size, - ) - } + is TokenList.GroupedByNetwork -> TokenListUMData.TokenList( + tokensList = tokenList.toGroupedItems(tokenConverter).toPersistentList(), + totalTokensCount = tokenList.flattenCurrencies().size, + ) + is TokenList.Ungrouped -> TokenListUMData.TokenList( + tokensList = tokenList.toUngroupedItems(tokenConverter).toPersistentList(), + totalTokensCount = tokenList.flattenCurrencies().size, + ) } } diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/model/ChooseTokenModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/model/ChooseTokenModel.kt index 2eb003236d..ca32af6c5e 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/model/ChooseTokenModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/model/ChooseTokenModel.kt @@ -5,8 +5,7 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.fields.entity.SearchBarUM -import com.tangem.core.ui.ds.button.TangemButtonType -import com.tangem.core.ui.ds.button.TangemButtonUM +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.models.account.AccountId @@ -19,13 +18,9 @@ import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.feature.swap.choosetoken.api.* import com.tangem.feature.swap.choosetoken.impl.converter.SearchBarToggleTransformer import com.tangem.feature.swap.choosetoken.impl.converter.SearchBarUpdateQueryTransformer -import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenFullUM -import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenInitialUM -import com.tangem.feature.swap.choosetoken.impl.ui.ChooseTokenUM -import com.tangem.feature.swap.choosetoken.impl.ui.WalletListUM +import com.tangem.feature.swap.choosetoken.impl.ui.* import com.tangem.feature.swap.converters.TokensDataConverter import com.tangem.feature.swap.models.SwapSelectTokenStateHolder -import com.tangem.feature.swap.models.TokenListUMData import com.tangem.feature.swap.models.market.state.SwapMarketState import com.tangem.feature.swap.presentation.R import com.tangem.features.feed.components.market.details.portfolio.add.AddToPortfolioComponent @@ -147,41 +142,39 @@ internal class ChooseTokenModel @Inject constructor( @Suppress("LongMethod") private fun combineUI(): StateFlow = channelFlow { - val allWalletsFlow: StateFlow> = + val allWalletsFlow: StateFlow> = getWalletsUseCase.invokeAsMap().stateIn(this) + // todo swap add optional param, store, and GetSelectedWalletUseCase + val firstSelectedWallet = allWalletsFlow.value.values.first() val selectedWalletFlow: StateFlow = onWalletSelected.receiveAsFlow() .mapNotNull { walletId -> allWalletsFlow.value[walletId] } - .stateIn(this, SharingStarted.Eagerly, allWalletsFlow.value.values.first()) + .stateIn(this, SharingStarted.Eagerly, firstSelectedWallet) - val selectedWalletTokensData: Flow = combine( - flow = selectedWalletFlow.map { wallet -> wallet.walletId }.distinctUntilChanged(), + val fullPortfolioBlockFlow = combine( + flow = allWalletsFlow, flow2 = portfolioListBlockDelegate.portfolioList, - transform = { selectedWalletId, allPortfoliosData -> allPortfoliosData[selectedWalletId] }, - ) - .filterNotNull() - .distinctUntilChanged() - - val walletListUmFlow = combine( - flow = selectedWalletFlow, - flow2 = allWalletsFlow, - transform = { selectedWallet, allWallets -> - allWallets.entries + flow3 = selectedWalletFlow.map { wallet -> wallet.walletId }.distinctUntilChanged(), + transform = { allWallets, portfolioList, selectedWalletId -> + val tokensListData = portfolioList[selectedWalletId] ?: return@combine null + val walletsUM = allWallets.entries .map { (walletId, wallet) -> - val type = if (selectedWallet.walletId == walletId) { - TangemButtonType.Primary - } else { - TangemButtonType.Secondary - } - TangemButtonUM( + val searchResultCount: TextReference? = portfolioList[walletId]?.totalTokensCount + ?.toString() + ?.let(::stringReference) + ?.takeIf { isSearchingState } + WalletTabUM( text = stringReference(wallet.name), onClick = { onWalletSelected.trySend(walletId) }, - type = type, + isSelected = selectedWalletId == walletId, + count = searchResultCount, ) } + walletsUM to tokensListData }, ) + .filterNotNull() .distinctUntilChanged() portfolioListBlockDelegate.onTokenItemClick.receiveAsFlow() @@ -195,11 +188,10 @@ internal class ChooseTokenModel @Inject constructor( .launchIn(this) combine( - flow = selectedWalletTokensData, + flow = fullPortfolioBlockFlow, flow2 = settingContextUseCase.invoke(), flow3 = marketsStateFlow, - flow4 = walletListUmFlow, - transform = { tokensData, settings, marketsData, walletList -> + transform = { (walletList, tokensData), settings, marketsData -> val walletsUM = if (walletList.size != 1) { WalletListUM(walletList.toPersistentList()) } else { diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/ui/ChooseTokenScreen.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/ui/ChooseTokenScreen.kt index 626a24fe4e..a02d3a52c2 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/ui/ChooseTokenScreen.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/impl/ui/ChooseTokenScreen.kt @@ -1,15 +1,23 @@ package com.tangem.feature.swap.choosetoken.impl.ui +import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape 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.ColorFilter import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -17,10 +25,6 @@ import androidx.compose.ui.unit.dp import com.tangem.common.ui.tokens.portfolioTokensList import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.appbar.AppBarWithBackButton -import com.tangem.core.ui.components.buttons.common.TangemButton -import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition -import com.tangem.core.ui.components.buttons.common.TangemButtonSize -import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.components.fields.SearchBar import com.tangem.core.ui.components.fields.TangemSearchBarDefaults @@ -34,8 +38,6 @@ import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.decorations.roundedShapeItemDecoration -import com.tangem.core.ui.ds.button.TangemButtonType -import com.tangem.core.ui.ds.button.TangemButtonUM import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -54,6 +56,18 @@ import kotlin.random.Random private const val LOAD_MORE_BUFFER = 25 +private val ChooseTokenUM.isNotFoundState: Boolean + get() = tokensListData.tokensList.isEmpty() && + isSearching && + marketsState !is SwapMarketState.Content && + marketsState !is SwapMarketState.Loading + +private val ChooseTokenUM.isEmptyState: Boolean + get() = tokensListData.tokensList.isEmpty() && + !isSearching && + marketsState !is SwapMarketState.Content && + marketsState !is SwapMarketState.Loading + @Composable internal fun ChooseTokenScreen(state: ChooseTokenFullUM, modifier: Modifier = Modifier) { Column( @@ -93,7 +107,6 @@ private fun Content(state: ChooseTokenFullUM, modifier: Modifier = Modifier) { modifier = modifier .fillMaxSize() .nestedScroll(nestedScrollConnection), - horizontalAlignment = Alignment.CenterHorizontally, state = lazyListState, contentPadding = WindowInsets.navigationBars.asPaddingValues(), ) { @@ -108,20 +121,26 @@ private fun Content(state: ChooseTokenFullUM, modifier: Modifier = Modifier) { assetsTitle() if (state.contentUM != null) { - walletListItem(state.contentUM.walletList) + when { + state.contentUM.isNotFoundState -> tokensNotFound() + state.contentUM.isEmptyState -> emptyTokensList() + else -> { + walletListItem(state.contentUM.walletList) - tokensListItems( - tokensListData = state.contentUM.tokensListData, - isBalanceHidden = state.contentUM.isBalanceHidden, - ) + tokensListItems( + tokensListData = state.contentUM.tokensListData, + isBalanceHidden = state.contentUM.isBalanceHidden, + ) - if (state.contentUM.marketsState != null) { - item("markets_title_spacer") { SpacerH(height = 20.dp) } - swapMarketsListItems(state.contentUM.marketsState) + if (state.contentUM.marketsState != null) { + item("markets_title_spacer") { SpacerH(height = 20.dp) } + swapMarketsListItems(state.contentUM.marketsState) + } + } } } } - if (state.contentUM?.marketsState != null) { + if (state.contentUM?.marketsState != null && !state.contentUM.isNotFoundState && !state.contentUM.isEmptyState) { SetupMarketScrollTracker(state.contentUM.marketsState, lazyListState) } } @@ -183,26 +202,59 @@ private fun LazyListScope.assetsTitle() { private fun LazyListScope.walletListItem(walletList: WalletListUM) { if (walletList.items.isEmpty()) return item("wallet_list") { - Row( - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing16) - .fillMaxWidth(), + LazyRow( + modifier = Modifier.padding(top = 12.dp, bottom = 4.dp), horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8), - verticalAlignment = Alignment.CenterVertically, + contentPadding = PaddingValues(horizontal = 16.dp), ) { - walletList.items.forEach { um -> - val colors = when (um.type) { - TangemButtonType.Primary -> TangemButtonsDefaults.primaryButtonColors - else -> TangemButtonsDefaults.secondaryButtonColors - } - TangemButton( - text = um.text?.resolveReference().orEmpty(), - icon = TangemButtonIconPosition.None, - size = TangemButtonSize.Action, - colors = colors, - showProgress = false, - onClick = um.onClick, - enabled = true, + items(walletList.items) { um -> + WalletTabItem(um) + } + } + } +} + +@Composable +private fun WalletTabItem(state: WalletTabUM, modifier: Modifier = Modifier) { + val isSelected = state.isSelected + val backgroundColor = if (isSelected) TangemTheme.colors.button.primary else TangemTheme.colors.button.secondary + val buttonTextColor = if (isSelected) TangemTheme.colors.text.primary2 else TangemTheme.colors.text.primary1 + val countTextColor = if (isSelected) TangemTheme.colors.text.primary2 else TangemTheme.colors.text.secondary + val countBackground = if (isSelected) { + TangemTheme.colors.button.secondary.copy(alpha = 0.2f) + } else { + TangemTheme.colors.button.primary.copy(alpha = 0.1f) + } + + Row( + modifier = modifier + .clip(RoundedCornerShape(12.dp)) + .background(backgroundColor) + .clickable(onClick = state.onClick) + .padding(horizontal = 16.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = state.text.resolveReference(), + color = buttonTextColor, + style = TangemTheme.typography.button, + ) + + if (state.count != null) { + Spacer(modifier = Modifier.width(8.dp)) + + Box( + modifier = Modifier + .background(countBackground, shape = CircleShape) + .defaultMinSize(minWidth = 20.dp) + .padding(horizontal = 4.dp, vertical = 2.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = state.count.resolveReference(), + color = countTextColor, + style = TangemTheme.typography.caption1, ) } } @@ -253,6 +305,58 @@ private fun LazyListScope.tokensList(items: ImmutableList, isB ) } +private fun LazyListScope.emptyTokensList(modifier: Modifier = Modifier) { + item("EmptyTokensList") { + Box( + modifier = modifier + .background(TangemTheme.colors.background.secondary) + .fillParentMaxSize(), + ) { + Column(modifier = Modifier.align(Alignment.Center)) { + Image( + modifier = Modifier + .size(TangemTheme.dimens.size64) + .align(Alignment.CenterHorizontally), + painter = painterResource(id = R.drawable.ic_no_token_44), + colorFilter = ColorFilter.tint(TangemTheme.colors.icon.inactive), + contentDescription = null, + ) + Text( + modifier = Modifier + .padding(top = TangemTheme.dimens.spacing16) + .padding(horizontal = TangemTheme.dimens.spacing30) + .align(Alignment.CenterHorizontally), + text = stringResourceSafe(id = R.string.exchange_tokens_empty_tokens), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.Center, + ) + } + } + } +} + +private fun LazyListScope.tokensNotFound(modifier: Modifier = Modifier) { + item("TokensNotFound") { + Box( + modifier = modifier + .background(TangemTheme.colors.background.secondary) + .fillParentMaxSize(), + ) { + Text( + modifier = Modifier + .padding(top = TangemTheme.dimens.spacing32) + .padding(horizontal = TangemTheme.dimens.spacing30) + .align(Alignment.TopCenter), + text = stringResourceSafe(id = R.string.express_token_list_empty_search), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.Center, + ) + } + } +} + @Preview @Composable private fun TokenScreenPreview(@PreviewParameter(ChooseTokenScreenPreviewProvider::class) state: ChooseTokenFullUM) { @@ -321,31 +425,42 @@ private val accounts private val wallets get() = persistentListOf( - TangemButtonUM( + WalletTabUM( text = TextReference.Str(value = "Wallet 1"), - type = TangemButtonType.Primary, + isSelected = true, onClick = {}, + count = null, ), - TangemButtonUM( + WalletTabUM( + text = TextReference.Str(value = "Wallet 1"), + isSelected = true, + onClick = {}, + count = stringReference("3"), + ), + WalletTabUM( text = TextReference.Str(value = "Wallet 2"), - type = TangemButtonType.Secondary, + isSelected = false, onClick = {}, + count = stringReference("333"), ), - TangemButtonUM( + WalletTabUM( text = TextReference.Str(value = "Wallet 3"), - type = TangemButtonType.Secondary, + isSelected = false, onClick = {}, + count = null, ), ) +private val initialUM = ChooseTokenInitialUM( + screenTitle = stringReference("Choose token"), + onCloseClick = {}, + searchBar = searchBar, +) + private class ChooseTokenScreenPreviewProvider : PreviewParameterProvider { override val values: Sequence = sequenceOf( ChooseTokenFullUM( - initialUM = ChooseTokenInitialUM( - screenTitle = stringReference("Choose token"), - onCloseClick = {}, - searchBar = searchBar, - ), + initialUM = initialUM, contentUM = ChooseTokenUM( walletList = WalletListUM(wallets), isBalanceHidden = false, @@ -357,5 +472,15 @@ private class ChooseTokenScreenPreviewProvider : PreviewParameterProvider, + val items: ImmutableList, +) + +internal data class WalletTabUM( + val text: TextReference, + val count: TextReference?, + val isSelected: Boolean, + val onClick: () -> Unit, ) \ No newline at end of file