Updated on 2026-08-14
This commit is contained in:
parent
804e4eca23
commit
fd018a73f9
21 changed files with 918 additions and 79 deletions
|
|
@ -71,7 +71,6 @@ fun NetworkTitle(
|
|||
Spacer(modifier = Modifier.size(TangemTheme.dimens.spacing8))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(weight = 1f)
|
||||
.heightIn(min = TangemTheme.dimens.size24),
|
||||
contentAlignment = Alignment.CenterEnd,
|
||||
content = action,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ fun PortfolioTokensListItem(state: PortfolioTokensListItemUM, isBalanceHidden: B
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ExpandedPortfolioHeader(state: TokenItemState, isCollapsable: Boolean, modifier: Modifier = Modifier) {
|
||||
fun ExpandedPortfolioHeader(state: TokenItemState, isCollapsable: Boolean, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
|
|
|
|||
|
|
@ -38,4 +38,8 @@ sealed interface AccountStatus {
|
|||
fun flattenCurrencies(): List<CryptoCurrencyStatus> = when (this) {
|
||||
is CryptoPortfolio -> tokenList.flattenCurrencies()
|
||||
}
|
||||
|
||||
fun getCryptoTokenList(): TokenList = when (this) {
|
||||
is CryptoPortfolio -> tokenList
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,11 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
|
|
@ -27,6 +32,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeToken
|
|||
import com.tangem.feature.wallet.presentation.organizetokens.utils.CryptoCurrenciesIdsResolver
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.disableSortingByBalance
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.dnd.DragAndDropAdapter
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.dnd.DragAndDropAdapterV2
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -46,6 +52,9 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
) : Model(), OrganizeTokensIntents {
|
||||
|
||||
private val selectedAppCurrencyFlow = createSelectedAppCurrencyFlow()
|
||||
|
|
@ -56,15 +65,22 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
listStateProvider = Provider { uiState.value.itemsState },
|
||||
)
|
||||
|
||||
private val dragAndDropAdapterV2 = DragAndDropAdapterV2(
|
||||
tokenListUMProvider = Provider { uiState.value.tokenListUM },
|
||||
)
|
||||
|
||||
private val stateHolder = OrganizeTokensStateHolder(
|
||||
intents = this,
|
||||
dragAndDropIntents = dragAndDropAdapter,
|
||||
dragAndDropAdapterV2 = dragAndDropAdapterV2,
|
||||
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
)
|
||||
|
||||
private val userWalletId = paramsContainer.require<OrganizeTokensComponent.Params>().userWalletId
|
||||
|
||||
private var cachedTokenList: TokenList? = null
|
||||
private var cachedAccountStatusList: AccountStatusList? = null
|
||||
|
||||
val uiState: StateFlow<OrganizeTokensState> = stateHolder.stateFlow
|
||||
|
||||
|
|
@ -89,59 +105,92 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onSortClick() {
|
||||
val list = cachedTokenList ?: return
|
||||
if (list.sortedBy == TokensSortType.BALANCE) return
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
val list = cachedAccountStatusList ?: return
|
||||
if (list.sortType == TokensSortType.BALANCE) return
|
||||
|
||||
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ByBalance)
|
||||
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ByBalance)
|
||||
|
||||
modelScope.launch {
|
||||
toggleTokenListSortingUseCase(list).fold(
|
||||
ifLeft = stateHolder::updateStateWithError,
|
||||
ifRight = {
|
||||
stateHolder.updateStateAfterTokenListSorting(it)
|
||||
cachedTokenList = it
|
||||
},
|
||||
)
|
||||
modelScope.launch {
|
||||
// todo account token list sorting
|
||||
}
|
||||
} else {
|
||||
val list = cachedTokenList ?: return
|
||||
if (list.sortedBy == TokensSortType.BALANCE) return
|
||||
|
||||
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ByBalance)
|
||||
|
||||
modelScope.launch {
|
||||
toggleTokenListSortingUseCase(list).fold(
|
||||
ifLeft = stateHolder::updateStateWithError,
|
||||
ifRight = {
|
||||
stateHolder.updateStateAfterTokenListSorting(it)
|
||||
cachedTokenList = it
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGroupClick() {
|
||||
val list = cachedTokenList ?: return
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
cachedAccountStatusList ?: return
|
||||
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Group)
|
||||
modelScope.launch {
|
||||
// todo account token list grouping
|
||||
}
|
||||
} else {
|
||||
val list = cachedTokenList ?: return
|
||||
|
||||
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Group)
|
||||
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Group)
|
||||
|
||||
modelScope.launch {
|
||||
toggleTokenListGroupingUseCase(list).fold(
|
||||
ifLeft = stateHolder::updateStateWithError,
|
||||
ifRight = {
|
||||
stateHolder.updateStateAfterTokenListSorting(it)
|
||||
cachedTokenList = it
|
||||
},
|
||||
)
|
||||
modelScope.launch {
|
||||
toggleTokenListGroupingUseCase(list).fold(
|
||||
ifLeft = stateHolder::updateStateWithError,
|
||||
ifRight = {
|
||||
stateHolder.updateStateAfterTokenListSorting(it)
|
||||
cachedTokenList = it
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onApplyClick() {
|
||||
modelScope.launch {
|
||||
stateHolder.updateStateToDisplayProgress()
|
||||
|
||||
val listState = uiState.value.itemsState
|
||||
val resolver = CryptoCurrenciesIdsResolver()
|
||||
|
||||
val isGroupedByNetwork = listState is OrganizeTokensListState.GroupedByNetwork
|
||||
val isSortedByBalance = uiState.value.header.isSortedByBalance
|
||||
|
||||
sendAnalyticsEvent(
|
||||
isGroupedByNetwork = isGroupedByNetwork,
|
||||
isSortedByBalance = isSortedByBalance,
|
||||
)
|
||||
val result = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
val tokensListUM = uiState.value.tokenListUM
|
||||
|
||||
val result = applyTokenListSortingUseCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = resolver.resolve(listState, cachedTokenList),
|
||||
isGroupedByNetwork = isGroupedByNetwork,
|
||||
isSortedByBalance = isSortedByBalance,
|
||||
)
|
||||
val isGroupedByNetwork = tokensListUM.isGrouped
|
||||
|
||||
sendAnalyticsEvent(
|
||||
isGroupedByNetwork = isGroupedByNetwork,
|
||||
isSortedByBalance = isSortedByBalance,
|
||||
)
|
||||
|
||||
// val sorted = resolver.resolveV2(tokensListUM, cachedAccountStatusList)
|
||||
TODO("Implement account token list sorting")
|
||||
} else {
|
||||
val listState = uiState.value.itemsState
|
||||
|
||||
val isGroupedByNetwork = listState is OrganizeTokensListState.GroupedByNetwork
|
||||
|
||||
sendAnalyticsEvent(
|
||||
isGroupedByNetwork = isGroupedByNetwork,
|
||||
isSortedByBalance = isSortedByBalance,
|
||||
)
|
||||
|
||||
applyTokenListSortingUseCase(
|
||||
userWalletId = userWalletId,
|
||||
sortedTokensIds = resolver.resolve(listState, cachedTokenList),
|
||||
isGroupedByNetwork = isGroupedByNetwork,
|
||||
isSortedByBalance = isSortedByBalance,
|
||||
)
|
||||
}
|
||||
|
||||
result.fold(
|
||||
ifLeft = stateHolder::updateStateWithError,
|
||||
|
|
@ -161,10 +210,24 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
|
||||
private fun bootstrapTokenList() {
|
||||
modelScope.launch {
|
||||
val tokenList = getTokenList() ?: return@launch
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
val accountList = singleAccountStatusListSupplier.getSyncOrNull(
|
||||
SingleAccountStatusListProducer.Params(userWalletId),
|
||||
) ?: return@launch
|
||||
|
||||
stateHolder.updateStateWithTokenList(tokenList)
|
||||
cachedTokenList = tokenList
|
||||
val isAccountsModeEnabled = isAccountsModeEnabledUseCase.invokeSync()
|
||||
|
||||
stateHolder.updateStateWithAccountList(
|
||||
accountStatusList = accountList,
|
||||
isAccountsModeEnabled = isAccountsModeEnabled,
|
||||
)
|
||||
|
||||
cachedAccountStatusList = accountList
|
||||
} else {
|
||||
val tokenList = getTokenList() ?: return@launch
|
||||
stateHolder.updateStateWithTokenList(tokenList)
|
||||
cachedTokenList = tokenList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,14 +243,25 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun bootstrapDragAndDropUpdates() {
|
||||
dragAndDropAdapter.dragAndDropUpdates
|
||||
.distinctUntilChanged()
|
||||
.onEach { (type, updatedListState) ->
|
||||
disableSortingByBalanceIfListChanged(type)
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
dragAndDropAdapterV2.dragAndDropUpdates
|
||||
.distinctUntilChanged()
|
||||
.onEach { (type, updatedListState) ->
|
||||
disableSortingByBalanceIfListChangedV2(type)
|
||||
|
||||
stateHolder.updateStateWithManualSorting(updatedListState)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
stateHolder.updateStateWithManualSortingV2(updatedListState)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
} else {
|
||||
dragAndDropAdapter.dragAndDropUpdates
|
||||
.distinctUntilChanged()
|
||||
.onEach { (type, updatedListState) ->
|
||||
disableSortingByBalanceIfListChanged(type)
|
||||
|
||||
stateHolder.updateStateWithManualSorting(updatedListState)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun disableSortingByBalanceIfListChanged(dragOperationType: DragAndDropAdapter.DragOperation.Type) {
|
||||
|
|
@ -199,6 +273,15 @@ internal class OrganizeTokensModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun disableSortingByBalanceIfListChangedV2(dragOperationType: DragAndDropAdapterV2.DragOperation.Type) {
|
||||
if (dragOperationType !is DragAndDropAdapterV2.DragOperation.Type.End) return
|
||||
|
||||
if (uiState.value.header.isSortedByBalance && dragOperationType.isItemsOrderChanged) {
|
||||
cachedAccountStatusList = cachedAccountStatusList?.copy(sortType = TokensSortType.NONE)
|
||||
stateHolder.disableSortingByBalance()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { maybeAppCurrency ->
|
||||
|
|
|
|||
|
|
@ -8,15 +8,13 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.ActionsBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenActionButtonConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletBottomSheetConfig
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
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.OrganizeTokensListUM
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
|
@ -88,7 +86,7 @@ internal object WalletPreviewData {
|
|||
|
||||
private const val networksSize = 10
|
||||
private const val tokensSize = 3
|
||||
private val draggableItems by lazy {
|
||||
private val draggableItems: PersistentList<DraggableItem> by lazy {
|
||||
List(networksSize) { it }
|
||||
.flatMap { index ->
|
||||
val lastNetworkIndex = networksSize - 1
|
||||
|
|
@ -98,11 +96,13 @@ internal object WalletPreviewData {
|
|||
val group = DraggableItem.GroupHeader(
|
||||
id = networkNumber,
|
||||
networkName = "$networkNumber",
|
||||
|
||||
roundingMode = when (index) {
|
||||
0 -> DraggableItem.RoundingMode.Top()
|
||||
lastNetworkIndex -> DraggableItem.RoundingMode.Bottom()
|
||||
else -> DraggableItem.RoundingMode.None
|
||||
},
|
||||
accountId = "account_$networkNumber",
|
||||
)
|
||||
|
||||
val tokens: MutableList<DraggableItem.Token> = mutableListOf()
|
||||
|
|
@ -117,6 +117,7 @@ internal object WalletPreviewData {
|
|||
),
|
||||
),
|
||||
groupId = group.id,
|
||||
accountId = "account_$networkNumber",
|
||||
roundingMode = when {
|
||||
i == lastTokenIndex && index == lastNetworkIndex -> DraggableItem.RoundingMode.Bottom()
|
||||
else -> DraggableItem.RoundingMode.None
|
||||
|
|
@ -125,7 +126,10 @@ internal object WalletPreviewData {
|
|||
)
|
||||
}
|
||||
|
||||
val divider = DraggableItem.Placeholder(id = "divider_$networkNumber")
|
||||
val divider = DraggableItem.Placeholder(
|
||||
id = "divider_$networkNumber",
|
||||
accountId = "account_$networkNumber",
|
||||
)
|
||||
|
||||
buildList {
|
||||
add(group)
|
||||
|
|
@ -154,6 +158,7 @@ internal object WalletPreviewData {
|
|||
itemsState = OrganizeTokensListState.GroupedByNetwork(
|
||||
items = draggableItems,
|
||||
),
|
||||
tokenListUM = OrganizeTokensListUM.EmptyList,
|
||||
header = OrganizeTokensState.HeaderConfig(
|
||||
onSortClick = {},
|
||||
onGroupClick = {},
|
||||
|
|
|
|||
|
|
@ -33,6 +33,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.ExpandedPortfolioHeader
|
||||
import com.tangem.core.ui.components.tokenlist.internal.DraggableGroupTitleItem
|
||||
import com.tangem.core.ui.event.EventEffect
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -47,6 +48,7 @@ import com.tangem.feature.wallet.impl.R
|
|||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
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.OrganizeTokensListUM
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
|
||||
import org.burnoutcrew.reorderable.ReorderableLazyListState
|
||||
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
||||
|
|
@ -73,6 +75,7 @@ internal fun OrganizeTokensScreen(state: OrganizeTokensState, modifier: Modifier
|
|||
.padding(paddingValues)
|
||||
.fillMaxSize(),
|
||||
listState = tokensListState,
|
||||
tokensListUM = state.tokenListUM,
|
||||
state = state.itemsState,
|
||||
dndConfig = state.dndConfig,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
|
|
@ -96,11 +99,17 @@ internal fun OrganizeTokensScreen(state: OrganizeTokensState, modifier: Modifier
|
|||
private fun TokenList(
|
||||
listState: LazyListState,
|
||||
state: OrganizeTokensListState,
|
||||
tokensListUM: OrganizeTokensListUM,
|
||||
dndConfig: OrganizeTokensState.DragAndDropConfig,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
val tokenList = if (tokensListUM !is OrganizeTokensListUM.EmptyList) {
|
||||
tokensListUM.items
|
||||
} else {
|
||||
state.items
|
||||
}
|
||||
Box(modifier = modifier) {
|
||||
val onDragEnd: (Int, Int) -> Unit = remember {
|
||||
{ _, _ ->
|
||||
|
|
@ -127,7 +136,7 @@ private fun TokenList(
|
|||
// because sometimes items disappear after reordering in 1.7.4+ compose-runtime version
|
||||
// check removing after update to compose-runtime 1.8.0+
|
||||
val forceRecompose = remember { mutableIntStateOf(0) }
|
||||
LaunchedEffect(state.items) {
|
||||
LaunchedEffect(tokenList) {
|
||||
forceRecompose.intValue++
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +149,7 @@ private fun TokenList(
|
|||
contentPadding = listContentPadding,
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = state.items,
|
||||
items = tokenList,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
|
||||
|
|
@ -206,6 +215,13 @@ private fun LazyItemScope.DraggableItem(
|
|||
)
|
||||
// Should be presented in the list but remain invisible
|
||||
is DraggableItem.Placeholder -> Box(modifier = Modifier.fillMaxWidth())
|
||||
is DraggableItem.Portfolio -> ExpandedPortfolioHeader(
|
||||
state = item.tokenItemState,
|
||||
isCollapsable = false,
|
||||
modifier = modifierWithBackground
|
||||
.padding(top = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,19 +2,24 @@ package com.tangem.feature.wallet.presentation.organizetokens
|
|||
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.error.TokenListSortingError
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
|
||||
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.TokenListToStateConverterV2
|
||||
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 com.tangem.feature.wallet.presentation.organizetokens.utils.dnd.DragAndDropAdapterV2
|
||||
import com.tangem.utils.Provider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
|
@ -23,7 +28,9 @@ import kotlinx.coroutines.flow.update
|
|||
internal class OrganizeTokensStateHolder(
|
||||
private val intents: OrganizeTokensIntents,
|
||||
private val dragAndDropIntents: DragAndDropIntents,
|
||||
private val dragAndDropAdapterV2: DragAndDropAdapterV2,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
) {
|
||||
|
||||
private val stateFlowInternal: MutableStateFlow<OrganizeTokensState> = MutableStateFlow(getInitialState())
|
||||
|
|
@ -54,6 +61,16 @@ internal class OrganizeTokensStateHolder(
|
|||
updateState { tokenListConverter.convert(tokenList) }
|
||||
}
|
||||
|
||||
fun updateStateWithAccountList(accountStatusList: AccountStatusList, isAccountsModeEnabled: Boolean) {
|
||||
updateState {
|
||||
TokenListToStateConverterV2(
|
||||
accountStatusList = accountStatusList,
|
||||
isAccountsMode = isAccountsModeEnabled,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
).transform(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateStateAfterTokenListSorting(tokenList: TokenList) {
|
||||
updateState {
|
||||
tokenListConverter.convert(tokenList).copy(
|
||||
|
|
@ -70,6 +87,10 @@ internal class OrganizeTokensStateHolder(
|
|||
updateState { inProgressStateConverter.convertBack(value = this) }
|
||||
}
|
||||
|
||||
fun updateStateWithManualSortingV2(tokenListUM: OrganizeTokensListUM) {
|
||||
updateState { copy(tokenListUM = tokenListUM) }
|
||||
}
|
||||
|
||||
fun updateStateWithManualSorting(itemsState: OrganizeTokensListState) {
|
||||
updateState { copy(itemsState = itemsState) }
|
||||
}
|
||||
|
|
@ -94,6 +115,7 @@ internal class OrganizeTokensStateHolder(
|
|||
return OrganizeTokensState(
|
||||
onBackClick = intents::onBackClick,
|
||||
itemsState = OrganizeTokensListState.Empty,
|
||||
tokenListUM = OrganizeTokensListUM.EmptyList,
|
||||
header = OrganizeTokensState.HeaderConfig(
|
||||
onSortClick = intents::onSortClick,
|
||||
onGroupClick = intents::onGroupClick,
|
||||
|
|
@ -102,12 +124,21 @@ internal class OrganizeTokensStateHolder(
|
|||
onApplyClick = intents::onApplyClick,
|
||||
onCancelClick = intents::onCancelClick,
|
||||
),
|
||||
dndConfig = OrganizeTokensState.DragAndDropConfig(
|
||||
onItemDragged = dragAndDropIntents::onItemDragged,
|
||||
onItemDragStart = dragAndDropIntents::onItemDraggingStart,
|
||||
onItemDragEnd = dragAndDropIntents::onItemDraggingEnd,
|
||||
canDragItemOver = dragAndDropIntents::canDragItemOver,
|
||||
),
|
||||
dndConfig = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
OrganizeTokensState.DragAndDropConfig(
|
||||
onItemDragged = dragAndDropAdapterV2::onItemDragged,
|
||||
onItemDragStart = dragAndDropAdapterV2::onItemDraggingStart,
|
||||
onItemDragEnd = dragAndDropAdapterV2::onItemDraggingEnd,
|
||||
canDragItemOver = dragAndDropAdapterV2::canDragItemOver,
|
||||
)
|
||||
} else {
|
||||
OrganizeTokensState.DragAndDropConfig(
|
||||
onItemDragged = dragAndDropIntents::onItemDragged,
|
||||
onItemDragStart = dragAndDropIntents::onItemDraggingStart,
|
||||
onItemDragEnd = dragAndDropIntents::onItemDraggingEnd,
|
||||
canDragItemOver = dragAndDropIntents::canDragItemOver,
|
||||
)
|
||||
},
|
||||
scrollListToTop = consumedEvent(),
|
||||
isBalanceHidden = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem.RoundingMode
|
||||
|
||||
/**
|
||||
* Helper class for the DND list items
|
||||
|
|
@ -26,12 +25,14 @@ internal sealed class DraggableItem {
|
|||
*
|
||||
* @property id ID of the network group
|
||||
* @property networkName network group name
|
||||
* @property accountId account id
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
data class GroupHeader(
|
||||
override val id: Int,
|
||||
val networkName: String,
|
||||
val accountId: String = "",
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
override val showShadow: Boolean = false,
|
||||
) : DraggableItem() {
|
||||
|
|
@ -50,6 +51,7 @@ internal sealed class DraggableItem {
|
|||
*
|
||||
* @property tokenItemState state of the token item
|
||||
* @property groupId ID of the network group which contains this token
|
||||
* @property accountId account id
|
||||
* @property id ID of the token
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
|
|
@ -57,6 +59,7 @@ internal sealed class DraggableItem {
|
|||
data class Token(
|
||||
val tokenItemState: TokenItemState.Draggable,
|
||||
val groupId: Int,
|
||||
val accountId: String = "",
|
||||
override val showShadow: Boolean = false,
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
) : DraggableItem() {
|
||||
|
|
@ -67,14 +70,32 @@ internal sealed class DraggableItem {
|
|||
* Helper item used to detect possible positions where a draggable item can be placed.
|
||||
*
|
||||
* @property id ID of the placeholder
|
||||
* @property accountId account id
|
||||
* */
|
||||
data class Placeholder(
|
||||
override val id: String,
|
||||
val accountId: String = "",
|
||||
) : DraggableItem() {
|
||||
override val showShadow: Boolean = false
|
||||
override val roundingMode: RoundingMode = RoundingMode.None
|
||||
}
|
||||
|
||||
/**
|
||||
* Item for portfolio.
|
||||
*
|
||||
* @property tokenItemState state of the portfolio item
|
||||
* @property id ID of the portfolio
|
||||
* @property roundingMode item [RoundingMode]
|
||||
* @property showShadow if true then item should be elevated
|
||||
* */
|
||||
data class Portfolio(
|
||||
override val roundingMode: RoundingMode = RoundingMode.None,
|
||||
val tokenItemState: TokenItemState,
|
||||
) : DraggableItem() {
|
||||
override val id: String = tokenItemState.id
|
||||
override val showShadow: Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounding mode of the [DraggableItem]
|
||||
*
|
||||
|
|
@ -122,6 +143,7 @@ internal sealed class DraggableItem {
|
|||
* */
|
||||
fun updateRoundingMode(mode: RoundingMode): DraggableItem = when (this) {
|
||||
is Placeholder -> this
|
||||
is Portfolio -> this.copy(roundingMode = mode)
|
||||
is GroupHeader -> this.copy(roundingMode = mode)
|
||||
is Token -> this.copy(roundingMode = mode)
|
||||
}
|
||||
|
|
@ -134,7 +156,9 @@ internal sealed class DraggableItem {
|
|||
* @return updated [DraggableItem]
|
||||
* */
|
||||
fun updateShadowVisibility(show: Boolean): DraggableItem = when (this) {
|
||||
is Placeholder -> this
|
||||
is Portfolio,
|
||||
is Placeholder,
|
||||
-> this
|
||||
is GroupHeader -> this.copy(showShadow = show)
|
||||
is Token -> this.copy(showShadow = show)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable
|
|||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Deprecated("Use OrganizeTokensListUM instead, will be removed in future releases")
|
||||
@Immutable
|
||||
internal sealed class OrganizeTokensListState {
|
||||
abstract val items: PersistentList<DraggableItem>
|
||||
|
|
@ -19,4 +20,26 @@ internal sealed class OrganizeTokensListState {
|
|||
data object Empty : OrganizeTokensListState() {
|
||||
override val items: PersistentList<DraggableItem> = persistentListOf()
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed interface OrganizeTokensListUM {
|
||||
|
||||
val items: PersistentList<DraggableItem>
|
||||
val isGrouped: Boolean
|
||||
|
||||
data class AccountList(
|
||||
override val items: PersistentList<DraggableItem>,
|
||||
override val isGrouped: Boolean,
|
||||
) : OrganizeTokensListUM
|
||||
|
||||
data class TokensList(
|
||||
override val items: PersistentList<DraggableItem>,
|
||||
override val isGrouped: Boolean,
|
||||
) : OrganizeTokensListUM
|
||||
|
||||
data object EmptyList : OrganizeTokensListUM {
|
||||
override val items: PersistentList<DraggableItem> = persistentListOf()
|
||||
override val isGrouped: Boolean = false
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import org.burnoutcrew.reorderable.ItemPosition
|
|||
internal data class OrganizeTokensState(
|
||||
val onBackClick: () -> Unit,
|
||||
val itemsState: OrganizeTokensListState,
|
||||
val tokenListUM: OrganizeTokensListUM,
|
||||
val header: HeaderConfig,
|
||||
val actions: ActionsConfig,
|
||||
val dndConfig: DragAndDropConfig,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
|||
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
|
||||
|
||||
internal fun getGroupPlaceholder(index: Int): DraggableItem.Placeholder {
|
||||
return DraggableItem.Placeholder(id = "placeholder_${index.inc()}")
|
||||
internal fun getGroupPlaceholder(index: Int, accountId: String = ""): DraggableItem.Placeholder {
|
||||
return DraggableItem.Placeholder(
|
||||
id = "placeholder_${accountId}_${index.inc()}",
|
||||
accountId = accountId,
|
||||
)
|
||||
}
|
||||
|
|
@ -12,7 +12,9 @@ internal fun List<DraggableItem>.uniteItems(): List<DraggableItem> {
|
|||
1 -> DraggableItem.RoundingMode.Top()
|
||||
lastItemIndex -> DraggableItem.RoundingMode.Bottom()
|
||||
else -> when (item) {
|
||||
is DraggableItem.Placeholder -> DraggableItem.RoundingMode.None
|
||||
is DraggableItem.Portfolio,
|
||||
is DraggableItem.Placeholder,
|
||||
-> DraggableItem.RoundingMode.None
|
||||
is DraggableItem.GroupHeader -> DraggableItem.RoundingMode.Top(showGap = true)
|
||||
is DraggableItem.Token -> if (items[index + 1] is DraggableItem.Placeholder) {
|
||||
DraggableItem.RoundingMode.Bottom(showGap = true)
|
||||
|
|
@ -28,6 +30,48 @@ internal fun List<DraggableItem>.uniteItems(): List<DraggableItem> {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun List<DraggableItem>.uniteItemsV2(isAccountsMode: Boolean): List<DraggableItem> {
|
||||
val items = this
|
||||
val lastItemIndex = items.lastIndex
|
||||
|
||||
return items
|
||||
.asSequence()
|
||||
.mapIndexed { index, item ->
|
||||
val mode = when (index) {
|
||||
0 -> if (item is DraggableItem.Placeholder) {
|
||||
DraggableItem.RoundingMode.None
|
||||
} else {
|
||||
DraggableItem.RoundingMode.Top()
|
||||
}
|
||||
lastItemIndex -> DraggableItem.RoundingMode.Bottom()
|
||||
1 -> if (items.first() is DraggableItem.Placeholder) {
|
||||
DraggableItem.RoundingMode.Top()
|
||||
} else {
|
||||
DraggableItem.RoundingMode.None
|
||||
}
|
||||
else -> when (item) {
|
||||
is DraggableItem.Placeholder -> DraggableItem.RoundingMode.None
|
||||
is DraggableItem.GroupHeader -> if (isAccountsMode) {
|
||||
DraggableItem.RoundingMode.None
|
||||
} else {
|
||||
DraggableItem.RoundingMode.Top(showGap = true)
|
||||
}
|
||||
is DraggableItem.Token -> applyRoundingModeToToken(
|
||||
isAccountsMode = isAccountsMode,
|
||||
items = items,
|
||||
index = index,
|
||||
lastItemIndex = lastItemIndex,
|
||||
)
|
||||
is DraggableItem.Portfolio -> DraggableItem.RoundingMode.Top(showGap = true)
|
||||
}
|
||||
}
|
||||
|
||||
item
|
||||
.updateRoundingMode(mode)
|
||||
.updateShadowVisibility(show = false)
|
||||
}.toList()
|
||||
}
|
||||
|
||||
internal fun List<DraggableItem>.divideMovingItem(movingItem: DraggableItem): List<DraggableItem> {
|
||||
val mutableList = this.toMutableList()
|
||||
val listIterator = mutableList.listIterator()
|
||||
|
|
@ -63,12 +107,55 @@ private fun List<DraggableItem>.prepareItems(): List<DraggableItem> {
|
|||
return mutableListOf<DraggableItem>().apply {
|
||||
add(DraggableItem.Placeholder(firstPlaceholderId))
|
||||
|
||||
val itemsWithoutFirstPlaceholder = if (items.firstOrNull()?.id == firstPlaceholderId) {
|
||||
items.drop(n = 1)
|
||||
} else {
|
||||
items
|
||||
}
|
||||
val itemsWithoutFirstPlaceholder = items.filterNot { it.id == firstPlaceholderId }
|
||||
|
||||
addAll(itemsWithoutFirstPlaceholder)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applying rounding to tokens
|
||||
*
|
||||
* If is in accounts mode without grouping
|
||||
* * PORTFOLIO
|
||||
* * TOKEN
|
||||
* * TOKEN <- add rounding
|
||||
* * PORTFOLIO index + 1 is PORTFOLIO
|
||||
*
|
||||
* If is in accounts mode with grouping
|
||||
* * PORTFOLIO
|
||||
* * PLACEHOLDER
|
||||
* * GROUPING
|
||||
* * TOKEN
|
||||
* * TOKEN <- add rounding
|
||||
* * PLACEHOLDER index + 1 is PLACEHOLDER
|
||||
* * PORTFOLIO index + 2 is PORTFOLIO
|
||||
* * PLACEHOLDER
|
||||
*
|
||||
* If is not accounts mode without grouping
|
||||
* * TOKEN
|
||||
* * TOKEN <- add rounding
|
||||
*
|
||||
* If is not accounts mode with grouping
|
||||
* * PLACEHOLDER
|
||||
* * GROUPING
|
||||
* * TOKEN
|
||||
* * TOKEN <- add rounding
|
||||
* * PLACEHOLDER index + 1 is PLACEHOLDER
|
||||
*/
|
||||
private fun applyRoundingModeToToken(
|
||||
isAccountsMode: Boolean,
|
||||
items: List<DraggableItem>,
|
||||
index: Int,
|
||||
lastItemIndex: Int,
|
||||
) = when {
|
||||
isAccountsMode && index + 1 < lastItemIndex &&
|
||||
(items[index + 1] is DraggableItem.Portfolio ||
|
||||
items[index + 1] is DraggableItem.Placeholder && items[index + 2] is DraggableItem.Portfolio) -> {
|
||||
DraggableItem.RoundingMode.Bottom(showGap = true)
|
||||
}
|
||||
(!isAccountsMode || index + 1 == lastItemIndex) && items[index + 1] is DraggableItem.Placeholder -> {
|
||||
DraggableItem.RoundingMode.Bottom(showGap = true)
|
||||
}
|
||||
else -> DraggableItem.RoundingMode.None
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.organizetokens.utils.common
|
|||
|
||||
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.OrganizeTokensListUM
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
|
|
@ -15,4 +16,16 @@ internal inline fun OrganizeTokensListState.updateItems(
|
|||
is OrganizeTokensListState.Ungrouped -> copy(items = updatedItems)
|
||||
is OrganizeTokensListState.Empty -> this
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun OrganizeTokensListUM.updateItems(
|
||||
update: (PersistentList<DraggableItem>) -> List<DraggableItem>,
|
||||
): OrganizeTokensListUM {
|
||||
val updatedItems = update(items).toPersistentList()
|
||||
|
||||
return when (this) {
|
||||
is OrganizeTokensListUM.AccountList -> copy(items = updatedItems)
|
||||
is OrganizeTokensListUM.TokensList -> copy(items = updatedItems)
|
||||
OrganizeTokensListUM.EmptyList -> this
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter
|
||||
|
||||
import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupPlaceholder
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.uniteItemsV2
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.OrganizedTokenListConverter
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class TokenListToStateConverterV2(
|
||||
private val accountStatusList: AccountStatusList,
|
||||
private val isAccountsMode: Boolean,
|
||||
private val appCurrency: AppCurrency,
|
||||
) : Transformer<OrganizeTokensState> {
|
||||
|
||||
private val accountListItemConverter by lazy {
|
||||
AccountTokenItemConverter(appCurrency = appCurrency, isAccountsMode)
|
||||
}
|
||||
|
||||
override fun transform(prevState: OrganizeTokensState): OrganizeTokensState {
|
||||
val tokenListUM = accountListItemConverter.convert(accountStatusList)
|
||||
|
||||
return prevState.copy(
|
||||
tokenListUM = tokenListUM,
|
||||
header = prevState.header.copy(
|
||||
isEnabled = tokenListUM !is OrganizeTokensListUM.EmptyList,
|
||||
isSortedByBalance = accountStatusList.sortType == TokensSortType.BALANCE,
|
||||
isGrouped = accountStatusList.groupType == TokensGroupType.NETWORK,
|
||||
),
|
||||
actions = prevState.actions.copy(
|
||||
canApply = tokenListUM !is OrganizeTokensListUM.EmptyList,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class AccountTokenItemConverter(
|
||||
private val appCurrency: AppCurrency,
|
||||
private val isAccountsMode: Boolean,
|
||||
) : Converter<AccountStatusList, OrganizeTokensListUM> {
|
||||
|
||||
private val organizedTokenListConverter by lazy {
|
||||
OrganizedTokenListConverter(appCurrency)
|
||||
}
|
||||
|
||||
override fun convert(value: AccountStatusList): OrganizeTokensListUM {
|
||||
val isGrouping = value.groupType == TokensGroupType.NETWORK
|
||||
return if (isAccountsMode) {
|
||||
OrganizeTokensListUM.AccountList(
|
||||
isGrouped = isGrouping,
|
||||
items = value.accountStatuses
|
||||
.asSequence()
|
||||
.filterIsInstance<AccountStatus.CryptoPortfolio>()
|
||||
.flatMap { accountStatus ->
|
||||
if (accountStatus.tokenList != TokenList.Empty) {
|
||||
buildList {
|
||||
add(
|
||||
DraggableItem.Portfolio(
|
||||
tokenItemState = AccountCryptoPortfolioItemStateConverter(
|
||||
appCurrency = appCurrency,
|
||||
account = accountStatus.account,
|
||||
).convert(TotalFiatBalance.Loading),
|
||||
),
|
||||
)
|
||||
if (isGrouping) {
|
||||
add(getGroupPlaceholder(accountId = accountStatus.accountId.value, index = -1))
|
||||
}
|
||||
addAll(organizedTokenListConverter.convert(accountStatus))
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}.toList()
|
||||
.uniteItemsV2(true).toPersistentList(),
|
||||
)
|
||||
} else {
|
||||
OrganizeTokensListUM.TokensList(
|
||||
isGrouped = isGrouping,
|
||||
items = buildList {
|
||||
if (isGrouping) {
|
||||
add(getGroupPlaceholder(accountId = value.mainAccount.accountId.value, index = -1))
|
||||
}
|
||||
addAll(organizedTokenListConverter.convert(value.mainAccount))
|
||||
}.uniteItemsV2(false)
|
||||
.toPersistentList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
|
||||
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.BigDecimalFormatConstants
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.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
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class CryptoCurrencyToDraggableItemConverterV2(
|
||||
private val appCurrency: AppCurrency,
|
||||
) : Converter<AccountCryptoCurrencyStatus, DraggableItem.Token> {
|
||||
|
||||
private val iconStateConverter = CryptoCurrencyToIconStateConverter()
|
||||
|
||||
override fun convert(value: AccountCryptoCurrencyStatus): DraggableItem.Token {
|
||||
return createDraggableToken(value)
|
||||
}
|
||||
|
||||
private fun createDraggableToken(accountCryptoCurrencyStatus: AccountCryptoCurrencyStatus): DraggableItem.Token {
|
||||
val (account, currencyStatus) = accountCryptoCurrencyStatus
|
||||
return DraggableItem.Token(
|
||||
tokenItemState = createTokenItemState(currencyStatus, appCurrency),
|
||||
groupId = getGroupHeaderId(currencyStatus.currency.network),
|
||||
accountId = account.accountId.value,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createTokenItemState(
|
||||
currencyStatus: CryptoCurrencyStatus,
|
||||
appCurrency: AppCurrency,
|
||||
): TokenItemState.Draggable {
|
||||
val currency = currencyStatus.currency
|
||||
|
||||
return TokenItemState.Draggable(
|
||||
id = getTokenItemId(currency.id),
|
||||
iconState = iconStateConverter.convert(currencyStatus),
|
||||
titleState = TokenItemState.TitleState.Content(text = stringReference(currency.name)),
|
||||
subtitle2State = if (currencyStatus.value.isError) {
|
||||
TokenItemState.Subtitle2State.Unreachable
|
||||
} else {
|
||||
TokenItemState.Subtitle2State.TextContent(text = getFormattedFiatAmount(currencyStatus, appCurrency))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFormattedFiatAmount(currency: CryptoCurrencyStatus, appCurrency: AppCurrency): String {
|
||||
val yieldBalance = currency.value.yieldBalance as? YieldBalance.Data
|
||||
val fiatRate = currency.value.fiatRate ?: BigDecimal.ZERO
|
||||
val fiatYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance(currency.currency.network.rawId)
|
||||
?.multiply(fiatRate).orZero()
|
||||
|
||||
val fiatAmount = currency.value.fiatAmount ?: return BigDecimalFormatConstants.EMPTY_BALANCE_SIGN
|
||||
return (fiatAmount + fiatYieldBalance).format { fiat(appCurrency.code, appCurrency.symbol) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
|
||||
|
||||
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.tokenlist.TokenList.GroupedByNetwork.NetworkGroup
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.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 NetworkGroupToDraggableItemsConverterV2(
|
||||
private val itemConverter: CryptoCurrencyToDraggableItemConverterV2,
|
||||
) : Converter<Pair<Account.CryptoPortfolio, NetworkGroup>, List<DraggableItem>> {
|
||||
|
||||
override fun convert(value: Pair<Account.CryptoPortfolio, NetworkGroup>): List<DraggableItem> {
|
||||
val (account, networkGroup) = value
|
||||
return buildList {
|
||||
add(createGroupHeader(account.accountId, networkGroup))
|
||||
addAll(createTokens(account, networkGroup))
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertList(
|
||||
input: Collection<Pair<Account.CryptoPortfolio, NetworkGroup>>,
|
||||
): List<List<DraggableItem>> {
|
||||
return input.mapIndexed { index, pair ->
|
||||
convert(pair).toMutableList()
|
||||
.also { mutableGroup ->
|
||||
mutableGroup.add(
|
||||
getGroupPlaceholder(accountId = pair.first.accountId.value, index = index),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createGroupHeader(accountId: AccountId, group: NetworkGroup) = DraggableItem.GroupHeader(
|
||||
id = getGroupHeaderId(group.network),
|
||||
accountId = accountId.value,
|
||||
networkName = group.network.name,
|
||||
)
|
||||
|
||||
private fun createTokens(account: Account.CryptoPortfolio, group: NetworkGroup): List<DraggableItem.Token> {
|
||||
return itemConverter.convertList(
|
||||
group.currencies.map {
|
||||
AccountCryptoCurrencyStatus(
|
||||
account = account,
|
||||
status = it,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
|
||||
|
||||
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.tokenlist.TokenList
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class OrganizedTokenListConverter(
|
||||
private val appCurrency: AppCurrency,
|
||||
) : Converter<AccountStatus, PersistentList<DraggableItem>> {
|
||||
|
||||
private val tokensConverter by lazy { CryptoCurrencyToDraggableItemConverterV2(appCurrency) }
|
||||
private val groupsConverter by lazy {
|
||||
NetworkGroupToDraggableItemsConverterV2(tokensConverter)
|
||||
}
|
||||
|
||||
override fun convert(value: AccountStatus): PersistentList<DraggableItem> {
|
||||
val cryptoAccount = value.account as? Account.CryptoPortfolio ?: return persistentListOf()
|
||||
return when (val tokenList = value.getCryptoTokenList()) {
|
||||
is TokenList.GroupedByNetwork -> groupsConverter.convertList(
|
||||
tokenList.groups.map { cryptoAccount to it },
|
||||
)
|
||||
.flatten()
|
||||
.toPersistentList()
|
||||
|
||||
is TokenList.Ungrouped -> tokensConverter.convertList(
|
||||
value.flattenCurrencies().map {
|
||||
AccountCryptoCurrencyStatus(
|
||||
account = cryptoAccount,
|
||||
status = it,
|
||||
)
|
||||
},
|
||||
).toPersistentList()
|
||||
|
||||
is TokenList.Empty -> persistentListOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +51,9 @@ internal class DragAndDropAdapter(
|
|||
return when (draggingItem) {
|
||||
is DraggableItem.GroupHeader -> checkCanMoveHeaderOver(dragOver, dragOverItem, items.lastIndex)
|
||||
is DraggableItem.Token -> checkCanMoveTokenOver(draggingItem, dragOverItem)
|
||||
is DraggableItem.Placeholder -> false
|
||||
is DraggableItem.Placeholder,
|
||||
is DraggableItem.Portfolio,
|
||||
-> false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +63,9 @@ internal class DragAndDropAdapter(
|
|||
|
||||
updateListState(DragOperation.Type.Start) {
|
||||
when (item) {
|
||||
is DraggableItem.Placeholder -> items
|
||||
is DraggableItem.Placeholder,
|
||||
is DraggableItem.Portfolio,
|
||||
-> items
|
||||
is DraggableItem.GroupHeader -> draggableGroupsOperations.collapseGroup(items, item)
|
||||
is DraggableItem.Token -> when (this) {
|
||||
is OrganizeTokensListState.GroupedByNetwork -> items.divideMovingItem(item)
|
||||
|
|
@ -81,7 +85,9 @@ internal class DragAndDropAdapter(
|
|||
when (draggingItem) {
|
||||
is DraggableItem.GroupHeader -> draggableGroupsOperations.expandGroups(items)
|
||||
is DraggableItem.Token -> items.uniteItems()
|
||||
is DraggableItem.Placeholder -> items
|
||||
is DraggableItem.Placeholder,
|
||||
is DraggableItem.Portfolio,
|
||||
-> items
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +150,9 @@ internal class DragAndDropAdapter(
|
|||
return when (moveOverItem) {
|
||||
is DraggableItem.GroupHeader -> false // Token item can not be moved to group item
|
||||
is DraggableItem.Token -> item.groupId == moveOverItem.groupId // Token item can not be moved over its group
|
||||
is DraggableItem.Placeholder -> false
|
||||
is DraggableItem.Portfolio,
|
||||
is DraggableItem.Placeholder,
|
||||
-> false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
package com.tangem.feature.wallet.presentation.organizetokens.utils.dnd
|
||||
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.DragAndDropIntents
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.divideMovingItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.uniteItemsV2
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.updateItems
|
||||
import com.tangem.utils.Provider
|
||||
import kotlinx.collections.immutable.mutate
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
|
||||
internal class DragAndDropAdapterV2(
|
||||
private val tokenListUMProvider: Provider<OrganizeTokensListUM>,
|
||||
) : DragAndDropIntents {
|
||||
|
||||
private val tokenListUM: OrganizeTokensListUM
|
||||
get() = tokenListUMProvider.invoke()
|
||||
|
||||
private val draggableGroupsOperations = DraggableGroupsOperations()
|
||||
|
||||
private val dragAndDropUpdatesInternal: MutableStateFlow<DragOperation?> = MutableStateFlow(value = null)
|
||||
|
||||
private var draggingItem: DraggableItem? = null
|
||||
private var draggingListState: OrganizeTokensListUM? = null
|
||||
|
||||
val dragAndDropUpdates: Flow<DragOperation>
|
||||
get() = dragAndDropUpdatesInternal.filterNotNull()
|
||||
|
||||
override fun canDragItemOver(dragOver: ItemPosition, dragging: ItemPosition): Boolean {
|
||||
val items = when (val listState = tokenListUM) {
|
||||
is OrganizeTokensListUM.AccountList -> listState.items
|
||||
is OrganizeTokensListUM.TokensList -> {
|
||||
if (tokenListUM.isGrouped) {
|
||||
listState.items
|
||||
} else {
|
||||
return true // If ungrouped then item can be moved anywhere
|
||||
}
|
||||
}
|
||||
OrganizeTokensListUM.EmptyList -> return true
|
||||
}
|
||||
|
||||
val (dragOverItem, draggingItem) = findItemsToMove(
|
||||
items = items,
|
||||
moveOverItemKey = dragOver.key,
|
||||
movedItemKey = dragging.key,
|
||||
)
|
||||
|
||||
if (dragOverItem == null || draggingItem == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val canDrag = when (draggingItem) {
|
||||
is DraggableItem.GroupHeader -> checkCanMoveHeaderOver(
|
||||
item = draggingItem,
|
||||
moveOverItem = dragOverItem,
|
||||
)
|
||||
is DraggableItem.Token -> checkCanMoveTokenOver(
|
||||
item = draggingItem,
|
||||
moveOverItem = dragOverItem,
|
||||
isAccountsMode = tokenListUM is OrganizeTokensListUM.AccountList,
|
||||
isGrouped = tokenListUM.isGrouped,
|
||||
)
|
||||
is DraggableItem.Placeholder,
|
||||
is DraggableItem.Portfolio,
|
||||
-> false
|
||||
}
|
||||
|
||||
return canDrag
|
||||
}
|
||||
|
||||
override fun onItemDraggingStart(item: DraggableItem) {
|
||||
if (draggingItem != null) return
|
||||
draggingItem = item
|
||||
|
||||
updateListState(DragOperation.Type.Start) {
|
||||
when (item) {
|
||||
is DraggableItem.Placeholder,
|
||||
is DraggableItem.Portfolio,
|
||||
-> items
|
||||
is DraggableItem.GroupHeader -> draggableGroupsOperations.collapseGroupV2(items, item)
|
||||
.divideMovingItem(item)
|
||||
is DraggableItem.Token -> items.divideMovingItem(item)
|
||||
}
|
||||
}
|
||||
|
||||
draggingListState = tokenListUM
|
||||
}
|
||||
|
||||
override fun onItemDraggingEnd() {
|
||||
val draggingItem = draggingItem ?: return
|
||||
|
||||
updateListState(DragOperation.Type.End(isItemsOrderChanged = checkIsItemsOrderChanged())) {
|
||||
when (draggingItem) {
|
||||
is DraggableItem.GroupHeader -> {
|
||||
draggableGroupsOperations.expandGroupsV2(items)
|
||||
.uniteItemsV2(tokenListUM is OrganizeTokensListUM.AccountList)
|
||||
}
|
||||
is DraggableItem.Token -> {
|
||||
items.uniteItemsV2(tokenListUM is OrganizeTokensListUM.AccountList)
|
||||
}
|
||||
is DraggableItem.Placeholder,
|
||||
is DraggableItem.Portfolio,
|
||||
-> items
|
||||
}
|
||||
}
|
||||
|
||||
this.draggingItem = null
|
||||
}
|
||||
|
||||
override fun onItemDragged(from: ItemPosition, to: ItemPosition) {
|
||||
updateListState(DragOperation.Type.Dragged) {
|
||||
items.mutate {
|
||||
it.add(to.index, it.removeAt(from.index))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateListState(type: DragOperation.Type, block: OrganizeTokensListUM.() -> List<DraggableItem>) {
|
||||
val updatedState = tokenListUM.updateItems { block(tokenListUM) }
|
||||
|
||||
dragAndDropUpdatesInternal.value = DragOperation(type, updatedState)
|
||||
}
|
||||
|
||||
private fun findItemsToMove(
|
||||
items: List<DraggableItem>,
|
||||
moveOverItemKey: Any?,
|
||||
movedItemKey: Any?,
|
||||
): Pair<DraggableItem?, DraggableItem?> {
|
||||
var moveOverItem: DraggableItem? = null
|
||||
var movedItem: DraggableItem? = null
|
||||
|
||||
for (item in items) {
|
||||
if (item.id == moveOverItemKey) {
|
||||
moveOverItem = item
|
||||
}
|
||||
if (item.id == movedItemKey) {
|
||||
movedItem = item
|
||||
}
|
||||
if (moveOverItem != null && movedItem != null) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return Pair(moveOverItem, movedItem)
|
||||
}
|
||||
|
||||
private fun checkCanMoveHeaderOver(item: DraggableItem.GroupHeader, moveOverItem: DraggableItem): Boolean {
|
||||
return when (moveOverItem) {
|
||||
// Header can be moved only in its account
|
||||
is DraggableItem.Placeholder -> item.accountId == moveOverItem.accountId
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCanMoveTokenOver(
|
||||
item: DraggableItem.Token,
|
||||
moveOverItem: DraggableItem,
|
||||
isGrouped: Boolean,
|
||||
isAccountsMode: Boolean,
|
||||
): Boolean {
|
||||
return when (moveOverItem) {
|
||||
is DraggableItem.GroupHeader -> false // Token item can not be moved to group item
|
||||
is DraggableItem.Token -> when {
|
||||
// Token item can be moved only in its group
|
||||
isGrouped -> item.groupId == moveOverItem.groupId
|
||||
|
||||
// Token item can be moved only in its account
|
||||
isAccountsMode -> item.accountId == moveOverItem.accountId
|
||||
|
||||
// If ungrouped and not accounts mode then item can be moved anywhere
|
||||
else -> true
|
||||
}
|
||||
is DraggableItem.Portfolio,
|
||||
is DraggableItem.Placeholder,
|
||||
-> false // Token item can not be moved to portfolio or placeholder
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIsItemsOrderChanged(): Boolean {
|
||||
fun OrganizeTokensListUM?.getItemsIds(): List<Any>? = this?.items?.mapNotNull { item ->
|
||||
if (item is DraggableItem.Placeholder) {
|
||||
null
|
||||
} else {
|
||||
item.id
|
||||
}
|
||||
}
|
||||
|
||||
return tokenListUM.getItemsIds() != draggingListState.getItemsIds()
|
||||
}
|
||||
|
||||
data class DragOperation(
|
||||
val type: Type,
|
||||
val listState: OrganizeTokensListUM,
|
||||
) {
|
||||
|
||||
sealed class Type {
|
||||
|
||||
data object Start : Type()
|
||||
|
||||
data object Dragged : Type()
|
||||
|
||||
data class End(val isItemsOrderChanged: Boolean) : Type()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,21 @@ internal class DraggableGroupsOperations {
|
|||
return itemsWithoutGroupTokens.divideMovingItem(movingGroup)
|
||||
}
|
||||
|
||||
fun collapseGroupV2(items: List<DraggableItem>, movingGroup: DraggableItem.GroupHeader): List<DraggableItem> {
|
||||
if (!groupIdToTokens.isNullOrEmpty()) return items
|
||||
|
||||
groupIdToTokens = items
|
||||
.asSequence()
|
||||
.filterIsInstance<DraggableItem.Token>()
|
||||
.groupBy { it.groupId }
|
||||
|
||||
val itemsWithoutGroupTokens = items.filterNot {
|
||||
it is DraggableItem.Token && it.groupId == movingGroup.id
|
||||
}
|
||||
|
||||
return itemsWithoutGroupTokens.divideMovingItem(movingGroup)
|
||||
}
|
||||
|
||||
fun expandGroups(items: List<DraggableItem>): List<DraggableItem> {
|
||||
if (groupIdToTokens.isNullOrEmpty()) return items
|
||||
|
||||
|
|
@ -46,4 +61,49 @@ internal class DraggableGroupsOperations {
|
|||
|
||||
return expandedGroups
|
||||
}
|
||||
|
||||
fun expandGroupsV2(items: List<DraggableItem>): List<DraggableItem> {
|
||||
if (groupIdToTokens.isNullOrEmpty()) return items
|
||||
|
||||
val accountList = items.filterIsInstance<DraggableItem.Portfolio>()
|
||||
val currentGroups = items.filterIsInstance<DraggableItem.GroupHeader>()
|
||||
|
||||
val expandedGroups = if (items.any { it is DraggableItem.Portfolio }) {
|
||||
accountList
|
||||
.asSequence()
|
||||
.flatMap { account ->
|
||||
buildList {
|
||||
add(account)
|
||||
currentGroups
|
||||
.asSequence()
|
||||
.filter { it.accountId == account.id }
|
||||
.forEachIndexed { index, group ->
|
||||
if (index == 0) {
|
||||
add(getGroupPlaceholder(accountId = group.accountId, index = -1))
|
||||
}
|
||||
add(group)
|
||||
addAll(groupIdToTokens?.get(group.id).orEmpty())
|
||||
add(getGroupPlaceholder(accountId = group.accountId, index = index))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentGroups
|
||||
.asSequence()
|
||||
.flatMapIndexed { index, group ->
|
||||
buildList {
|
||||
if (index == 0) {
|
||||
add(getGroupPlaceholder(accountId = group.accountId, index = -1))
|
||||
}
|
||||
add(group)
|
||||
addAll(groupIdToTokens?.get(group.id).orEmpty())
|
||||
add(getGroupPlaceholder(accountId = group.accountId, index = index))
|
||||
}
|
||||
}
|
||||
}.toList()
|
||||
|
||||
groupIdToTokens = null
|
||||
|
||||
return expandedGroups
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM
|
|||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.account.models.AccountStatusList
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.PortfolioId
|
||||
|
|
@ -21,7 +22,6 @@ import com.tangem.domain.staking.model.stakekit.Yield
|
|||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
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.OrganizeTokensButtonConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
|
@ -82,8 +82,6 @@ internal class TokenListStateConverter(
|
|||
|
||||
private fun convertAccountList(params: TokenConverterParams.Account): WalletTokensListState {
|
||||
val accountList = params.accountList
|
||||
// todo account null for firs iteration?
|
||||
val organizeTokensButtonConfig: OrganizeTokensButtonConfig? = null
|
||||
|
||||
fun AccountStatus.CryptoPortfolio.map(): TokensListItemUM.Portfolio {
|
||||
val tokenList: TokenList = this.tokenList
|
||||
|
|
@ -128,7 +126,7 @@ internal class TokenListStateConverter(
|
|||
}
|
||||
return WalletTokensListState.ContentState.PortfolioContent(
|
||||
items = accountItems.toPersistentList(),
|
||||
organizeTokensButtonConfig = organizeTokensButtonConfig,
|
||||
organizeTokensButtonConfig = getOrganizeTokensButtonStateV2(accountList = accountList),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -193,6 +191,17 @@ internal class TokenListStateConverter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getOrganizeTokensButtonStateV2(accountList: AccountStatusList): WalletOrganizeTokensButtonConfig? {
|
||||
return if (accountList.flattenCurrencies().size > 1 && !isSingleCurrencyWalletWithToken()) {
|
||||
WalletOrganizeTokensButtonConfig(
|
||||
isEnabled = accountList.totalFiatBalance !is TotalFiatBalance.Loading,
|
||||
onClick = clickIntents::onOrganizeTokensClick,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSingleCurrencyWalletWithToken(): Boolean {
|
||||
return selectedWallet is UserWallet.Cold &&
|
||||
selectedWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue