From c933d44932e9a5030735885734dcfdc0b8140b32 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 10 Jun 2026 19:47:47 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../txhistory/model/TxHistoryModel.kt | 8 +- .../state/TxHistoryStateController.kt | 16 ++- .../state/TxHistoryStateControllerTest.kt | 120 ++++++++++++++++++ 3 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt index babda57ca1..b40657fc23 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/model/TxHistoryModel.kt @@ -144,7 +144,13 @@ internal class TxHistoryModel @Inject constructor( private fun subscribeToUiItemChanges() { txHistoryListManager.uiItems - .onEach { snapshot -> stateController.setContent(snapshot = snapshot, loadMore = ::loadMoreItems) } + .onEach { snapshot -> + stateController.setContent( + snapshot = snapshot, + loadMore = ::loadMoreItems, + onExploreClick = ::openExplorer, + ) + } .launchIn(modelScope) txHistoryListManager.paginationStatus .onEach { paginationStatus -> handlePaginationStatus(paginationStatus) } diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt index ac79d77a9a..1c4661b41b 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/state/TxHistoryStateController.kt @@ -110,10 +110,15 @@ internal class TxHistoryStateController @Inject constructor( } } - fun setContent(snapshot: TxHistoryItemsSnapshot, loadMore: () -> Boolean) { + fun setContent(snapshot: TxHistoryItemsSnapshot, loadMore: () -> Boolean, onExploreClick: () -> Unit) { when (snapshot) { is TxHistoryItemsSnapshot.Items -> _uiState.update { state -> - if (state is TxHistoryItemsUM.Content) { + if (snapshot.items.none { it is TxHistoryItemsUM.TxHistoryItemUM.Transaction }) { + TxHistoryItemsUM.Empty( + isBalanceHidden = state.isBalanceHidden, + onExploreClick = onExploreClick, + ) + } else if (state is TxHistoryItemsUM.Content) { state.copy(items = snapshot.items) } else { TxHistoryItemsUM.Content( @@ -125,7 +130,12 @@ internal class TxHistoryStateController @Inject constructor( } } is TxHistoryItemsSnapshot.LegacyItems -> _legacyUiState.update { state -> - if (state is TxHistoryUM.Content) { + if (snapshot.items.none { it is TxHistoryUM.TxHistoryItemUM.Transaction }) { + TxHistoryUM.Empty( + isBalanceHidden = state.isBalanceHidden, + onExploreClick = onExploreClick, + ) + } else if (state is TxHistoryUM.Content) { state.copy(items = snapshot.items) } else { TxHistoryUM.Content( diff --git a/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt b/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt new file mode 100644 index 0000000000..328bdf2d48 --- /dev/null +++ b/features/txhistory/impl/src/test/kotlin/com/tangem/features/txhistory/state/TxHistoryStateControllerTest.kt @@ -0,0 +1,120 @@ +package com.tangem.features.txhistory.state + +import com.google.common.truth.Truth.assertThat +import com.tangem.core.ui.DesignFeatureToggles +import com.tangem.core.ui.components.transactions.state.TransactionItemUM +import com.tangem.core.ui.components.transactions.state.TransactionState +import com.tangem.features.txhistory.entity.TxHistoryItemsUM +import com.tangem.features.txhistory.entity.TxHistoryUM +import io.mockk.every +import io.mockk.mockk +import kotlinx.collections.immutable.persistentListOf +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +internal class TxHistoryStateControllerTest { + + private val controller = TxHistoryStateController( + designFeatureToggles = mockk { every { isRedesignEnabled } returns true }, + ) + private val legacyController = TxHistoryStateController( + designFeatureToggles = mockk { every { isRedesignEnabled } returns false }, + ) + + @Test + fun `GIVEN empty items snapshot WHEN setContent THEN Empty state with explorer action`() { + val onExploreClick = {} + + controller.setContent( + snapshot = TxHistoryItemsSnapshot.Items(persistentListOf()), + loadMore = { true }, + onExploreClick = onExploreClick, + ) + + val state = controller.uiState.value + assertThat(state).isInstanceOf(TxHistoryItemsUM.Empty::class.java) + assertThat((state as TxHistoryItemsUM.Empty).onExploreClick).isEqualTo(onExploreClick) + } + + @Test + fun `GIVEN snapshot with only a group title WHEN setContent THEN Empty state`() { + controller.setContent( + snapshot = TxHistoryItemsSnapshot.Items( + persistentListOf( + TxHistoryItemsUM.TxHistoryItemUM.GroupTitle(title = "Today", itemKey = "0-Today"), + ), + ), + loadMore = { true }, + onExploreClick = {}, + ) + + assertThat(controller.uiState.value).isInstanceOf(TxHistoryItemsUM.Empty::class.java) + } + + @Test + fun `GIVEN snapshot with transactions WHEN setContent THEN Content state`() { + controller.setContent( + snapshot = TxHistoryItemsSnapshot.Items( + persistentListOf( + TxHistoryItemsUM.TxHistoryItemUM.GroupTitle(title = "Today", itemKey = "0-Today"), + TxHistoryItemsUM.TxHistoryItemUM.Transaction(TransactionItemUM.Loading("hash")), + ), + ), + loadMore = { true }, + onExploreClick = {}, + ) + + assertThat(controller.uiState.value).isInstanceOf(TxHistoryItemsUM.Content::class.java) + } + + @Test + fun `GIVEN Empty state WHEN empty snapshot arrives THEN Empty is not overridden by Content`() { + controller.setEmpty(onExploreClick = {}) + + controller.setContent( + snapshot = TxHistoryItemsSnapshot.Items(persistentListOf()), + loadMore = { true }, + onExploreClick = {}, + ) + + assertThat(controller.uiState.value).isInstanceOf(TxHistoryItemsUM.Empty::class.java) + } + + // region Legacy (e.g. Solana: probe reports HasTransactions but the mapped page is empty) + + @Test + fun `GIVEN legacy snapshot with only a title WHEN setContent THEN legacy Empty state with explorer`() { + val onExploreClick = {} + + legacyController.setContent( + snapshot = TxHistoryItemsSnapshot.LegacyItems( + persistentListOf(TxHistoryUM.TxHistoryItemUM.Title(onExploreClick = {})), + ), + loadMore = { true }, + onExploreClick = onExploreClick, + ) + + val state = legacyController.legacyUiState.value + assertThat(state).isInstanceOf(TxHistoryUM.Empty::class.java) + assertThat((state as TxHistoryUM.Empty).onExploreClick).isEqualTo(onExploreClick) + } + + @Test + fun `GIVEN legacy snapshot with transactions WHEN setContent THEN legacy Content state`() { + legacyController.setContent( + snapshot = TxHistoryItemsSnapshot.LegacyItems( + persistentListOf( + TxHistoryUM.TxHistoryItemUM.Title(onExploreClick = {}), + TxHistoryUM.TxHistoryItemUM.Transaction(TransactionState.Loading("hash")), + ), + ), + loadMore = { true }, + onExploreClick = {}, + ) + + assertThat(legacyController.legacyUiState.value).isInstanceOf(TxHistoryUM.Content::class.java) + } + + // endregion +} \ No newline at end of file