From 4ae70b5391abd395919e345250336c67e6346e67 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 18 May 2026 16:12:10 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../features/txhistory/ui/TxHistoryContent.kt | 2 +- .../txhistory/utils/TxHistoryUiManager.kt | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt index 1c7f55bbac..96d2311a94 100644 --- a/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt +++ b/features/txhistory/api/src/main/kotlin/com/tangem/features/txhistory/ui/TxHistoryContent.kt @@ -61,7 +61,7 @@ private fun LazyListScope.contentItems(listState: LazyListState, state: TxHistor key = { item -> when (item) { is TxHistoryItemUM.GroupTitle -> "group_title:${item.itemKey}" - is TxHistoryItemUM.Transaction -> "tx:${item.state.txHash}" + is TxHistoryItemUM.Transaction -> "tx:${item.state.txHash}:${item.state.hashCode()}" } }, contentType = { item -> item::class.java }, diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt index f929e1e03e..4a13a25948 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/utils/TxHistoryUiManager.kt @@ -33,14 +33,16 @@ internal class TxHistoryUiManager( ): List>> { val currentUiBatches = state.value.uiBatches val batches = if (shouldClearUiBatches) mutableListOf() else currentUiBatches.toMutableList() + val seenTxIds = mutableSetOf() for ((key, data) in newCurrencyBatches) { + val uniqueItems = data.items.filter { seenTxIds.add(it.identityKey()) } val existingBatchIndex = batches.indexOfFirst { it.key == key } if (existingBatchIndex == -1) { - val items = generateUiItems(key, data, converter) + val items = generateUiItems(key, data.copy(items = uniqueItems), converter) batches.add(Batch(key = key, data = items)) - } else if (currentUiBatches[existingBatchIndex].data.transactionItemsSizeNotEqual(data.items)) { - val items = generateUiItems(key, data, converter) + } else if (currentUiBatches[existingBatchIndex].data.transactionItemsSizeNotEqual(uniqueItems)) { + val items = generateUiItems(key, data.copy(items = uniqueItems), converter) batches[existingBatchIndex] = Batch(key = key, data = items) } } @@ -94,4 +96,13 @@ internal class TxHistoryUiManager( private val TxHistoryListState.hasContent: Boolean get() = status !is PaginationStatus.None && status !is PaginationStatus.InitialLoading && - status !is PaginationStatus.InitialLoadingError \ No newline at end of file + status !is PaginationStatus.InitialLoadingError + +/** + * Cross-batch identity of a tx: `txHash` alone is not enough because gasless flows surface several + * events under the same on-chain hash (e.g. `GaslessFee` + `Transfer`). Pinning the [TxInfo.type] + * keeps those legitimate sibling events apart while still collapsing the same event seen twice — + * e.g. an Unconfirmed copy injected via `addRecentTransactions` and a Confirmed copy that arrives + * in a later API batch. + */ +private fun TxInfo.identityKey(): String = "$txHash|$type" \ No newline at end of file