Updated on 2026-08-14
This commit is contained in:
parent
31e4cafad0
commit
36b4671a05
18 changed files with 629 additions and 203 deletions
|
|
@ -11,7 +11,7 @@ import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
|||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState.TokenOptionsState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState.TokensListItemState
|
||||
|
|
@ -205,21 +205,21 @@ internal object WalletPreviewData {
|
|||
}
|
||||
|
||||
val groupedOrganizeTokensState by lazy {
|
||||
OrganizeTokensStateHolder(
|
||||
OrganizeTokensState(
|
||||
itemsState = OrganizeTokensListState.GroupedByNetwork(
|
||||
items = draggableItems,
|
||||
),
|
||||
header = OrganizeTokensStateHolder.HeaderConfig(
|
||||
header = OrganizeTokensState.HeaderConfig(
|
||||
onSortByBalanceClick = {},
|
||||
onGroupByNetworkClick = {},
|
||||
),
|
||||
dragConfig = OrganizeTokensStateHolder.DragConfig(
|
||||
dndConfig = OrganizeTokensState.DragAndDropConfig(
|
||||
onItemDragged = { _, _ -> },
|
||||
onDragStart = {},
|
||||
canDragItemOver = { _, _ -> false },
|
||||
onItemDragEnd = {},
|
||||
),
|
||||
actions = OrganizeTokensStateHolder.ActionsConfig(
|
||||
actions = OrganizeTokensState.ActionsConfig(
|
||||
onApplyClick = {},
|
||||
onCancelClick = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens
|
||||
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
|
||||
internal interface OrganizeTokensIntents {
|
||||
|
||||
fun onBackClick()
|
||||
|
||||
fun onSortClick()
|
||||
|
||||
fun onGroupClick()
|
||||
|
||||
fun onApplyClick()
|
||||
|
||||
fun onCancelClick()
|
||||
|
||||
fun onItemDragged(from: ItemPosition, to: ItemPosition)
|
||||
|
||||
fun canDragItemOver(dragOver: ItemPosition, dragging: ItemPosition): Boolean
|
||||
|
||||
fun onItemDraggingStart(item: DraggableItem)
|
||||
|
||||
fun onItemDraggingEnd()
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ import com.tangem.feature.wallet.presentation.common.component.DraggableTokenIte
|
|||
import org.burnoutcrew.reorderable.*
|
||||
|
||||
@Composable
|
||||
internal fun OrganizeTokensScreen(state: OrganizeTokensStateHolder, modifier: Modifier = Modifier) {
|
||||
internal fun OrganizeTokensScreen(state: OrganizeTokensState, modifier: Modifier = Modifier) {
|
||||
val tokensListState = rememberLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -47,7 +47,7 @@ internal fun OrganizeTokensScreen(state: OrganizeTokensStateHolder, modifier: Mo
|
|||
modifier = Modifier.padding(paddingValues),
|
||||
listState = tokensListState,
|
||||
state = state.itemsState,
|
||||
dragConfig = state.dragConfig,
|
||||
dragConfig = state.dndConfig,
|
||||
)
|
||||
},
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
|
|
@ -62,7 +62,7 @@ internal fun OrganizeTokensScreen(state: OrganizeTokensStateHolder, modifier: Mo
|
|||
private fun TokenList(
|
||||
listState: LazyListState,
|
||||
state: OrganizeTokensListState,
|
||||
dragConfig: OrganizeTokensStateHolder.DragConfig,
|
||||
dragConfig: OrganizeTokensState.DragAndDropConfig,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
|
|
@ -166,7 +166,7 @@ private fun BottomGradient(modifier: Modifier = Modifier) {
|
|||
|
||||
@Composable
|
||||
private fun TopBar(
|
||||
config: OrganizeTokensStateHolder.HeaderConfig,
|
||||
config: OrganizeTokensState.HeaderConfig,
|
||||
tokensListState: LazyListState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -211,7 +211,7 @@ private fun TopBar(
|
|||
config = ActionButtonConfig(
|
||||
text = TextReference.Res(id = R.string.organize_tokens_sort_by_balance),
|
||||
iconResId = R.drawable.ic_sort_24,
|
||||
onClick = config.onSortByBalanceClick,
|
||||
onClick = config.onSortClick,
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
color = TangemTheme.colors.background.primary,
|
||||
|
|
@ -220,7 +220,7 @@ private fun TopBar(
|
|||
config = ActionButtonConfig(
|
||||
text = TextReference.Res(id = R.string.organize_tokens_group),
|
||||
iconResId = R.drawable.ic_group_24,
|
||||
onClick = config.onGroupByNetworkClick,
|
||||
onClick = config.onGroupClick,
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
color = TangemTheme.colors.background.primary,
|
||||
|
|
@ -230,7 +230,7 @@ private fun TopBar(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Actions(config: OrganizeTokensStateHolder.ActionsConfig, modifier: Modifier = Modifier) {
|
||||
private fun Actions(config: OrganizeTokensState.ActionsConfig, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
|
|
@ -308,7 +308,7 @@ private fun Modifier.applyShapeAndShadow(roundingMode: DraggableItem.RoundingMod
|
|||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun OrganizeTokensScreenPreview_Light(
|
||||
@PreviewParameter(OrganizeTokensStateProvider::class) state: OrganizeTokensStateHolder,
|
||||
@PreviewParameter(OrganizeTokensStateProvider::class) state: OrganizeTokensState,
|
||||
) {
|
||||
TangemTheme {
|
||||
OrganizeTokensScreen(state)
|
||||
|
|
@ -318,14 +318,14 @@ private fun OrganizeTokensScreenPreview_Light(
|
|||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun OrganizeTokensScreenPreview_Dark(
|
||||
@PreviewParameter(OrganizeTokensStateProvider::class) state: OrganizeTokensStateHolder,
|
||||
@PreviewParameter(OrganizeTokensStateProvider::class) state: OrganizeTokensState,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
OrganizeTokensScreen(state)
|
||||
}
|
||||
}
|
||||
|
||||
private class OrganizeTokensStateProvider : CollectionPreviewParameterProvider<OrganizeTokensStateHolder>(
|
||||
private class OrganizeTokensStateProvider : CollectionPreviewParameterProvider<OrganizeTokensState>(
|
||||
collection = listOf(
|
||||
WalletPreviewData.organizeTokensState,
|
||||
WalletPreviewData.groupedOrganizeTokensState,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem.RoundingMode
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
|
||||
@Immutable
|
||||
internal data class OrganizeTokensState(
|
||||
val onBackClick: () -> Unit,
|
||||
val itemsState: OrganizeTokensListState,
|
||||
val header: HeaderConfig,
|
||||
val actions: ActionsConfig,
|
||||
val dndConfig: DragAndDropConfig,
|
||||
) {
|
||||
|
||||
data class HeaderConfig(
|
||||
val isEnabled: Boolean = false,
|
||||
val isSortedByBalance: Boolean = false,
|
||||
val isGrouped: Boolean = false,
|
||||
val onSortClick: () -> Unit,
|
||||
val onGroupClick: () -> Unit,
|
||||
)
|
||||
|
||||
data class ActionsConfig(
|
||||
val canApply: Boolean = false,
|
||||
val showApplyProgress: Boolean = false,
|
||||
val onApplyClick: () -> Unit,
|
||||
val onCancelClick: () -> Unit,
|
||||
)
|
||||
|
||||
data class DragAndDropConfig(
|
||||
val onItemDragged: (ItemPosition, ItemPosition) -> Unit,
|
||||
val canDragItemOver: (ItemPosition, ItemPosition) -> Boolean,
|
||||
val onItemDragEnd: () -> Unit,
|
||||
val onDragStart: (DraggableItem) -> Unit,
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed class OrganizeTokensListState {
|
||||
abstract val items: PersistentList<DraggableItem>
|
||||
|
||||
data class GroupedByNetwork(
|
||||
override val items: PersistentList<DraggableItem>,
|
||||
) : OrganizeTokensListState()
|
||||
|
||||
data class Ungrouped(
|
||||
override val items: PersistentList<DraggableItem.Token>,
|
||||
) : OrganizeTokensListState()
|
||||
|
||||
object Empty : OrganizeTokensListState() {
|
||||
override val items: PersistentList<DraggableItem> = persistentListOf()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for the DND list items
|
||||
*
|
||||
* @property id ID of the item
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
@Immutable
|
||||
internal sealed class DraggableItem {
|
||||
abstract val id: String
|
||||
abstract val roundingMode: RoundingMode
|
||||
abstract val showShadow: Boolean
|
||||
|
||||
/**
|
||||
* Item for network group header.
|
||||
*
|
||||
* @property id ID of the network group
|
||||
* @property networkName network group name
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
data class GroupHeader(
|
||||
override val id: String,
|
||||
val networkName: String,
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
override val showShadow: Boolean = false,
|
||||
) : DraggableItem()
|
||||
|
||||
/**
|
||||
* Item for token.
|
||||
*
|
||||
* @property tokenItemState state of the token item
|
||||
* @property groupId ID of the network group which contains this token
|
||||
* @property id ID of the token
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
data class Token(
|
||||
val tokenItemState: TokenItemState.Draggable,
|
||||
val groupId: String,
|
||||
override val showShadow: Boolean = false,
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
) : DraggableItem() {
|
||||
override val id: String = tokenItemState.id
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper item used to detect possible positions where a network group can be placed.
|
||||
* Used only on [OrganizeTokensListState.GroupedByNetwork] and placed between network groups.
|
||||
*
|
||||
* @property id ID of the placeholder
|
||||
* */
|
||||
data class GroupPlaceholder(
|
||||
override val id: String,
|
||||
) : DraggableItem() {
|
||||
override val showShadow: Boolean = false
|
||||
override val roundingMode: RoundingMode = RoundingMode.None
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounding mode of the [DraggableItem]
|
||||
*
|
||||
* @property showGap if true then item should have padding on rounded side
|
||||
* */
|
||||
@Immutable
|
||||
sealed class RoundingMode {
|
||||
abstract val showGap: Boolean
|
||||
|
||||
/**
|
||||
* In this mode, item is not rounded
|
||||
* */
|
||||
object None : RoundingMode() {
|
||||
override val showGap: Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* In this mode, item should have a rounded top side
|
||||
*
|
||||
* @property showGap if true then item should have top padding
|
||||
* */
|
||||
data class Top(override val showGap: Boolean = false) : RoundingMode()
|
||||
|
||||
/**
|
||||
* In this mode, item should have a rounded bottom side
|
||||
*
|
||||
* @property showGap if true then item should have bottom padding
|
||||
* */
|
||||
data class Bottom(override val showGap: Boolean = false) : RoundingMode()
|
||||
|
||||
/**
|
||||
* In this mode, item should have a rounded all sides
|
||||
*
|
||||
* @property showGap if true then item should have top and bottom padding
|
||||
* */
|
||||
data class All(override val showGap: Boolean = false) : RoundingMode()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,179 +1,120 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.error.TokenListSortingError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.updateSorting
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.InProgressStateConverter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.TokenListToStateConverter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.error.TokenListErrorConverter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.error.TokenListSortingErrorConverter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.CryptoCurrencyToDraggableItemConverter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.NetworkGroupToDraggableItemsConverter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.TokenListToListStateConverter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
internal data class OrganizeTokensStateHolder(
|
||||
val header: HeaderConfig,
|
||||
val itemsState: OrganizeTokensListState,
|
||||
val dragConfig: DragConfig,
|
||||
val actions: ActionsConfig,
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate") // TODO: Will be used in next MR
|
||||
internal class OrganizeTokensStateHolder(
|
||||
private val intents: OrganizeTokensIntents,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
private val onSubscription: () -> Unit,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
|
||||
data class HeaderConfig(
|
||||
val onSortByBalanceClick: () -> Unit,
|
||||
val onGroupByNetworkClick: () -> Unit,
|
||||
)
|
||||
private val stateFlowInternal: MutableStateFlow<OrganizeTokensState> = MutableStateFlow(getInitialState())
|
||||
|
||||
data class ActionsConfig(
|
||||
val onApplyClick: () -> Unit,
|
||||
val onCancelClick: () -> Unit,
|
||||
)
|
||||
private val tokenListConverter by lazy {
|
||||
val tokensConverter = CryptoCurrencyToDraggableItemConverter(
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
fiatCurrencySymbol = fiatCurrencySymbol,
|
||||
)
|
||||
val itemsConverter = TokenListToListStateConverter(
|
||||
tokensConverter = tokensConverter,
|
||||
groupsConverter = NetworkGroupToDraggableItemsConverter(tokensConverter),
|
||||
)
|
||||
|
||||
data class DragConfig(
|
||||
val onItemDragged: (from: ItemPosition, to: ItemPosition) -> Unit,
|
||||
val canDragItemOver: (dragOver: ItemPosition, dragging: ItemPosition) -> Boolean,
|
||||
val onItemDragEnd: () -> Unit,
|
||||
val onDragStart: (item: DraggableItem) -> Unit,
|
||||
)
|
||||
}
|
||||
TokenListToStateConverter(Provider(stateFlowInternal::value), itemsConverter)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed interface OrganizeTokensListState {
|
||||
val items: PersistentList<DraggableItem>
|
||||
private val inProgressStateConverter by lazy {
|
||||
InProgressStateConverter()
|
||||
}
|
||||
|
||||
data class GroupedByNetwork(
|
||||
override val items: PersistentList<DraggableItem>,
|
||||
) : OrganizeTokensListState
|
||||
private val tokenListErrorConverter by lazy {
|
||||
TokenListErrorConverter(Provider(stateFlowInternal::value), inProgressStateConverter)
|
||||
}
|
||||
|
||||
data class Ungrouped(
|
||||
override val items: PersistentList<DraggableItem.Token>,
|
||||
) : OrganizeTokensListState
|
||||
private val tokenListSortingErrorConverter by lazy {
|
||||
TokenListSortingErrorConverter(Provider(stateFlowInternal::value), inProgressStateConverter)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun updateItems(update: (PersistentList<DraggableItem>) -> List<DraggableItem>): OrganizeTokensListState {
|
||||
val updatedItems = update(this.items).toPersistentList()
|
||||
val stateFlow: StateFlow<OrganizeTokensState> = stateFlowInternal
|
||||
.onSubscription { onSubscription() }
|
||||
.stateIn(
|
||||
scope = scope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = getInitialState(),
|
||||
)
|
||||
|
||||
return when (this) {
|
||||
is GroupedByNetwork -> this.copy(items = updatedItems)
|
||||
is Ungrouped -> this.copy(items = updatedItems as PersistentList<DraggableItem.Token>)
|
||||
var tokenList: TokenList? = null
|
||||
private set
|
||||
|
||||
fun updateStateWithTokenList(tokenList: TokenList) {
|
||||
updateState { tokenListConverter.convert(tokenList) }
|
||||
this.tokenList = tokenList
|
||||
}
|
||||
|
||||
fun updateStateToDisplayProgress() {
|
||||
updateState { inProgressStateConverter.convert(value = this) }
|
||||
}
|
||||
|
||||
fun updateStateToHideProgress() {
|
||||
updateState { inProgressStateConverter.convertBack(value = this) }
|
||||
}
|
||||
|
||||
fun updateStateWithManualSorting(itemsState: OrganizeTokensListState) {
|
||||
updateState {
|
||||
copy(
|
||||
header = header.copy(isSortedByBalance = false),
|
||||
itemsState = itemsState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for the DND list items
|
||||
*
|
||||
* @property id ID of the item
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
@Immutable
|
||||
internal sealed interface DraggableItem {
|
||||
val id: String
|
||||
val roundingMode: RoundingMode
|
||||
val showShadow: Boolean
|
||||
|
||||
/**
|
||||
* Item for network group header.
|
||||
*
|
||||
* @property id ID of the network group
|
||||
* @property networkName network group name
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
data class GroupHeader(
|
||||
override val id: String,
|
||||
val networkName: String,
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
override val showShadow: Boolean = false,
|
||||
) : DraggableItem
|
||||
|
||||
/**
|
||||
* Item for token.
|
||||
*
|
||||
* @property tokenItemState state of the token item
|
||||
* @property groupId ID of the network group which contains this token
|
||||
* @property id ID of the token
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
data class Token(
|
||||
val tokenItemState: TokenItemState.Draggable,
|
||||
val groupId: String,
|
||||
override val showShadow: Boolean = false,
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
) : DraggableItem {
|
||||
override val id: String = tokenItemState.id
|
||||
tokenList = tokenList?.updateSorting(isSortedByBalance = false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper item used to detect possible positions where a network group can be placed.
|
||||
* Used only on [OrganizeTokensListState.GroupedByNetwork] and placed between network groups.
|
||||
*
|
||||
* @property id ID of the placeholder
|
||||
* */
|
||||
data class GroupPlaceholder(
|
||||
override val id: String,
|
||||
) : DraggableItem {
|
||||
override val showShadow: Boolean = false
|
||||
override val roundingMode: RoundingMode = RoundingMode.None
|
||||
fun updateStateWithError(error: TokenListError) {
|
||||
updateState { tokenListErrorConverter.convert(error) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Update item [RoundingMode]
|
||||
*
|
||||
* @param mode new [RoundingMode]
|
||||
*
|
||||
* @return updated [DraggableItem]
|
||||
* */
|
||||
fun roundingMode(mode: RoundingMode): DraggableItem = when (this) {
|
||||
is GroupPlaceholder -> this
|
||||
is GroupHeader -> this.copy(roundingMode = mode)
|
||||
is Token -> this.copy(roundingMode = mode)
|
||||
fun updateStateWithError(error: TokenListSortingError) {
|
||||
updateState { tokenListSortingErrorConverter.convert(error) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Update item shadow visibility
|
||||
*
|
||||
* @param show if true then item should be elevated
|
||||
*
|
||||
* @return updated [DraggableItem]
|
||||
* */
|
||||
fun showShadow(show: Boolean): DraggableItem = when (this) {
|
||||
is GroupPlaceholder -> this
|
||||
is GroupHeader -> this.copy(showShadow = show)
|
||||
is Token -> this.copy(showShadow = show)
|
||||
private fun getInitialState(): OrganizeTokensState {
|
||||
return OrganizeTokensState(
|
||||
onBackClick = intents::onBackClick,
|
||||
itemsState = OrganizeTokensListState.Empty,
|
||||
header = OrganizeTokensState.HeaderConfig(
|
||||
onSortClick = intents::onSortClick,
|
||||
onGroupClick = intents::onGroupClick,
|
||||
),
|
||||
actions = OrganizeTokensState.ActionsConfig(
|
||||
onApplyClick = intents::onApplyClick,
|
||||
onCancelClick = intents::onCancelClick,
|
||||
),
|
||||
dndConfig = OrganizeTokensState.DragAndDropConfig(
|
||||
onItemDragged = intents::onItemDragged,
|
||||
onDragStart = intents::onItemDraggingStart,
|
||||
onItemDragEnd = intents::onItemDraggingEnd,
|
||||
canDragItemOver = intents::canDragItemOver,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounding mode of the [DraggableItem]
|
||||
*
|
||||
* @property showGap if true then item should have padding on rounded side
|
||||
* */
|
||||
@Immutable
|
||||
sealed interface RoundingMode {
|
||||
val showGap: Boolean
|
||||
|
||||
/**
|
||||
* In this mode, item is not rounded
|
||||
* */
|
||||
object None : RoundingMode {
|
||||
override val showGap: Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* In this mode, item should have a rounded top side
|
||||
*
|
||||
* @property showGap if true then item should have top padding
|
||||
* */
|
||||
data class Top(override val showGap: Boolean = false) : RoundingMode
|
||||
|
||||
/**
|
||||
* In this mode, item should have a rounded bottom side
|
||||
*
|
||||
* @property showGap if true then item should have bottom padding
|
||||
* */
|
||||
data class Bottom(override val showGap: Boolean = false) : RoundingMode
|
||||
|
||||
/**
|
||||
* In this mode, item should have a rounded all sides
|
||||
*
|
||||
* @property showGap if true then item should have top and bottom padding
|
||||
* */
|
||||
data class All(override val showGap: Boolean = false) : RoundingMode
|
||||
private fun updateState(block: OrganizeTokensState.() -> OrganizeTokensState) {
|
||||
stateFlowInternal.update(block)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder.DragConfig
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder.HeaderConfig
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.*
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.*
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.router.WalletRoute
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -35,22 +33,22 @@ internal class OrganizeTokensViewModel @Inject constructor(savedStateHandle: Sav
|
|||
UserWalletId(userWalletIdValue)
|
||||
}
|
||||
|
||||
var uiState: OrganizeTokensStateHolder by mutableStateOf(getInitialState())
|
||||
var uiState: OrganizeTokensState by mutableStateOf(getInitialState())
|
||||
private set
|
||||
|
||||
private fun getInitialState(): OrganizeTokensStateHolder = WalletPreviewData.organizeTokensState.copy(
|
||||
private fun getInitialState(): OrganizeTokensState = WalletPreviewData.organizeTokensState.copy(
|
||||
itemsState = OrganizeTokensListState.Ungrouped(
|
||||
items = WalletPreviewData.draggableTokens,
|
||||
),
|
||||
dragConfig = DragConfig(
|
||||
dndConfig = OrganizeTokensState.DragAndDropConfig(
|
||||
onItemDragged = this::moveItem,
|
||||
canDragItemOver = this::checkCanMoveItemOver,
|
||||
onItemDragEnd = this::endMoving,
|
||||
onDragStart = this::startMoving,
|
||||
),
|
||||
header = HeaderConfig(
|
||||
onSortByBalanceClick = { /* no-op */ },
|
||||
onGroupByNetworkClick = this::toggleTokensByNetworkGrouping,
|
||||
header = OrganizeTokensState.HeaderConfig(
|
||||
onSortClick = { /* no-op */ },
|
||||
onGroupClick = this::toggleTokensByNetworkGrouping,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -62,6 +60,7 @@ internal class OrganizeTokensViewModel @Inject constructor(savedStateHandle: Sav
|
|||
is OrganizeTokensListState.Ungrouped -> OrganizeTokensListState.GroupedByNetwork(
|
||||
items = WalletPreviewData.draggableItems,
|
||||
)
|
||||
is OrganizeTokensListState.Empty -> itemsState
|
||||
}
|
||||
|
||||
uiState = uiState.copy(itemsState = newListState)
|
||||
|
|
@ -95,6 +94,7 @@ internal class OrganizeTokensViewModel @Inject constructor(savedStateHandle: Sav
|
|||
is DraggableItem.Token -> when (uiState.itemsState) {
|
||||
is OrganizeTokensListState.GroupedByNetwork -> items.divideGroups(movingItem)
|
||||
is OrganizeTokensListState.Ungrouped -> items.divideItems(movingItem)
|
||||
is OrganizeTokensListState.Empty -> uiState.itemsState.items
|
||||
}
|
||||
is DraggableItem.GroupPlaceholder -> items
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
||||
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem.RoundingMode
|
||||
|
||||
/**
|
||||
* Update item [RoundingMode]
|
||||
*
|
||||
* @param mode new [RoundingMode]
|
||||
*
|
||||
* @return updated [DraggableItem]
|
||||
* */
|
||||
internal fun DraggableItem.updateRoundingMode(mode: RoundingMode): DraggableItem = when (this) {
|
||||
is DraggableItem.GroupPlaceholder -> this
|
||||
is DraggableItem.GroupHeader -> this.copy(roundingMode = mode)
|
||||
is DraggableItem.Token -> this.copy(roundingMode = mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update item shadow visibility
|
||||
*
|
||||
* @param show if true then item should be elevated
|
||||
*
|
||||
* @return updated [DraggableItem]
|
||||
* */
|
||||
internal fun DraggableItem.updateShadowVisibility(show: Boolean): DraggableItem = when (this) {
|
||||
is DraggableItem.GroupPlaceholder -> this
|
||||
is DraggableItem.GroupHeader -> this.copy(showShadow = show)
|
||||
is DraggableItem.Token -> this.copy(showShadow = show)
|
||||
}
|
||||
|
||||
internal fun getGroupPlaceholder(index: Int): DraggableItem.GroupPlaceholder {
|
||||
return DraggableItem.GroupPlaceholder(id = "placeholder_${index.inc()}")
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils
|
||||
package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
||||
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
|
@ -59,13 +59,15 @@ internal fun PersistentList<DraggableItem>.moveItem(fromIndex: Int, toIndex: Int
|
|||
internal fun List<DraggableItem>.divideItems(movingItem: DraggableItem): List<DraggableItem> {
|
||||
return this.map {
|
||||
it
|
||||
.roundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.showShadow(show = it.id == movingItem.id)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.updateShadowVisibility(show = it.id == movingItem.id)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun List<DraggableItem>.uniteItems(): List<DraggableItem> {
|
||||
@Suppress("UNCHECKED_CAST") // Erased type
|
||||
internal fun <T : DraggableItem> List<T>.uniteItems(): List<T> {
|
||||
val lastItemIndex = this.lastIndex
|
||||
|
||||
return this.mapIndexed { index, item ->
|
||||
val mode = when (index) {
|
||||
0 -> DraggableItem.RoundingMode.Top()
|
||||
|
|
@ -74,9 +76,9 @@ internal fun List<DraggableItem>.uniteItems(): List<DraggableItem> {
|
|||
}
|
||||
|
||||
item
|
||||
.roundingMode(mode)
|
||||
.showShadow(show = false)
|
||||
}
|
||||
.updateRoundingMode(mode)
|
||||
.updateShadowVisibility(show = false)
|
||||
} as List<T>
|
||||
}
|
||||
|
||||
// TODO: Move to domain
|
||||
|
|
@ -131,51 +133,51 @@ internal fun List<DraggableItem>.divideGroups(movingItem: DraggableItem): List<D
|
|||
// Case when current item is the moving item
|
||||
item.id == movingItem.id -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.showShadow(show = true)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.updateShadowVisibility(show = true)
|
||||
}
|
||||
// Case when moving item is a token and current item is the group of the moving token
|
||||
movingItem is DraggableItem.Token && item.id == movingItem.groupId -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.showShadow(show = true)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.updateShadowVisibility(show = true)
|
||||
}
|
||||
// Case when both moving item and current item are tokens and belong to the same group
|
||||
movingItem is DraggableItem.Token &&
|
||||
item is DraggableItem.Token && item.groupId == movingItem.groupId -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.showShadow(show = false)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.All(showGap = true))
|
||||
.updateShadowVisibility(show = false)
|
||||
}
|
||||
// Case when current item is the first item in the list
|
||||
index == 0 -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.Top())
|
||||
.showShadow(show = false)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.Top())
|
||||
.updateShadowVisibility(show = false)
|
||||
}
|
||||
// Case when current item is the last item in the list
|
||||
index == lastItemIndex -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.Bottom())
|
||||
.showShadow(show = false)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.Bottom())
|
||||
.updateShadowVisibility(show = false)
|
||||
}
|
||||
// Case when previous item is a GroupPlaceholder
|
||||
this[index - 1] is DraggableItem.GroupPlaceholder -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.Top(showGap = true))
|
||||
.showShadow(show = false)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.Top(showGap = true))
|
||||
.updateShadowVisibility(show = false)
|
||||
}
|
||||
// Case when next item is a GroupPlaceholder
|
||||
this[index + 1] is DraggableItem.GroupPlaceholder -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.Bottom(showGap = true))
|
||||
.showShadow(show = false)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.Bottom(showGap = true))
|
||||
.updateShadowVisibility(show = false)
|
||||
}
|
||||
// Default case when none of the above conditions are met
|
||||
else -> {
|
||||
item
|
||||
.roundingMode(DraggableItem.RoundingMode.None)
|
||||
.showShadow(show = false)
|
||||
.updateRoundingMode(DraggableItem.RoundingMode.None)
|
||||
.updateShadowVisibility(show = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
||||
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
|
||||
internal fun getTokenItemId(currencyId: CryptoCurrency.ID): String = currencyId.value
|
||||
|
||||
internal fun getGroupHeaderId(networkId: Network.ID): String = networkId.value
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
||||
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal inline fun OrganizeTokensListState.updateItems(
|
||||
update: (PersistentList<DraggableItem>) -> List<DraggableItem>,
|
||||
): OrganizeTokensListState {
|
||||
val updatedItems = update(items).toPersistentList()
|
||||
|
||||
return when (this) {
|
||||
is OrganizeTokensListState.GroupedByNetwork -> copy(items = updatedItems)
|
||||
is OrganizeTokensListState.Ungrouped -> copy(items = updatedItems as PersistentList<DraggableItem.Token>)
|
||||
is OrganizeTokensListState.Empty -> this
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
||||
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.model.TokenList.SortType
|
||||
|
||||
internal fun TokenList.updateSorting(isSortedByBalance: Boolean): TokenList {
|
||||
val sortType = if (isSortedByBalance) SortType.BALANCE else SortType.NONE
|
||||
|
||||
return when (this) {
|
||||
is TokenList.GroupedByNetwork -> this.copy(sortedBy = sortType)
|
||||
is TokenList.Ungrouped -> this.copy(sortedBy = sortType)
|
||||
is TokenList.NotInitialized -> this
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter
|
||||
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensState
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
internal class InProgressStateConverter : TwoWayConverter<OrganizeTokensState, OrganizeTokensState> {
|
||||
|
||||
override fun convert(value: OrganizeTokensState): OrganizeTokensState {
|
||||
return value.copy(
|
||||
actions = value.actions.copy(
|
||||
showApplyProgress = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun convertBack(value: OrganizeTokensState): OrganizeTokensState {
|
||||
return value.copy(
|
||||
actions = value.actions.copy(
|
||||
showApplyProgress = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.TokenListToListStateConverter
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class TokenListToStateConverter(
|
||||
private val currentState: Provider<OrganizeTokensState>,
|
||||
private val itemsConverter: TokenListToListStateConverter,
|
||||
) : Converter<TokenList, OrganizeTokensState> {
|
||||
|
||||
override fun convert(value: TokenList): OrganizeTokensState {
|
||||
val state = currentState()
|
||||
val itemsState = itemsConverter.convert(value)
|
||||
|
||||
return state.copy(
|
||||
itemsState = itemsState,
|
||||
header = state.header.copy(
|
||||
isEnabled = itemsState !is OrganizeTokensListState.Empty,
|
||||
isSortedByBalance = value.sortedBy == TokenList.SortType.BALANCE,
|
||||
isGrouped = value is TokenList.GroupedByNetwork,
|
||||
),
|
||||
actions = state.actions.copy(
|
||||
canApply = itemsState !is OrganizeTokensListState.Empty,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.error
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.InProgressStateConverter
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class TokenListErrorConverter(
|
||||
private val currentState: Provider<OrganizeTokensState>,
|
||||
private val inProgressStateConverter: InProgressStateConverter,
|
||||
) : Converter<TokenListError, OrganizeTokensState> {
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
override fun convert(value: TokenListError): OrganizeTokensState {
|
||||
return inProgressStateConverter.convertBack(currentState())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.error
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.tokens.error.TokenListSortingError
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.InProgressStateConverter
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class TokenListSortingErrorConverter(
|
||||
private val currentState: Provider<OrganizeTokensState>,
|
||||
private val inProgressStateConverter: InProgressStateConverter,
|
||||
) : Converter<TokenListSortingError, OrganizeTokensState> {
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
override fun convert(value: TokenListSortingError): OrganizeTokensState {
|
||||
return inProgressStateConverter.convertBack(currentState())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupHeaderId
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getTokenItemId
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class CryptoCurrencyToDraggableItemConverter(
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
) : Converter<CryptoCurrencyStatus, DraggableItem.Token> {
|
||||
|
||||
private val CryptoCurrency.networkIconResId: Int?
|
||||
@DrawableRes get() {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
return if (this is CryptoCurrency.Coin) null else R.drawable.img_eth_22
|
||||
}
|
||||
|
||||
private val CryptoCurrency.tokenIconResId: Int
|
||||
@DrawableRes get() {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
return R.drawable.img_eth_22
|
||||
}
|
||||
|
||||
override fun convert(value: CryptoCurrencyStatus): DraggableItem.Token {
|
||||
return DraggableItem.Token(
|
||||
tokenItemState = createToTokenItemState(value),
|
||||
groupId = getGroupHeaderId(value.currency.networkId),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createToTokenItemState(currencyStatus: CryptoCurrencyStatus): TokenItemState.Draggable {
|
||||
val currency = currencyStatus.currency
|
||||
|
||||
return TokenItemState.Draggable(
|
||||
id = getTokenItemId(currency.id),
|
||||
tokenIconUrl = currency.iconUrl,
|
||||
tokenIconResId = currency.tokenIconResId,
|
||||
networkIconResId = currency.networkIconResId,
|
||||
name = currency.name,
|
||||
fiatAmount = getFormattedFiatAmount(currencyStatus),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFormattedFiatAmount(currency: CryptoCurrencyStatus): String {
|
||||
val fiatAmount = currency.value.fiatAmount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
|
||||
return BigDecimalFormatter.formatFiatAmount(fiatAmount, fiatCurrencyCode, fiatCurrencySymbol)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
|
||||
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupHeaderId
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupPlaceholder
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class NetworkGroupToDraggableItemsConverter(
|
||||
private val itemConverter: CryptoCurrencyToDraggableItemConverter,
|
||||
) : Converter<NetworkGroup, List<DraggableItem>> {
|
||||
|
||||
override fun convert(value: NetworkGroup): List<DraggableItem> {
|
||||
return buildList {
|
||||
add(createGroupHeader(value))
|
||||
addAll(createTokens(value))
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertList(input: Collection<NetworkGroup>): List<List<DraggableItem>> {
|
||||
val lastItemIndex = input.size - 1
|
||||
|
||||
return input.mapIndexed { index, networkGroup ->
|
||||
convert(networkGroup).toMutableList()
|
||||
.also { mutableGroup ->
|
||||
if (index != lastItemIndex) {
|
||||
mutableGroup.add(getGroupPlaceholder(index))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createGroupHeader(group: NetworkGroup) = DraggableItem.GroupHeader(
|
||||
id = getGroupHeaderId(group.network.id),
|
||||
networkName = group.network.name,
|
||||
)
|
||||
|
||||
private fun createTokens(group: NetworkGroup): List<DraggableItem.Token> {
|
||||
return itemConverter.convertList(group.currencies.toList())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
|
||||
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.uniteItems
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class TokenListToListStateConverter(
|
||||
private val groupsConverter: NetworkGroupToDraggableItemsConverter,
|
||||
private val tokensConverter: CryptoCurrencyToDraggableItemConverter,
|
||||
) : Converter<TokenList, OrganizeTokensListState> {
|
||||
|
||||
override fun convert(value: TokenList): OrganizeTokensListState {
|
||||
return when (value) {
|
||||
is TokenList.GroupedByNetwork -> createListState(value)
|
||||
is TokenList.Ungrouped -> createListState(value)
|
||||
is TokenList.NotInitialized -> createEmptyListState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createListState(tokenList: TokenList.GroupedByNetwork): OrganizeTokensListState.GroupedByNetwork {
|
||||
return OrganizeTokensListState.GroupedByNetwork(
|
||||
items = groupsConverter.convertList(tokenList.groups)
|
||||
.flatten()
|
||||
.uniteItems()
|
||||
.toPersistentList(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createListState(tokenList: TokenList.Ungrouped): OrganizeTokensListState.Ungrouped {
|
||||
return OrganizeTokensListState.Ungrouped(
|
||||
items = tokensConverter.convertList(tokenList.currencies)
|
||||
.uniteItems()
|
||||
.toPersistentList(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createEmptyListState(): OrganizeTokensListState.Empty {
|
||||
return OrganizeTokensListState.Empty
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue