Updated on 2026-08-14
This commit is contained in:
parent
799a423f9f
commit
ed94c73dcc
6 changed files with 85 additions and 40 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue