From 5013bb84ca5790dbefc1791b2522828c2e7bd913 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 1 Jul 2026 22:30:13 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/domain/card/CardTypesResolver.kt | 2 + .../domain/card/TangemCardTypesResolver.kt | 2 + .../domain/GetSingleWalletWarningsFactory.kt | 2 +- .../GetWalletNotificationsCarouselFactory.kt | 2 +- ...tWalletNotificationsCarouselFactoryTest.kt | 77 +++++++++++++++++++ 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/CardTypesResolver.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/CardTypesResolver.kt index ae9c6a0fbc..222017d966 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/CardTypesResolver.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/CardTypesResolver.kt @@ -31,6 +31,8 @@ interface CardTypesResolver { fun isSingleWalletWithToken(): Boolean + fun isSingleCurrency(): Boolean + fun isMultiwalletAllowed(): Boolean fun getBlockchain(): Blockchain diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/TangemCardTypesResolver.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/TangemCardTypesResolver.kt index 3e6943f724..bf3c6faab7 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/TangemCardTypesResolver.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/TangemCardTypesResolver.kt @@ -65,6 +65,8 @@ internal class TangemCardTypesResolver( override fun isSingleWalletWithToken(): Boolean = walletData?.token != null && !isMultiwalletAllowed() + override fun isSingleCurrency(): Boolean = isSingleWallet() || isSingleWalletWithToken() + override fun isMultiwalletAllowed(): Boolean { return !isTangemTwins() && !card.isStart2Coin && diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt index 82596dbd03..19ad21c2e1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetSingleWalletWarningsFactory.kt @@ -128,7 +128,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor( element = WalletNotification.NoteMigration( onClick = { clickIntents.onNoteMigrationButtonClick(NOTE_MIGRATION_URL) }, ), - condition = cardTypesResolver.isTangemNote() && !hasWalletOrWallet2, + condition = cardTypesResolver.isSingleCurrency() && !hasWalletOrWallet2, ) addIf( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactory.kt index 82610ab8c7..e4f9a1402f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactory.kt @@ -122,7 +122,7 @@ internal class GetWalletNotificationsCarouselFactory @Inject constructor( typesResolver.isTangemWallet() || typesResolver.isWallet2() } - addIf(cardTypesResolver != null && cardTypesResolver.isTangemNote() && !isUserHasWalletOrWallet2) { + addIf(cardTypesResolver != null && cardTypesResolver.isSingleCurrency() && !isUserHasWalletOrWallet2) { WalletNotificationUM.NoteMigration( onClick = { clickIntents.onNoteMigrationButtonClick(TangemSiteUrlBuilder.NOTE_MIGRATION_URL) }, ) diff --git a/features/wallet/impl/src/test/kotlin/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactoryTest.kt b/features/wallet/impl/src/test/kotlin/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactoryTest.kt index 5ce92507a5..6068ef6cf8 100644 --- a/features/wallet/impl/src/test/kotlin/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactoryTest.kt +++ b/features/wallet/impl/src/test/kotlin/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsCarouselFactoryTest.kt @@ -5,10 +5,13 @@ import com.google.common.truth.Truth.assertThat import com.tangem.domain.account.models.AccountStatusList import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.card.CardTypesResolver +import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TokensGroupType import com.tangem.domain.models.TokensSortType import com.tangem.domain.models.TotalFiatBalance +import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.notifications.repository.NotificationsRepository @@ -23,10 +26,13 @@ import io.mockk.clearMocks import io.mockk.coEvery import io.mockk.every import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic import io.mockk.verify import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance @@ -85,6 +91,11 @@ internal class GetWalletNotificationsCarouselFactoryTest { } returns flowOf(accountStatusList(TotalFiatBalance.Loaded(BigDecimal.ZERO, StatusSource.ACTUAL))) } + @AfterEach + fun tearDown() { + unmockkStatic(ScanResponse::cardTypesResolver) + } + @ParameterizedTest @MethodSource("provideTestModels") fun `GIVEN gating conditions WHEN create THEN yield boost banner visibility matches`(model: Model) = runTest { @@ -134,6 +145,56 @@ internal class GetWalletNotificationsCarouselFactoryTest { verify { clickIntents.onDismissYieldBoostBanner(WALLET_ID) } } + @ParameterizedTest + @MethodSource("provideNoteMigrationTestModels") + fun `GIVEN single-currency card WHEN create THEN discover wallet promo visibility matches`( + model: NoteMigrationModel, + ) = runTest { + // Arrange + mockkStatic(ScanResponse::cardTypesResolver) + val selectedResolver = mockk(relaxed = true) { + every { isSingleCurrency() } returns model.isSingleCurrency + } + val selectedWallet = mockColdWallet(selectedResolver, walletId = WALLET_ID) + val wallets = buildList { + add(selectedWallet) + if (model.userAlreadyHasWallet) { + val walletResolver = mockk(relaxed = true) { + every { isTangemWallet() } returns true + } + add(mockColdWallet(walletResolver, walletId = OTHER_WALLET_ID)) + } + } + every { getWalletsUseCase() } returns flowOf(wallets) + + // Act + val result = factory.create(selectedWallet, clickIntents).first() + + // Assert + assertThat(result.any { it is WalletNotificationUM.NoteMigration }).isEqualTo(model.expectedShown) + } + + @Test + fun `GIVEN hot wallet WHEN create THEN discover wallet promo is hidden`() = runTest { + // Arrange + every { getWalletsUseCase() } returns flowOf(listOf(userWallet)) + + // Act + val result = factory.create(userWallet, clickIntents).first() + + // Assert + assertThat(result.none { it is WalletNotificationUM.NoteMigration }).isTrue() + } + + private fun mockColdWallet(resolver: CardTypesResolver, walletId: UserWalletId): UserWallet.Cold { + val scanResponse = mockk() + every { scanResponse.cardTypesResolver } returns resolver + return mockk(relaxed = true) { + every { this@mockk.walletId } returns walletId + every { this@mockk.scanResponse } returns scanResponse + } + } + private fun accountStatusList(balance: TotalFiatBalance) = AccountStatusList( userWalletId = WALLET_ID, accountStatuses = emptyList(), @@ -189,7 +250,23 @@ internal class GetWalletNotificationsCarouselFactoryTest { ), ) + internal data class NoteMigrationModel( + val isSingleCurrency: Boolean, + val userAlreadyHasWallet: Boolean, + val expectedShown: Boolean, + ) + + private fun provideNoteMigrationTestModels() = listOf( + // Single-currency card (Note / S2C / Twins) and the user owns no multi-currency wallet — promo shown. + NoteMigrationModel(isSingleCurrency = true, userAlreadyHasWallet = false, expectedShown = true), + // Single-currency card, but the user already owns a Wallet / Wallet2 — promo hidden. + NoteMigrationModel(isSingleCurrency = true, userAlreadyHasWallet = true, expectedShown = false), + // Multi-currency card — promo hidden. + NoteMigrationModel(isSingleCurrency = false, userAlreadyHasWallet = false, expectedShown = false), + ) + private companion object { val WALLET_ID = UserWalletId("01") + val OTHER_WALLET_ID = UserWalletId("02") } } \ No newline at end of file