Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-28 15:36:35 +04:00
parent 9230cc4694
commit 41131e5b73
13 changed files with 114 additions and 79 deletions

View file

@ -1,4 +1,4 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
package com.tangem.core.ui.components.tokenlist
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
@ -6,36 +6,33 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.components.token.TokenItem
import com.tangem.core.ui.components.tokenlist.internal.NetworkTitleItem
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.feature.wallet.presentation.common.component.NetworkTitleItem
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
/**
* Multi-currency content item
*
* @param state item state
* @param modifier modifier
* @param state component UI model
* @param isBalanceHidden flag that shows/hides balance
* @param modifier modifier
*
[REDACTED_AUTHOR]
*/
@Composable
internal fun MultiCurrencyContentItem(
state: TokensListItemState,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
fun TokenListItem(state: TokensListItemUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
when (state) {
is TokensListItemState.NetworkGroupTitle -> {
is TokensListItemUM.NetworkGroupTitle -> {
NetworkTitleItem(networkName = state.name.resolveReference(), modifier = modifier)
}
is TokensListItemState.Token -> {
is TokensListItemUM.Token -> {
TokenItem(
state = state.state,
isBalanceHidden = isBalanceHidden,
modifier = modifier,
)
}
is TokensListItemState.SearchBar -> {
is TokensListItemUM.SearchBar -> {
SearchBar(state = state.searchBarUM, modifier = modifier.padding(all = 12.dp))
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.feature.wallet.presentation.common.component
package com.tangem.core.ui.components.tokenlist.internal
import android.content.res.Configuration
import androidx.compose.foundation.background
@ -17,21 +17,34 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.R
import com.tangem.core.ui.components.rows.NetworkTitle
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.wallet.impl.R
import org.burnoutcrew.reorderable.ReorderableLazyListState
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
/**
* Network title item
*
* @param networkName network name
* @param modifier modifier
*/
@Composable
internal fun NetworkTitleItem(networkName: String, modifier: Modifier = Modifier) {
BaseNetworkTitleItem(networkName = networkName, modifier = modifier)
}
/**
* Draggable network title item
*
* @param networkName network name
* @param reorderableTokenListState reorderable token list state
* @param modifier modifier
*/
@Composable
internal fun DraggableNetworkTitleItem(
fun DraggableNetworkTitleItem(
networkName: String,
reorderableTokenListState: ReorderableLazyListState,
modifier: Modifier = Modifier,

View file

@ -0,0 +1,42 @@
package com.tangem.core.ui.components.tokenlist.state
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.TextReference
/** Tokens list item state */
@Immutable
sealed interface TokensListItemUM {
/** Unique ID */
val id: Any
/**
* Search bar item
*
* @property id id
* @property searchBarUM search bar UI model
*/
data class SearchBar(
override val id: Any = "search_bar",
val searchBarUM: SearchBarUM,
) : TokensListItemUM
/**
* Network group title
*
* @property id id
* @property name network group name
*/
data class NetworkGroupTitle(override val id: Int, val name: TextReference) : TokensListItemUM
/**
* Token item
*
* @property state token state
*/
data class Token(val state: TokenItemState) : TokensListItemUM {
override val id: String = state.id
}
}

View file

@ -3,15 +3,16 @@ package com.tangem.feature.wallet.presentation.common.preview
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.WalletPreviewData.topBarConfig
import com.tangem.feature.wallet.presentation.wallet.state.model.*
import com.tangem.utils.StringsSigns.DASH_SIGN
import kotlinx.collections.immutable.persistentListOf
internal object WalletScreenPreviewData {
@ -32,16 +33,16 @@ internal object WalletScreenPreviewData {
private val textContentTokensState = WalletTokensListState.ContentState.Content(
items = persistentListOf(
WalletTokensListState.TokensListItemState.NetworkGroupTitle(
TokensListItemUM.NetworkGroupTitle(
id = 1,
name = stringReference("Bitcoin"),
),
WalletTokensListState.TokensListItemState.Token(state = tokenItemState),
WalletTokensListState.TokensListItemState.NetworkGroupTitle(
TokensListItemUM.Token(state = tokenItemState),
TokensListItemUM.NetworkGroupTitle(
id = 2,
name = stringReference("Ethereum"),
),
WalletTokensListState.TokensListItemState.Token(
TokensListItemUM.Token(
state = tokenItemState.copy(
id = "2",
titleState = TokenItemState.TitleState.Content(text = "Ethereum"),
@ -54,7 +55,7 @@ internal object WalletScreenPreviewData {
),
),
),
WalletTokensListState.TokensListItemState.Token(
TokensListItemUM.Token(
state = TokenItemState.Unreachable(
id = "3",
iconState = CurrencyIconState.Locked,
@ -63,7 +64,7 @@ internal object WalletScreenPreviewData {
onItemLongClick = {},
),
),
WalletTokensListState.TokensListItemState.Token(
TokensListItemUM.Token(
state = tokenItemState.copy(
id = "4",
titleState = TokenItemState.TitleState.Content(text = "Shiba Inu"),
@ -106,7 +107,7 @@ internal object WalletScreenPreviewData {
),
imageResId = R.drawable.ill_wallet2_cards3_120_106,
cardCount = 3,
balance = BigDecimalFormatter.EMPTY_BALANCE_SIGN,
balance = DASH_SIGN,
onRenameClick = { _ -> },
onDeleteClick = {},
)

View file

@ -32,6 +32,7 @@ import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
import com.tangem.core.ui.components.token.TokenItem
import com.tangem.core.ui.components.tokenlist.internal.DraggableNetworkTitleItem
import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.reordarable.ReorderableItem
@ -40,7 +41,6 @@ import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.WindowInsetsZero
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.common.component.DraggableNetworkTitleItem
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState

View file

@ -1,6 +1,6 @@
package com.tangem.feature.wallet.presentation.tokenlist.entity
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -13,17 +13,17 @@ import kotlinx.collections.immutable.persistentListOf
[REDACTED_AUTHOR]
*/
internal data class TokenListUM(
val items: ImmutableList<TokensListItemState>,
val items: ImmutableList<TokensListItemUM>,
val isBalanceHidden: Boolean,
) {
/** Get search bar if it exists */
fun getSearchBar(): TokensListItemState.SearchBar? {
return items.firstOrNull() as? TokensListItemState.SearchBar
fun getSearchBar(): TokensListItemUM.SearchBar? {
return items.firstOrNull() as? TokensListItemUM.SearchBar
}
/** Get tokens */
fun getTokens(): ImmutableList<TokensListItemState> {
fun getTokens(): ImmutableList<TokensListItemUM> {
if (getSearchBar() == null) return items
return if (items.size > 1) {

View file

@ -1,6 +1,6 @@
package com.tangem.feature.wallet.presentation.tokenlist.entity
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -35,7 +35,7 @@ internal class TokenListUMController @Inject constructor() {
}
/** Get search bar if it exists */
fun getSearchBar(): TokensListItemState.SearchBar? {
fun getSearchBar(): TokensListItemUM.SearchBar? {
return _state.value.getSearchBar()
}
}

View file

@ -2,12 +2,12 @@ package com.tangem.feature.wallet.presentation.tokenlist.entity.transformer
import com.tangem.common.ui.tokens.TokenItemStateConverter
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUMTransformer
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
import kotlinx.collections.immutable.toImmutableList
internal class UpdateTokenItemsTransformer(
@ -20,7 +20,7 @@ internal class UpdateTokenItemsTransformer(
) : TokenListUMTransformer {
override fun transform(prevState: TokenListUM): TokenListUM {
val items = tokenItemStateConverter.convertList(input = statuses).map(TokensListItemState::Token)
val items = tokenItemStateConverter.convertList(input = statuses).map(TokensListItemUM::Token)
val searchBarItem = if (hasSearchBar) {
prevState.getSearchBar() ?: createSearchBarItem()
@ -34,8 +34,8 @@ internal class UpdateTokenItemsTransformer(
)
}
private fun createSearchBarItem(): TokensListItemState.SearchBar {
return TokensListItemState.SearchBar(
private fun createSearchBarItem(): TokensListItemUM.SearchBar {
return TokensListItemUM.SearchBar(
searchBarUM = SearchBarUM(
placeholderText = resourceReference(id = R.string.common_search),
query = "",

View file

@ -10,12 +10,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.tokenlist.TokenListItem
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
import com.tangem.feature.wallet.presentation.tokenlist.ui.preview.PreviewTokenListUMProvider
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.MultiCurrencyContentItem
/**
* Token list
@ -33,7 +33,7 @@ internal fun TokenList(state: TokenListUM, contentPadding: PaddingValues, modifi
key = { _, item -> item.id },
contentType = { _, item -> item::class.java },
itemContent = { index, item ->
MultiCurrencyContentItem(
TokenListItem(
state = item,
isBalanceHidden = state.isBalanceHidden,
modifier = Modifier

View file

@ -5,10 +5,10 @@ import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.tokenlist.entity.TokenListUM
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
import kotlinx.collections.immutable.toImmutableList
internal class PreviewTokenListUMProvider : PreviewParameterProvider<TokenListUM> {
@ -18,11 +18,11 @@ internal class PreviewTokenListUMProvider : PreviewParameterProvider<TokenListUM
createTokensList(hasSearchBar = true, createDefaultTokenItem()),
)
private fun createTokensList(hasSearchBar: Boolean, vararg items: TokensListItemState): TokenListUM {
private fun createTokensList(hasSearchBar: Boolean, vararg items: TokensListItemUM): TokenListUM {
return TokenListUM(
items = buildList {
if (hasSearchBar) {
TokensListItemState.SearchBar(
TokensListItemUM.SearchBar(
searchBarUM = SearchBarUM(
placeholderText = resourceReference(id = R.string.common_search),
query = "",
@ -41,8 +41,8 @@ internal class PreviewTokenListUMProvider : PreviewParameterProvider<TokenListUM
)
}
private fun createDefaultTokenItem(): TokensListItemState.Token {
return TokensListItemState.Token(
private fun createDefaultTokenItem(): TokensListItemUM.Token {
return TokensListItemUM.Token(
state = TokenItemState.Content(
id = "1",
iconState = CurrencyIconState.Locked,

View file

@ -1,8 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.state.model
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.feature.wallet.impl.R
import kotlinx.collections.immutable.ImmutableList
@ -15,44 +15,27 @@ internal sealed class WalletTokensListState {
sealed class ContentState : WalletTokensListState() {
abstract val items: ImmutableList<TokensListItemState>
abstract val items: ImmutableList<TokensListItemUM>
abstract val organizeTokensButtonConfig: OrganizeTokensButtonConfig?
data object Loading : ContentState() {
override val items = persistentListOf<TokensListItemState>()
override val items = persistentListOf<TokensListItemUM>()
override val organizeTokensButtonConfig = null
}
data class Content(
override val items: ImmutableList<TokensListItemState>,
override val items: ImmutableList<TokensListItemUM>,
override val organizeTokensButtonConfig: OrganizeTokensButtonConfig?,
) : ContentState()
data object Locked : ContentState() {
override val items = persistentListOf(
TokensListItemState.NetworkGroupTitle(id = 42, name = TextReference.Res(id = R.string.main_tokens)),
TokensListItemState.Token(state = TokenItemState.Locked(id = "Locked#1")),
TokensListItemUM.NetworkGroupTitle(id = 42, name = TextReference.Res(id = R.string.main_tokens)),
TokensListItemUM.Token(state = TokenItemState.Locked(id = "Locked#1")),
)
override val organizeTokensButtonConfig = null
}
}
data class OrganizeTokensButtonConfig(val isEnabled: Boolean, val onClick: () -> Unit)
@Immutable
sealed class TokensListItemState {
abstract val id: Any
data class SearchBar(
override val id: Any = "search_bar",
val searchBarUM: SearchBarUM,
) : TokensListItemState()
data class NetworkGroupTitle(override val id: Int, val name: TextReference) : TokensListItemState()
data class Token(val state: TokenItemState) : TokensListItemState() {
override val id: String = state.id
}
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
import com.tangem.common.ui.tokens.TokenItemStateConverter
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.cardTypesResolver
@ -10,7 +11,6 @@ import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
@ -47,20 +47,20 @@ internal class TokenListStateConverter(
}
}
private fun TokenList.GroupedByNetwork.toGroupedItems(): PersistentList<TokensListItemState> {
private fun TokenList.GroupedByNetwork.toGroupedItems(): PersistentList<TokensListItemUM> {
return groups.fold(initial = persistentListOf()) { acc, group ->
acc.mutate { it.addGroup(group) }
}
}
private fun TokenList.Ungrouped.toUngroupedItems(): PersistentList<TokensListItemState> {
private fun TokenList.Ungrouped.toUngroupedItems(): PersistentList<TokensListItemUM> {
return currencies.fold(initial = persistentListOf()) { acc, token ->
acc.mutate { it.addToken(token) }
}
}
private fun MutableList<TokensListItemState>.addGroup(group: NetworkGroup): List<TokensListItemState> {
val groupTitle = TokensListItemState.NetworkGroupTitle(
private fun MutableList<TokensListItemUM>.addGroup(group: NetworkGroup): List<TokensListItemUM> {
val groupTitle = TokensListItemUM.NetworkGroupTitle(
id = group.network.hashCode(),
name = stringReference(group.network.name),
)
@ -71,9 +71,9 @@ internal class TokenListStateConverter(
return this
}
private fun MutableList<TokensListItemState>.addToken(token: CryptoCurrencyStatus): List<TokensListItemState> {
private fun MutableList<TokensListItemUM>.addToken(token: CryptoCurrencyStatus): List<TokensListItemUM> {
val tokenItemState = tokenStatusConverter.convert(token)
add(TokensListItemState.Token(tokenItemState))
add(TokensListItemUM.Token(tokenItemState))
return this
}

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
@ -14,11 +13,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.components.tokenlist.TokenListItem
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.TokensListItemState
import kotlinx.collections.immutable.ImmutableList
private const val NON_CONTENT_TOKENS_LIST_KEY = "NON_CONTENT_TOKENS_LIST"
@ -49,7 +49,7 @@ internal fun LazyListScope.tokensListItems(
}
private fun LazyListScope.contentItems(
items: ImmutableList<TokensListItemState>,
items: ImmutableList<TokensListItemUM>,
modifier: Modifier = Modifier,
isBalanceHidden: Boolean,
) {
@ -58,7 +58,7 @@ private fun LazyListScope.contentItems(
key = { _, item -> item.id },
contentType = { _, item -> item::class.java },
itemContent = { index, item ->
MultiCurrencyContentItem(
TokenListItem(
state = item,
isBalanceHidden = isBalanceHidden,
modifier = modifier.roundedShapeItemDecoration(
@ -71,7 +71,6 @@ private fun LazyListScope.contentItems(
)
}
@OptIn(ExperimentalFoundationApi::class)
private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
item(
key = NON_CONTENT_TOKENS_LIST_KEY,
@ -79,7 +78,7 @@ private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
) {
Column(
modifier = modifier
.animateItemPlacement()
.animateItem()
.padding(top = TangemTheme.dimens.spacing96),
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16),
horizontalAlignment = Alignment.CenterHorizontally,