Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-03 10:23:30 +03:00
parent 799a423f9f
commit ed94c73dcc
6 changed files with 85 additions and 40 deletions

View file

@ -308,10 +308,10 @@
<string name="onboarding_wallet_info_title_fourth">Восстановление кода доступа</string>
<string name="onboarding_wallet_info_title_second">Идентичные карты</string>
<string name="onboarding_wallet_info_title_third">Код доступа</string>
<string name="organize_tokens_group">Группировка</string>
<string name="organize_tokens_group">Группы</string>
<string name="organize_tokens_sort_by_balance">По балансу</string>
<string name="organize_tokens_title">Сортировка токенов</string>
<string name="organize_tokens_ungroup">Разгруппировать</string>
<string name="organize_tokens_ungroup">Список</string>
<string name="receive_bottom_sheet_title">%1$s %2$s адрес в сети %3$s</string>
<string name="receive_bottom_sheet_warning_message">%1$s (%2$s) в сети %3$s</string>
<string name="referral_button_participate">Участвовать</string>

View file

@ -244,7 +244,7 @@ private fun TopBar(
iconResId = R.drawable.ic_sort_24,
enabled = config.isEnabled,
onClick = config.onSortClick,
dimContent = !config.isSortedByBalance,
dimContent = config.isSortedByBalance,
),
modifier = Modifier.weight(1f),
color = TangemTheme.colors.background.primary,

View file

