Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-16 13:15:59 +03:00
parent e40ce860a4
commit 2b4aa16605
5 changed files with 93 additions and 47 deletions

View file

@ -17,5 +17,6 @@ internal sealed class SendRecipientListContent {
data class Wallets(
val list: PersistentList<Item>,
val isWalletsOnly: Boolean,
) : SendRecipientListContent()
}

View file

@ -105,10 +105,15 @@ internal class SendStateFactory(
//endregion
//region recipient
fun onLoadedRecipientList(wallets: List<AvailableWallet?>, txHistory: PagingData<TxHistoryItem>) {
fun onLoadedRecipientList(
wallets: List<AvailableWallet?>,
txHistory: PagingData<TxHistoryItem>,
txHistoryCount: Int,
) {
recipientListStateConverter.convert(
wallets = wallets,
txHistory = txHistory,
txHistoryCount = txHistoryCount,
)
}

View file

@ -22,7 +22,7 @@ internal class SendRecipientListConverter(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) {
fun convert(wallets: List<AvailableWallet?>, txHistory: PagingData<TxHistoryItem>) {
fun convert(wallets: List<AvailableWallet?>, txHistory: PagingData<TxHistoryItem>, txHistoryCount: Int) {
val filteredWallets = wallets.filterNotNull()
.groupBy { item -> item.name }
.values.flatten()
@ -32,49 +32,58 @@ internal class SendRecipientListConverter(
)
}
val walletsItem = getWalletItems(filteredWallets, txHistoryCount)
currentStateProvider().recipientList.update {
txHistory.filter { item ->
val isTransfer = item.type == TxHistoryItem.TransactionType.Transfer
val isNotContract = item.interactionAddressType is TxHistoryItem.InteractionAddressType.User
val isSingleAddress = if (item.isOutgoing) {
item.destinationType is TxHistoryItem.DestinationType.Single
} else {
item.sourceType is TxHistoryItem.SourceType.Single
}
isTransfer && isSingleAddress && isNotContract
}.map<TxHistoryItem, SendRecipientListContent> { tx ->
SendRecipientListContent.Item(
id = tx.txHash,
title = tx.extractAddress(),
subtitle = TextReference.Str(tx.getAmount()),
info = tx.extractTimestamp(),
subtitleIconRes = tx.extractIconRes(),
)
}.insertWallets(filteredWallets)
if (txHistoryCount == 0) {
PagingData.from(listOf(walletsItem))
} else {
txHistory.filter { item ->
val isTransfer = item.type == TxHistoryItem.TransactionType.Transfer
val isNotContract = item.interactionAddressType is TxHistoryItem.InteractionAddressType.User
val isSingleAddress = if (item.isOutgoing) {
item.destinationType is TxHistoryItem.DestinationType.Single
} else {
item.sourceType is TxHistoryItem.SourceType.Single
}
isTransfer && isSingleAddress && isNotContract
}.map<TxHistoryItem, SendRecipientListContent> { tx ->
SendRecipientListContent.Item(
id = tx.txHash,
title = tx.extractAddress(),
subtitle = TextReference.Str(tx.getAmount()),
info = tx.extractTimestamp(),
subtitleIconRes = tx.extractIconRes(),
)
}.insertWallets(walletsItem)
}
}
}
private fun PagingData<SendRecipientListContent>.insertWallets(
wallets: List<AvailableWallet>,
wallets: SendRecipientListContent.Wallets,
): PagingData<SendRecipientListContent> {
return insertSeparators(terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE) { before, after ->
return@insertSeparators when {
before == null && after is SendRecipientListContent.Item -> {
SendRecipientListContent.Wallets(
wallets.map {
SendRecipientListContent.Item(
id = it.address,
title = TextReference.Str(it.address),
subtitle = TextReference.Str(it.name),
)
}.toPersistentList(),
)
}
before == null && after is SendRecipientListContent.Item -> wallets
else -> null
}
}
}
private fun getWalletItems(wallets: List<AvailableWallet>, txHistoryCount: Int): SendRecipientListContent.Wallets {
return SendRecipientListContent.Wallets(
wallets.map {
SendRecipientListContent.Item(
id = it.address,
title = TextReference.Str(it.address),
subtitle = TextReference.Str(it.name),
)
}.toPersistentList(),
isWalletsOnly = txHistoryCount == 0,
)
}
private fun TxHistoryItem.extractAddress(): TextReference = if (isOutgoing) {
when (val destination = destinationType) {
is TxHistoryItem.DestinationType.Multiple -> TextReference.Res(

View file

@ -80,6 +80,7 @@ internal fun SendRecipientContent(
}
}
@Suppress("LongMethod")
@OptIn(ExperimentalFoundationApi::class)
private fun LazyListScope.recipientListItem(
recipientList: LazyPagingItems<SendRecipientListContent>,
@ -106,10 +107,17 @@ private fun LazyListScope.recipientListItem(
.padding(top = TangemTheme.dimens.spacing20)
.then(
if (index == 0) {
val bottomRadius = if (item.isWalletsOnly) {
TangemTheme.dimens.radius12
} else {
TangemTheme.dimens.radius0
}
Modifier.clip(
RoundedCornerShape(
topEnd = TangemTheme.dimens.radius12,
topStart = TangemTheme.dimens.radius12,
bottomStart = bottomRadius,
bottomEnd = bottomRadius,
),
)
} else {
@ -182,18 +190,25 @@ private fun RecipientWalletListItem(
onClick = { clickIntents.onRecipientAddressValueChange(title) },
)
}
Text(
text = stringResource(R.string.send_recent_transactions),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
.fillMaxWidth()
.padding(
top = TangemTheme.dimens.spacing8,
bottom = TangemTheme.dimens.spacing8,
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
)
if (!item.isWalletsOnly) {
val topPadding = if (item.list.isNotEmpty()) {
TangemTheme.dimens.spacing8
} else {
TangemTheme.dimens.spacing0
}
Text(
text = stringResource(R.string.send_recent_transactions),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
.fillMaxWidth()
.padding(
top = topPadding,
bottom = TangemTheme.dimens.spacing8,
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
)
}
}
}

View file

@ -20,6 +20,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
@ -57,6 +58,7 @@ internal class SendViewModel @Inject constructor(
private val getWalletsUseCase: GetWalletsUseCase,
private val getCryptoCurrenciesUseCase: GetCryptoCurrenciesUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val getFeeUseCase: GetFeeUseCase,
private val walletManagersFacade: WalletManagersFacade,
savedStateHandle: SavedStateHandle,
@ -97,7 +99,6 @@ internal class SendViewModel @Inject constructor(
override fun onCreate(owner: LifecycleOwner) {
getWalletAddresses()
subscribeOnCurrencyStatusUpdates(owner)
getWalletsAndRecent()
getFee()
}
@ -134,6 +135,7 @@ internal class SendViewModel @Inject constructor(
.onEach { either ->
either.onRight {
cryptoCurrencyStatus = it
getWalletsAndRecent()
uiState = stateFactory.getReadyState()
}
}
@ -158,10 +160,12 @@ internal class SendViewModel @Inject constructor(
combine(
flow = getUserWallets().conflate(),
flow2 = getTxHistory().conflate(),
) { wallets, txHistory ->
flow3 = getTxHistoryCount().conflate(),
) { wallets, txHistory, txHistoryCount ->
stateFactory.onLoadedRecipientList(
wallets = wallets,
txHistory = txHistory,
txHistoryCount = txHistoryCount,
)
}
.flowOn(dispatchers.io)
@ -213,6 +217,18 @@ internal class SendViewModel @Inject constructor(
}
}
private fun getTxHistoryCount(): Flow<Int> {
return flow {
txHistoryItemsCountUseCase(
userWalletId = userWalletId,
currency = cryptoCurrency,
).fold(
ifRight = { emit(it) },
ifLeft = { emit(0) },
)
}
}
private fun getFee() {
viewModelScope.launch(dispatchers.main) {
uiState.currentState