@ -73,12 +73,11 @@ internal class OrganizeTokensStateHolder(
}
fun updateStateWithManualSorting(itemsState: OrganizeTokensListState) {
updateState {
copy(
header = header.copy(isSortedByBalance = false),
itemsState = itemsState,
)
}
updateState { copy(itemsState = itemsState) }
}
fun disableSortingByBalance() {
updateState { copy(header = header.copy(isSortedByBalance = false)) }
}
fun updateStateWithError(error: TokenListError) {

View file

@ -77,11 +77,12 @@ internal class OrganizeTokensViewModel @Inject constructor(
}
override fun onSortClick() {
val list = tokenList ?: return
if (list.sortedBy == TokenList.SortType.BALANCE) return
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ByBalance)
viewModelScope.launch(dispatchers.default) {
val list = tokenList ?: return@launch
toggleTokenListSortingUseCase(list).fold(
ifLeft = stateHolder::updateStateWithError,
ifRight = {
@ -93,11 +94,11 @@ internal class OrganizeTokensViewModel @Inject constructor(
}
override fun onGroupClick() {
val list = tokenList ?: return
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Group)
viewModelScope.launch(dispatchers.default) {
val list = tokenList ?: return@launch
toggleTokenListGroupingUseCase(list).fold(
ifLeft = stateHolder::updateStateWithError,
ifRight = {
@ -166,13 +167,23 @@ internal class OrganizeTokensViewModel @Inject constructor(
private fun bootstrapDragAndDropUpdates() {
dragAndDropAdapter.dragAndDropUpdates
.distinctUntilChanged()
.onEach {
stateHolder.updateStateWithManualSorting(it)
tokenList = tokenList?.disableSortingByBalance()
.onEach { (type, updatedListState) ->
disableSortingByBalanceIfListChanged(type)
stateHolder.updateStateWithManualSorting(updatedListState)
}
.launchIn(viewModelScope)
}
private fun disableSortingByBalanceIfListChanged(dragOperationType: DragAndDropAdapter.DragOperation.Type) {
if (dragOperationType !is DragAndDropAdapter.DragOperation.Type.End) return
if (uiState.value.header.isSortedByBalance && dragOperationType.isItemsOrderChanged) {
tokenList = tokenList?.disableSortingByBalance()
stateHolder.disableSortingByBalance()
}
}
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
return getSelectedAppCurrencyUseCase()
.map { maybeAppCurrency ->

View file

@ -10,6 +10,9 @@ internal class InProgressStateConverter : TwoWayConverter<OrganizeTokensState, O
actions = value.actions.copy(
showApplyProgress = true,
),
header = value.header.copy(
isEnabled = false,
),
)
}
@ -18,6 +21,9 @@ internal class InProgressStateConverter : TwoWayConverter<OrganizeTokensState, O
actions = value.actions.copy(
showApplyProgress = false,
),
header = value.header.copy(
isEnabled = true,
),
)
}
}

View file

@ -8,9 +8,9 @@ import com.tangem.feature.wallet.presentation.organizetokens.utils.common.divide
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.uniteItems
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.updateItems
import kotlinx.collections.immutable.mutate
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
import org.burnoutcrew.reorderable.ItemPosition
internal class DragAndDropAdapter(
@ -19,21 +19,19 @@ internal class DragAndDropAdapter(
private val draggableGroupsOperations = DraggableGroupsOperations()
private val currentListState: OrganizeTokensListState
private val externalListState: OrganizeTokensListState
get() = listStateProvider.invoke()
private val dragAndDropUpdatesInternal: MutableSharedFlow<OrganizeTokensListState> = MutableSharedFlow(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
private val dragAndDropUpdatesInternal: MutableStateFlow<DragOperation?> = MutableStateFlow(value = null)
private var currentDraggingItem: DraggableItem? = null
private var draggingItem: DraggableItem? = null
private var draggingListState: OrganizeTokensListState? = null
val dragAndDropUpdates: SharedFlow<OrganizeTokensListState>
get() = dragAndDropUpdatesInternal
val dragAndDropUpdates: Flow<DragOperation>
get() = dragAndDropUpdatesInternal.filterNotNull()
override fun canDragItemOver(dragOver: ItemPosition, dragging: ItemPosition): Boolean {
val items = when (val listState = currentListState) {
val items = when (val listState = externalListState) {
is OrganizeTokensListState.GroupedByNetwork -> listState.items
is OrganizeTokensListState.Empty,
is OrganizeTokensListState.Ungrouped,
@ -58,10 +56,10 @@ internal class DragAndDropAdapter(
}
override fun onItemDraggingStart(item: DraggableItem) {
if (currentDraggingItem != null) return
currentDraggingItem = item
if (draggingItem != null) return
draggingItem = item
updateListState {
updateListState(DragOperation.Type.Start) {
when (item) {
is DraggableItem.Placeholder -> items
is DraggableItem.GroupHeader -> draggableGroupsOperations.collapseGroup(items, item)
@ -72,12 +70,14 @@ internal class DragAndDropAdapter(
}
}
}
draggingListState = externalListState
}
override fun onItemDraggingEnd() {
val draggingItem = currentDraggingItem ?: return
val draggingItem = draggingItem ?: return
updateListState {
updateListState(DragOperation.Type.End(isItemsOrderChanged = checkIsItemsOrderChanged())) {
when (draggingItem) {
is DraggableItem.GroupHeader -> draggableGroupsOperations.expandGroups(items)
is DraggableItem.Token -> items.uniteItems()
@ -85,19 +85,21 @@ internal class DragAndDropAdapter(
}
}
currentDraggingItem = null
this.draggingItem = null
}
override fun onItemDragged(from: ItemPosition, to: ItemPosition) = updateListState {
items.mutate {
it.add(to.index, it.removeAt(from.index))
override fun onItemDragged(from: ItemPosition, to: ItemPosition) {
updateListState(DragOperation.Type.Dragged) {
items.mutate {
it.add(to.index, it.removeAt(from.index))
}
}
}
private fun updateListState(block: OrganizeTokensListState.() -> List<DraggableItem>) {
val updatedState = currentListState.updateItems { block(currentListState) }
private fun updateListState(type: DragOperation.Type, block: OrganizeTokensListState.() -> List<DraggableItem>) {
val updatedState = externalListState.updateItems { block(externalListState) }
dragAndDropUpdatesInternal.tryEmit(updatedState)
dragAndDropUpdatesInternal.value = DragOperation(type, updatedState)
}
private fun findItemsToMove(
@ -145,4 +147,31 @@ internal class DragAndDropAdapter(
is DraggableItem.Placeholder -> false
}
}
private fun checkIsItemsOrderChanged(): Boolean {
fun OrganizeTokensListState?.getItemsIds(): List<Any>? = this?.items?.mapNotNull { item ->
if (item is DraggableItem.Placeholder) {
null
} else {
item.id
}
}
return externalListState.getItemsIds() != draggingListState.getItemsIds()
}
data class DragOperation(
val type: Type,
val listState: OrganizeTokensListState,
) {
sealed class Type {
object Start : Type()
object Dragged : Type()
data class End(val isItemsOrderChanged: Boolean) : Type()
}
}
}