From 2b1baa61feccf0c6385e5547f5f818a08bd9615b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Apr 2026 15:13:37 +0400 Subject: [PATCH 01/20] Updated on 2026-08-14 --- .../domain/transaction/usecase/AssociateAssetUseCase.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt index d20682fdc2..664a93a44f 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt @@ -32,9 +32,11 @@ class AssociateAssetUseCase( val networkCoin = multiWalletCryptoCurrenciesSupplier.getSyncOrNull( params = MultiWalletCryptoCurrenciesProducer.Params(userWallet.walletId), ) - ?.firstOrNull { + ?.firstOrNull { cryptoCurrency -> val network = currency.network - it.network.id == network.id && it.network.derivationPath == network.derivationPath + cryptoCurrency is CryptoCurrency.Coin && + cryptoCurrency.network.id == network.id && + cryptoCurrency.network.derivationPath == network.derivationPath } ?: error("Unable to create network coin for currencyID: ${currency.id}") From d52133d13ebf13d9a5a3165ef32fde4fafee03d7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Apr 2026 14:39:11 +0300 Subject: [PATCH 02/20] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 5f8d49287b..1c95c2ee9a 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 5f8d49287bdfa12f6618fc6a580706b14e4a9c13 +Subproject commit 1c95c2ee9aaa0007ea203b1bd9477e874f8211be From 9943f33070e7d63ee9b6d970ae5abdae9b2c6255 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Apr 2026 15:45:21 +0400 Subject: [PATCH 03/20] Updated on 2026-08-14 --- .../features/send/v2/api/SendNotificationsComponent.kt | 1 + .../notifications/model/NotificationsModel.kt | 4 ++++ .../v2/impl/notifications/SwapNotificationsComponent.kt | 2 ++ .../v2/impl/notifications/model/SwapNotificationsModel.kt | 7 ++++++- .../sendviaswap/confirm/model/SendWithSwapConfirmModel.kt | 5 +++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/SendNotificationsComponent.kt b/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/SendNotificationsComponent.kt index b6c92acf3a..8e8192a6db 100644 --- a/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/SendNotificationsComponent.kt +++ b/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/SendNotificationsComponent.kt @@ -41,6 +41,7 @@ interface SendNotificationsComponent { val fee: Fee?, val feeError: GetFeeError?, val feeCryptoCurrencyStatus: CryptoCurrencyStatus, + val isReduceAmountAvailable: Boolean = true, ) } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/notifications/model/NotificationsModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/notifications/model/NotificationsModel.kt index 8d0fd0bb25..676eb712c2 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/notifications/model/NotificationsModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/notifications/model/NotificationsModel.kt @@ -108,6 +108,10 @@ internal class NotificationsModel @Inject constructor( } private suspend fun checkIfSubtractAvailable() { + if (!notificationData.isReduceAmountAvailable) { + isAmountSubtractAvailable = false + return + } val feeCurrencyId = notificationData.feeCryptoCurrencyStatus.currency.id val fee = notificationData.fee isAmountSubtractAvailable = isAmountSubtractAvailableUseCase( diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/SwapNotificationsComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/SwapNotificationsComponent.kt index 580b1c629a..f68c3e608d 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/SwapNotificationsComponent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/SwapNotificationsComponent.kt @@ -53,6 +53,8 @@ internal class SwapNotificationsComponent( val fromCryptoCurrencyStatus: CryptoCurrencyStatus? = null, val priceImpact: PriceImpact? = null, val provider: ExpressProvider? = null, + val shouldIncludeFeeInBalanceCheck: Boolean = false, + val feeValue: BigDecimal? = null, ) } } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt index f69bf413d1..8855010bf1 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt @@ -132,7 +132,12 @@ internal class SwapNotificationsModel @Inject constructor( private fun MutableList.addInsufficientFundsNotification() { val enteredFromAmount = notificationData.enteredFromAmount ?: return val balance = notificationData.fromCryptoCurrencyStatus?.value?.amount ?: return - if (enteredFromAmount > balance) { + val totalRequired = if (notificationData.shouldIncludeFeeInBalanceCheck) { + enteredFromAmount + (notificationData.feeValue ?: BigDecimal.ZERO) + } else { + enteredFromAmount + } + if (totalRequired > balance) { add(SwapNotificationUM.Error.InsufficientFunds) } } diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt index 3c71e14050..c335013569 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt @@ -23,6 +23,7 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.account.status.usecase.GetAccountCurrencyByAddressUseCase import com.tangem.domain.express.models.ExpressOperationType +import com.tangem.domain.express.models.ExpressRateType import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.models.account.derivationIndex import com.tangem.domain.models.currency.CryptoCurrency @@ -432,6 +433,7 @@ internal class SendWithSwapConfirmModel @Inject constructor( private fun updateConfirmNotifications() { modelScope.launch { + val isFixedRate = amountUM?.swapRateType == ExpressRateType.Fixed val feeCryptoCurrencyStatus = feeUMV2?.feeExtraInfo?.feeCryptoCurrencyStatus ?: params.primaryFeePaidCurrencyStatusFlow.value sendNotificationsUpdateTrigger.triggerUpdate( @@ -448,6 +450,7 @@ internal class SendWithSwapConfirmModel @Inject constructor( fee = confirmData.fee, feeError = confirmData.feeError, feeCryptoCurrencyStatus = feeCryptoCurrencyStatus, + isReduceAmountAvailable = !isFixedRate, ), ) swapNotificationsUpdateTrigger.triggerUpdate( @@ -462,6 +465,8 @@ internal class SendWithSwapConfirmModel @Inject constructor( fromCryptoCurrencyStatus = confirmData.fromCryptoCurrencyStatus, priceImpact = confirmData.priceImpact, provider = confirmData.quote?.provider, + shouldIncludeFeeInBalanceCheck = isFixedRate && isAmountSubtractAvailable, + feeValue = confirmData.fee?.amount?.value, ), ) uiState.transformerUpdate( From fc5fbf69deb5b68b1a607f0d649727b449a54f4d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Apr 2026 17:12:23 +0400 Subject: [PATCH 04/20] Updated on 2026-08-14 --- .../sendviaswap/confirm/model/SendWithSwapConfirmModel.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt index c335013569..35c8b24d02 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt @@ -5,7 +5,6 @@ import arrow.core.getOrElse import arrow.core.left import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.common.transaction.TransactionFee -import com.tangem.common.routing.AppRouter import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.navigationButtons.NavigationButton @@ -100,7 +99,6 @@ internal class SendWithSwapConfirmModel @Inject constructor( private val swapAmountUpdateTrigger: SwapAmountUpdateTrigger, private val feeSelectorReloadTrigger: FeeSelectorReloadTrigger, private val swapAlertFactory: SwapAlertFactory, - private val appRouter: AppRouter, private val analyticsEventHandler: AnalyticsEventHandler, private val holdToConfirmButtonFeatureToggles: HoldToConfirmButtonFeatureToggles, swapTransactionSenderFactory: SwapTransactionSender.Factory, @@ -342,7 +340,7 @@ internal class SendWithSwapConfirmModel @Inject constructor( ) } }, - popBack = appRouter::pop, + popBack = {}, ) }, onSendError = { error -> @@ -365,7 +363,7 @@ internal class SendWithSwapConfirmModel @Inject constructor( ) } }, - popBack = appRouter::pop, + popBack = {}, ) }, onSendSuccess = { txHash, timestamp, data -> From 5a541834502989ab3482638a46b6b68362229a18 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Apr 2026 16:52:48 +0300 Subject: [PATCH 05/20] Updated on 2026-08-14 --- .../swap/v2/impl/notifications/model/SwapNotificationsModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt index 8855010bf1..bbfb56b4ad 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import java.math.BigDecimal import javax.inject.Inject @Suppress("LongParameterList") From 1012e81f09fff334d2d5328b9a0aa2ef9f617831 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Apr 2026 19:09:56 +0400 Subject: [PATCH 06/20] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 891cb8a686..af40440304 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.37-1489" +tangemBlockchainSdk = "releases-5.37-1490" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.37-603" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 02c3d09855549a09f02b94f4ff9570b7b25355ec Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 11:33:02 +0400 Subject: [PATCH 07/20] Updated on 2026-08-14 --- .../features/swap/v2/impl/amount/model/SwapAmountModel.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt index ecc249a62b..dcf53ad59d 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt @@ -149,9 +149,10 @@ internal class SwapAmountModel @Inject constructor( } fun onStart() { + val isDelayFirst = params !is SwapAmountComponentParams.AmountBlockParams quoteTaskScheduler.scheduleTask( scope = modelScope, - task = loadQuotesTask(), + task = loadQuotesTask(isDelayFirst = isDelayFirst), ) subscribeOnAutoupdateEnabling() } @@ -824,10 +825,10 @@ internal class SwapAmountModel @Inject constructor( ) } - private fun loadQuotesTask(): PeriodicTask { + private fun loadQuotesTask(isDelayFirst: Boolean = true): PeriodicTask { return PeriodicTask( delay = QUOTES_UPDATE_DELAY, - isDelayFirst = true, + isDelayFirst = isDelayFirst, task = { runCatching { loadQuotes(isSilentReload = true) } }, From 17add53bc0912f6f8714a4152ca912eacce7d4dc Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 11:21:42 +0300 Subject: [PATCH 08/20] Updated on 2026-08-14 --- .../models/promobanners/DismissPromoBannerRequest.kt | 12 ++++++++++-- .../impl/repository/DefaultPromoBannersRepository.kt | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/DismissPromoBannerRequest.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/DismissPromoBannerRequest.kt index 1bb3d5ac18..92cc200fc7 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/DismissPromoBannerRequest.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/DismissPromoBannerRequest.kt @@ -6,5 +6,13 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class DismissPromoBannerRequest( @Json(name = "walletId") val walletId: String, - @Json(name = "isDismissed") val isDismissed: Boolean, -) \ No newline at end of file + @Json(name = "status") val status: BannerDisplayStatus, +) { + + @JsonClass(generateAdapter = false) + enum class BannerDisplayStatus { + @Json(name = "active") ACTIVE, + + @Json(name = "dismissed") DISMISSED, + } +} \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt index 9a13d9fab1..37c5cf33ef 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt @@ -66,7 +66,7 @@ internal class DefaultPromoBannersRepository( withContext(dispatchers.io) { val request = DismissPromoBannerRequest( walletId = walletId, - isDismissed = true, + status = DismissPromoBannerRequest.BannerDisplayStatus.DISMISSED, ) tangemTechApi.dismissPromoBannerDisplay(displayId, request).getOrThrow() } From 304e6d0c5c9f2e6146e0903c89ac14814fbd985e Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 11:21:53 +0300 Subject: [PATCH 09/20] Updated on 2026-08-14 --- .../components/feed/DefaultFeedComponent.kt | 7 +++ .../api/PromoBannersBlockComponent.kt | 3 ++ .../impl/DefaultPromoBannersBlockComponent.kt | 4 ++ .../impl/model/PromoBannersBlockModel.kt | 9 +++- .../impl/model/PromoBannersBlockUM.kt | 1 + .../promobanners/impl/ui/PromoBannersBlock.kt | 44 ++++++++----------- 6 files changed, 41 insertions(+), 27 deletions(-) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt index 4f06480af4..a374e0faee 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt @@ -2,6 +2,7 @@ package com.tangem.features.feed.components.feed import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -44,6 +45,7 @@ internal class DefaultFeedComponent( context = child("promoBannersBlockComponent"), params = PromoBannersBlockComponent.Params( placeholder = PromoBannersBlockComponent.Placeholder.FEED, + isInitiallyVisibleOnScreen = false, ), ) } @@ -70,6 +72,11 @@ internal class DefaultFeedComponent( contentPadding: PaddingValues, modifier: Modifier, ) { + val isExpanded = bottomSheetState.value == BottomSheetState.EXPANDED + LaunchedEffect(isExpanded) { + promoBannersBlockComponent?.setVisibleOnScreen(isExpanded) + } + LifecycleStartEffect(Unit) { feedComponentModel.isVisibleOnScreen.value = true onStopOrDispose { diff --git a/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt b/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt index bb50b2bcd2..e97e39f047 100644 --- a/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt +++ b/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt @@ -5,8 +5,11 @@ import com.tangem.core.ui.decompose.ComposableContentComponent interface PromoBannersBlockComponent : ComposableContentComponent { + fun setVisibleOnScreen(isVisible: Boolean) + data class Params( val placeholder: Placeholder, + val isInitiallyVisibleOnScreen: Boolean = true, ) enum class Placeholder { diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt index 23ae1dce22..814031d197 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt @@ -20,6 +20,10 @@ internal class DefaultPromoBannersBlockComponent @AssistedInject constructor( private val model: PromoBannersBlockModel = getOrCreateModel(params) + override fun setVisibleOnScreen(isVisible: Boolean) { + model.setVisibleOnScreen(isVisible) + } + @Composable override fun Content(modifier: Modifier) { val state by model.uiState.collectAsStateWithLifecycle() diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt index f4f2d505e5..89a157c634 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt @@ -36,6 +36,7 @@ internal class PromoBannersBlockModel @Inject constructor( private val placeholder: String = params.placeholder.name.lowercase() private val shownBannerIds: MutableSet = ConcurrentHashMap.newKeySet() + private var isVisibleOnScreen: Boolean = params.isInitiallyVisibleOnScreen private var wasCarouselScrolled = false private val savedDisplayIdByWalletId: MutableMap = mutableMapOf() @@ -46,6 +47,11 @@ internal class PromoBannersBlockModel @Inject constructor( subscribeOnSelectedWallet() } + fun setVisibleOnScreen(visible: Boolean) { + isVisibleOnScreen = visible + uiState.update { it.copy(isVisibleOnScreen = visible) } + } + private fun subscribeOnSelectedWallet() { modelScope.launch { userWalletsListRepository.selectedUserWallet @@ -53,7 +59,6 @@ internal class PromoBannersBlockModel @Inject constructor( .map { it.walletId.stringValue } .distinctUntilChanged() .onEach { - shownBannerIds.clear() wasCarouselScrolled = false } .collectLatest { walletId -> loadBanners(walletId) } @@ -85,6 +90,7 @@ internal class PromoBannersBlockModel @Inject constructor( userWalletId = walletId, initialPage = initialPage, banners = bannerUMs, + isVisibleOnScreen = isVisibleOnScreen, onBannerShown = ::onBannerShown, onCarouselScrolled = ::onCarouselScrolled, onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId }, @@ -116,6 +122,7 @@ internal class PromoBannersBlockModel @Inject constructor( userWalletId = "", initialPage = 0, banners = persistentListOf(), + isVisibleOnScreen = isVisibleOnScreen, onBannerShown = {}, onCarouselScrolled = {}, onPageChanged = {}, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt index 0b12f8cf7c..d46d64f0de 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt @@ -6,6 +6,7 @@ internal data class PromoBannersBlockUM( val userWalletId: String, val initialPage: Int, val banners: ImmutableList, + val isVisibleOnScreen: Boolean, val onBannerShown: (displayId: Int) -> Unit, val onCarouselScrolled: (displayId: Int) -> Unit, val onPageChanged: (displayId: Int) -> Unit, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt index 49cff50a0a..ad49debe78 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt @@ -28,8 +28,10 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = if (state.banners.size == 1) { val banner = state.banners.first() - LaunchedEffect(banner.displayId) { - state.onBannerShown(banner.displayId) + LaunchedEffect(banner.displayId, state.isVisibleOnScreen) { + if (state.isVisibleOnScreen) { + state.onBannerShown(banner.displayId) + } } SingleBanner( banner = banner, @@ -38,11 +40,7 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = } else { key(state.userWalletId) { BannersCarousel( - banners = state.banners, - initialPage = state.initialPage, - onBannerShown = state.onBannerShown, - onCarouselScroll = state.onCarouselScrolled, - onPageChange = state.onPageChanged, + state = state, modifier = modifier, ) } @@ -59,31 +57,25 @@ private fun SingleBanner(banner: PromoBannerNotificationUM, modifier: Modifier = } @Composable -private fun BannersCarousel( - banners: List, - initialPage: Int, - onBannerShown: (Int) -> Unit, - onCarouselScroll: (Int) -> Unit, - onPageChange: (Int) -> Unit, - modifier: Modifier = Modifier, -) { +private fun BannersCarousel(state: PromoBannersBlockUM, modifier: Modifier = Modifier) { val pagerState = rememberPagerState( - initialPage = initialPage, - pageCount = { banners.size }, + initialPage = state.initialPage, + pageCount = { state.banners.size }, ) - LaunchedEffect(pagerState, banners) { + LaunchedEffect(pagerState, state.banners, state.isVisibleOnScreen) { + if (!state.isVisibleOnScreen) return@LaunchedEffect + var previousPage = pagerState.currentPage snapshotFlow { pagerState.currentPage } .collect { page -> - banners.getOrNull(page)?.let { banner -> - onPageChange(banner.displayId) - onBannerShown(banner.displayId) - if (page == 1) { - // one-time event when user scrolls from first to second page, - // indicating that he has interacted with the carousel - onCarouselScroll(banner.displayId) + state.banners.getOrNull(page)?.let { banner -> + state.onPageChanged(banner.displayId) + state.onBannerShown(banner.displayId) + if (previousPage == 0 && page == 1) { + state.onCarouselScrolled(banner.displayId) } } + previousPage = page } } @@ -92,7 +84,7 @@ private fun BannersCarousel( horizontalAlignment = Alignment.CenterHorizontally, ) { SmoothHeightPager( - banners = banners, + banners = state.banners, pagerState = pagerState, modifier = Modifier.fillMaxWidth(), ) From 58259ab3723620fcb846a3f48b91bd3b6442c257 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 14:55:01 +0400 Subject: [PATCH 10/20] Updated on 2026-08-14 --- .../src/main/assets/configs/feature_toggles_config.json | 4 ++++ gradle/tangem_dependencies.toml | 2 +- .../com/tangem/blockchainsdk/WalletManagerFactoryCreator.kt | 2 ++ .../com/tangem/blockchainsdk/di/BlockchainSDKFactoryModule.kt | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index 98751c086c..b6fbd1d807 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -83,5 +83,9 @@ { "name": "SOLANA_SCALED_UI_AMOUNT_ENABLED", "version": "undefined" + }, + { + "name": "HEDERA_ERC20_ENABLED", + "version": "5.37" } ] diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index af40440304..94aa5668ec 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.37-1490" +tangemBlockchainSdk = "releases-5.37-1494" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.37-603" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/WalletManagerFactoryCreator.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/WalletManagerFactoryCreator.kt index 3de6c03bd1..2213a287ff 100644 --- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/WalletManagerFactoryCreator.kt +++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/WalletManagerFactoryCreator.kt @@ -25,6 +25,7 @@ internal class WalletManagerFactoryCreator @Inject constructor( private val blockchainSDKLogger: BlockchainSDKLogger, private val isSolanaTxHistoryEnabled: Boolean, private val isSolanaScaledUiAmountEnabled: Boolean, + private val isHederaErc20Enabled: Boolean, ) { fun create(config: BlockchainSdkConfig, blockchainProviderTypes: BlockchainProviderTypes): WalletManagerFactory { @@ -39,6 +40,7 @@ internal class WalletManagerFactoryCreator @Inject constructor( isPendingTransactionsEnabled = true, isSolanaTxHistoryEnabled = isSolanaTxHistoryEnabled, isSolanaScaledUiAmountEnabled = isSolanaScaledUiAmountEnabled, + isHederaErc20Enabled = isHederaErc20Enabled, ), blockchainDataStorage = blockchainDataStorage, loggers = listOf(blockchainSDKLogger), diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/di/BlockchainSDKFactoryModule.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/di/BlockchainSDKFactoryModule.kt index 9bdbd36f05..cd52d01c17 100644 --- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/di/BlockchainSDKFactoryModule.kt +++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/di/BlockchainSDKFactoryModule.kt @@ -103,6 +103,9 @@ internal object BlockchainSDKFactoryModule { isSolanaScaledUiAmountEnabled = featureTogglesManager.isFeatureEnabled( FeatureToggles.SOLANA_SCALED_UI_AMOUNT_ENABLED, ), + isHederaErc20Enabled = featureTogglesManager.isFeatureEnabled( + FeatureToggles.HEDERA_ERC20_ENABLED, + ), ) } } \ No newline at end of file From c4dd3f69044d7725c6f925c0d4653ec4d698c667 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 20:39:04 +0500 Subject: [PATCH 11/20] Updated on 2026-08-14 --- .../src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 6f704854d9..1f953197d9 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -448,6 +448,7 @@ internal class StateBuilder( selectionType = ProviderState.SelectionType.CLICK, onProviderClick = actions.onProviderClick, needApplyFCARestrictions = needApplyFCARestrictions, + permissionState = quoteModel.permissionState, ), priceImpact = priceImpact, tosState = createTosState(swapProvider), @@ -1188,6 +1189,7 @@ internal class StateBuilder( isNeedBestRateBadge: Boolean, onProviderClick: (String) -> Unit, needApplyFCARestrictions: Boolean, + permissionState: PermissionDataState, ): ProviderState { val rate = toTokenInfo.tokenAmount.value.calculateRate( fromTokenInfo.tokenAmount.value, @@ -1202,6 +1204,8 @@ internal class StateBuilder( val additionalBadge = when { needApplyFCARestrictions && isFCARestrictedProvider() -> ProviderState.AdditionalBadge.FCAWarningList + permissionState is PermissionDataState.PermissionReadyForRequest -> + ProviderState.AdditionalBadge.PermissionRequired isRecommended -> ProviderState.AdditionalBadge.Recommended isNeedBestRateBadge && isBestRate && !needApplyFCARestrictions -> ProviderState.AdditionalBadge.BestTrade else -> ProviderState.AdditionalBadge.Empty From b8ec236366e98d0dc5da34460ed2d674410e50b0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 15:58:18 +0000 Subject: [PATCH 12/20] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index b1d2bf912f..94aa5668ec 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,13 +5,13 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.36-1480" +tangemBlockchainSdk = "releases-5.37-1494" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.36-607" +tangemCardSdk = "releases-5.37-603" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ -tangemVico = "2.0.0-alpha.25-tangem12" +tangemVico = "tangem-master-21" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ -tangemHotSdk = "develop-549" +tangemHotSdk = "develop-550" #tangemHotSdk = "0.0.1" # Keep it! - used for local builds ^ From 60c9657ec7f8e683392f534f4a470ec0c1f36f78 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Apr 2026 19:00:32 +0300 Subject: [PATCH 13/20] Updated on 2026-08-14 --- .../tangem/features/feed/ui/feed/FeedList.kt | 5 +++- .../feed/ui/feed/components/MarketsBlock.kt | 2 -- .../impl/model/PromoBannersBlockModel.kt | 2 ++ .../impl/model/PromoBannersBlockUM.kt | 2 ++ .../promobanners/impl/ui/PromoBannersBlock.kt | 26 ++++++++++++++----- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt index 1c459a5e09..e69bccddd0 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/FeedList.kt @@ -130,7 +130,10 @@ private fun FeedListContent( feedListCallbacks = state.feedListCallbacks, ) - promoBannersBlockComponent?.Content(modifier = Modifier.padding(horizontal = 16.dp)) + promoBannersBlockComponent?.Content( + modifier = Modifier.padding(top = 12.dp, start = 16.dp, end = 16.dp), + ) + SpacerH(32.dp) NewsBlock( news = state.news, diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt index 832e2e4ea0..daf0b624ae 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/MarketsBlock.kt @@ -78,8 +78,6 @@ internal fun MarketBlock(marketChart: MarketChartUM?, feedListCallbacks: FeedLis modifier = Modifier.padding(horizontal = 16.dp), marketChart = currentChart, ) - - SpacerH(32.dp) } } null -> Unit diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt index 89a157c634..d4a633984f 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt @@ -91,6 +91,7 @@ internal class PromoBannersBlockModel @Inject constructor( initialPage = initialPage, banners = bannerUMs, isVisibleOnScreen = isVisibleOnScreen, + placeholder = params.placeholder, onBannerShown = ::onBannerShown, onCarouselScrolled = ::onCarouselScrolled, onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId }, @@ -123,6 +124,7 @@ internal class PromoBannersBlockModel @Inject constructor( initialPage = 0, banners = persistentListOf(), isVisibleOnScreen = isVisibleOnScreen, + placeholder = params.placeholder, onBannerShown = {}, onCarouselScrolled = {}, onPageChanged = {}, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt index d46d64f0de..e2adc41722 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt @@ -1,5 +1,6 @@ package com.tangem.features.promobanners.impl.model +import com.tangem.features.promobanners.api.PromoBannersBlockComponent import kotlinx.collections.immutable.ImmutableList internal data class PromoBannersBlockUM( @@ -7,6 +8,7 @@ internal data class PromoBannersBlockUM( val initialPage: Int, val banners: ImmutableList, val isVisibleOnScreen: Boolean, + val placeholder: PromoBannersBlockComponent.Placeholder, val onBannerShown: (displayId: Int) -> Unit, val onCarouselScrolled: (displayId: Int) -> Unit, val onPageChanged: (displayId: Int) -> Unit, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt index ad49debe78..5cebe96145 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt @@ -11,12 +11,14 @@ import androidx.compose.runtime.key import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.SubcomposeLayout import androidx.compose.ui.util.lerp import com.tangem.core.ui.components.SpacerH8 import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.pager.PagerIndicator import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.promobanners.api.PromoBannersBlockComponent.Placeholder import com.tangem.features.promobanners.impl.model.PromoBannerNotificationUM import com.tangem.features.promobanners.impl.model.PromoBannersBlockUM import kotlin.math.ceil @@ -26,6 +28,8 @@ import kotlin.math.floor internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = Modifier) { if (state.banners.isEmpty()) return + val containerColor = bannerContainerColor(state.placeholder) + if (state.banners.size == 1) { val banner = state.banners.first() LaunchedEffect(banner.displayId, state.isVisibleOnScreen) { @@ -35,12 +39,14 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = } SingleBanner( banner = banner, + containerColor = containerColor, modifier = modifier, ) } else { key(state.userWalletId) { BannersCarousel( state = state, + containerColor = containerColor, modifier = modifier, ) } @@ -48,16 +54,22 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = } @Composable -private fun SingleBanner(banner: PromoBannerNotificationUM, modifier: Modifier = Modifier) { +private fun bannerContainerColor(placeholder: Placeholder): Color = when (placeholder) { + Placeholder.MAIN -> TangemTheme.colors.background.primary + Placeholder.FEED -> TangemTheme.colors.background.action +} + +@Composable +private fun SingleBanner(banner: PromoBannerNotificationUM, containerColor: Color, modifier: Modifier = Modifier) { Notification( config = banner.config, modifier = modifier.fillMaxWidth(), - containerColor = TangemTheme.colors.background.primary, + containerColor = containerColor, ) } @Composable -private fun BannersCarousel(state: PromoBannersBlockUM, modifier: Modifier = Modifier) { +private fun BannersCarousel(state: PromoBannersBlockUM, containerColor: Color, modifier: Modifier = Modifier) { val pagerState = rememberPagerState( initialPage = state.initialPage, pageCount = { state.banners.size }, @@ -86,6 +98,7 @@ private fun BannersCarousel(state: PromoBannersBlockUM, modifier: Modifier = Mod SmoothHeightPager( banners = state.banners, pagerState = pagerState, + containerColor = containerColor, modifier = Modifier.fillMaxWidth(), ) @@ -109,6 +122,7 @@ private fun BannersCarousel(state: PromoBannersBlockUM, modifier: Modifier = Mod private fun SmoothHeightPager( banners: List, pagerState: PagerState, + containerColor: Color, modifier: Modifier = Modifier, ) { SubcomposeLayout(modifier = modifier) { constraints -> @@ -128,7 +142,7 @@ private fun SmoothHeightPager( Notification( config = banners[lowerPage].config, modifier = Modifier.fillMaxWidth(), - containerColor = TangemTheme.colors.background.primary, + containerColor = containerColor, ) }.first().measure(pageConstraints).height @@ -137,7 +151,7 @@ private fun SmoothHeightPager( Notification( config = banners[upperPage].config, modifier = Modifier.fillMaxWidth(), - containerColor = TangemTheme.colors.background.primary, + containerColor = containerColor, ) }.first().measure(pageConstraints).height } else { @@ -156,7 +170,7 @@ private fun SmoothHeightPager( Notification( config = banner.config, modifier = Modifier.fillMaxWidth(), - containerColor = TangemTheme.colors.background.primary, + containerColor = containerColor, ) } }.first().measure( From 179ee8f01b457fce452ff31f9aa67fc92a11693f Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 16 Apr 2026 13:48:29 +0500 Subject: [PATCH 14/20] Updated on 2026-08-14 --- .../subcomponents/destination/model/SendDestinationModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt index 18ff42ff9e..4ca07d90b2 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt @@ -82,6 +82,8 @@ internal class SendDestinationModel @Inject constructor( private val cryptoCurrency = params.cryptoCurrency private val userWalletId = params.userWalletId + // In "Send with swap" flow, these are addresses in the destination network (not the actual sender addresses). + // Self-send validation must be skipped for them, so use only with params.isAllowSelfSend. private val senderAddresses = MutableStateFlow>(emptyList()) private val validationJobHolder = JobHolder() @@ -208,7 +210,7 @@ internal class SendDestinationModel @Inject constructor( SendDestinationRecentListTransformer( cryptoCurrency = cryptoCurrency, senderAddress = senderAddresses.value.firstOrNull()?.address, - isSelfSendAvailable = isSelfSendAvailable, + isSelfSendAvailable = params.isAllowSelfSend || isSelfSendAvailable, destinationWalletList = destinationWalletList, txHistoryList = txHistoryList, isAccountsMode = isAccountsMode, From ffc2e8a6db5594eabdd3042728b7f5ee706c46c9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 16 Apr 2026 14:41:37 +0400 Subject: [PATCH 15/20] Updated on 2026-08-14 --- features/swap-v2/impl/build.gradle.kts | 5 + .../analytics/SwapAmountAnalyticsSender.kt | 38 +++++ .../v2/impl/amount/model/SwapAmountModel.kt | 20 ++- .../model/SwapNotificationsModel.kt | 34 ++++ .../SendWithSwapAnalyticsErrorMessages.kt | 11 ++ .../SwapAmountAnalyticsSenderTest.kt | 148 ++++++++++++++++++ 6 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSender.kt create mode 100644 features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/analytics/SendWithSwapAnalyticsErrorMessages.kt create mode 100644 features/swap-v2/impl/src/test/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSenderTest.kt diff --git a/features/swap-v2/impl/build.gradle.kts b/features/swap-v2/impl/build.gradle.kts index 612a39dcc8..76f57cbad9 100644 --- a/features/swap-v2/impl/build.gradle.kts +++ b/features/swap-v2/impl/build.gradle.kts @@ -92,4 +92,9 @@ dependencies { /** DI */ implementation(deps.hilt.android) kapt(deps.hilt.kapt) + + /** Test */ + testImplementation(deps.test.junit) + testImplementation(deps.test.truth) + testImplementation(deps.test.mockk) } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSender.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSender.kt new file mode 100644 index 0000000000..d6b20adde2 --- /dev/null +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSender.kt @@ -0,0 +1,38 @@ +package com.tangem.features.swap.v2.impl.amount.analytics + +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.express.models.ExpressError +import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM +import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents +import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticsErrorMessages + +internal class SwapAmountAnalyticsSender( + private val analyticsEventHandler: AnalyticsEventHandler, +) { + + private var lastSentErrorMessage: String? = null + + fun sendErrorIfNeeded(quotes: List, selectedQuote: SwapQuoteUM?) { + val errorMessage = resolveErrorMessage(quotes, selectedQuote) + if (errorMessage == lastSentErrorMessage) return + lastSentErrorMessage = errorMessage + if (errorMessage != null) { + analyticsEventHandler.send( + SendWithSwapAnalyticEvents.SendWithSwapError( + errorScreen = SendWithSwapAnalyticEvents.ErrorScreen.Amount, + message = errorMessage, + ), + ) + } + } + + private fun resolveErrorMessage(quotes: List, selectedQuote: SwapQuoteUM?): String? { + if (quotes.isEmpty()) return SendWithSwapAnalyticsErrorMessages.EXPRESS_QUOTE_NO_PROVIDERS + val error = (selectedQuote as? SwapQuoteUM.Error)?.expressError ?: return null + return when (error) { + is ExpressError.AmountError.TooSmallError -> SendWithSwapAnalyticsErrorMessages.MIN_AMOUNT + is ExpressError.AmountError.TooBigError -> SendWithSwapAnalyticsErrorMessages.MAX_AMOUNT + else -> "${SendWithSwapAnalyticsErrorMessages.EXPRESS_QUOTE}: code=${error.code}" + } + } +} \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt index dcf53ad59d..b033d4f8cf 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt @@ -46,6 +46,7 @@ import com.tangem.features.swap.v2.impl.amount.SwapAmountComponentParams import com.tangem.features.swap.v2.impl.amount.SwapAmountReduceListener import com.tangem.features.swap.v2.impl.amount.SwapAmountUpdateListener import com.tangem.features.swap.v2.impl.amount.analytics.SwapAmountAnalyticEvents +import com.tangem.features.swap.v2.impl.amount.analytics.SwapAmountAnalyticsSender import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountFieldUM import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM import com.tangem.features.swap.v2.impl.amount.model.converter.SwapQuoteUMConverter @@ -56,6 +57,7 @@ import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents.NoticeFixedRate.toAnalyticsRateType +import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticsErrorMessages import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.Debouncer import com.tangem.utils.coroutines.PeriodicTask @@ -120,7 +122,8 @@ internal class SwapAmountModel @Inject constructor( val rateInfoNavigation: SlotNavigation = SlotNavigation() private var isShowBestRateAnimation: Boolean = false - private var lastAmountScreenOpenedCurrencyId: CryptoCurrency.ID? = null + private var isAmountScreenOpenedSent: Boolean = false + private val amountAnalyticsSender = SwapAmountAnalyticsSender(analyticsEventHandler) private var autoUpdateSubscriberJob: Job? = null @@ -608,7 +611,7 @@ internal class SwapAmountModel @Inject constructor( @Suppress("NullableToStringCall") TangemLogger.e( """ - Invalid cryptocurrencies status: + Invalid cryptocurrencies status: | Primary -> $primaryStatus | Secondary -> $secondaryStatus """.trimIndent(), @@ -616,7 +619,8 @@ internal class SwapAmountModel @Inject constructor( analyticsEventHandler.send( SendWithSwapAnalyticEvents.SendWithSwapError( errorScreen = SendWithSwapAnalyticEvents.ErrorScreen.Amount, - message = "Invalid cryptocurrencies status: primary=$primaryStatus, secondary=$secondaryStatus", + message = "${SendWithSwapAnalyticsErrorMessages.INVALID_CRYPTOCURRENCIES_STATUS}: " + + "primary=$primaryStatus, secondary=$secondaryStatus", ), ) showErrorAlert(errorMessage = null) @@ -625,9 +629,9 @@ internal class SwapAmountModel @Inject constructor( } private fun sendAmountScreenOpenedIfNeeded(secondaryStatus: CryptoCurrencyStatus) { - val currencyId = secondaryStatus.currency.id - if (lastAmountScreenOpenedCurrencyId == currencyId) return - lastAmountScreenOpenedCurrencyId = currencyId + if (params !is SwapAmountComponentParams.AmountParams) return + if (isAmountScreenOpenedSent) return + isAmountScreenOpenedSent = true val content = uiState.value as? SwapAmountUM.Content ?: return @@ -778,6 +782,10 @@ internal class SwapAmountModel @Inject constructor( secondaryFiatRateUSD = secondaryFiatRateUSD, ), ) + if (params is SwapAmountComponentParams.AmountParams) { + val selectedQuote = (uiState.value as? SwapAmountUM.Content)?.selectedQuote + amountAnalyticsSender.sendErrorIfNeeded(quotes, selectedQuote) + } feeSelectorReloadTrigger.triggerUpdate() } } diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt index bbfb56b4ad..0031fd2efd 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/notifications/model/SwapNotificationsModel.kt @@ -17,6 +17,7 @@ import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsComponent import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsUpdateListener import com.tangem.features.swap.v2.impl.notifications.entity.SwapNotificationUM import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents +import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticsErrorMessages import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -44,6 +45,7 @@ internal class SwapNotificationsModel @Inject constructor( private val params: SwapNotificationsComponent.Params = paramsContainer.require() private var notificationData = params.swapNotificationData + private var lastSentErrorMessages: Set = emptySet() val uiState: StateFlow> field = MutableStateFlow>(persistentListOf()) @@ -110,6 +112,8 @@ internal class SwapNotificationsModel @Inject constructor( ) } } + + sendErrorAnalyticsIfNeeded(notifications) } private suspend fun MutableList.addDestinationTagRequiredNotification() { @@ -189,4 +193,34 @@ internal class SwapNotificationsModel @Inject constructor( add(notification) } + + private fun sendErrorAnalyticsIfNeeded(notifications: List) { + val currentErrors = notifications.mapNotNull { notification -> + when (notification) { + is SwapNotificationUM.Error.InsufficientFunds -> + SendWithSwapAnalyticsErrorMessages.INSUFFICIENT_BALANCE + is SwapNotificationUM.Error.MinimalAmountError -> + SendWithSwapAnalyticsErrorMessages.MIN_AMOUNT + is SwapNotificationUM.Error.MaximumAmountError -> + SendWithSwapAnalyticsErrorMessages.MAX_AMOUNT + is SwapNotificationUM.Warning.ExpressGeneralError -> + "${SendWithSwapAnalyticsErrorMessages.EXPRESS_QUOTE}: code=${notification.expressError.code}" + is NotificationUM.Error.DestinationTagRequired -> + SendWithSwapAnalyticsErrorMessages.DESTINATION_TAG_REQUIRED + else -> null + } + }.toSet() + + val newErrors = currentErrors - lastSentErrorMessages + lastSentErrorMessages = currentErrors + + newErrors.forEach { errorMessage -> + analyticsEventHandler.send( + SendWithSwapAnalyticEvents.SendWithSwapError( + errorScreen = SendWithSwapAnalyticEvents.ErrorScreen.Confirm, + message = errorMessage, + ), + ) + } + } } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/analytics/SendWithSwapAnalyticsErrorMessages.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/analytics/SendWithSwapAnalyticsErrorMessages.kt new file mode 100644 index 0000000000..610a9c1159 --- /dev/null +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/analytics/SendWithSwapAnalyticsErrorMessages.kt @@ -0,0 +1,11 @@ +package com.tangem.features.swap.v2.impl.sendviaswap.analytics + +internal object SendWithSwapAnalyticsErrorMessages { + const val INSUFFICIENT_BALANCE = "Error - Insufficient balance" + const val MIN_AMOUNT = "Error - Min amount" + const val MAX_AMOUNT = "Error - Max amount" + const val EXPRESS_QUOTE_NO_PROVIDERS = "Error - Express quote no providers found" + const val EXPRESS_QUOTE = "Error - Express quote" + const val DESTINATION_TAG_REQUIRED = "Error - Destination tag required" + const val INVALID_CRYPTOCURRENCIES_STATUS = "Error - Invalid cryptocurrencies status" +} \ No newline at end of file diff --git a/features/swap-v2/impl/src/test/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSenderTest.kt b/features/swap-v2/impl/src/test/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSenderTest.kt new file mode 100644 index 0000000000..26f07c6275 --- /dev/null +++ b/features/swap-v2/impl/src/test/java/com/tangem/features/swap/v2/impl/amount/analytics/SwapAmountAnalyticsSenderTest.kt @@ -0,0 +1,148 @@ +package com.tangem.features.swap.v2.impl.amount.analytics + +import com.google.common.truth.Truth.assertThat +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.domain.express.models.ExpressError +import com.tangem.domain.express.models.ExpressProvider +import com.tangem.domain.express.models.ExpressProviderType +import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM +import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents +import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticsErrorMessages +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import org.junit.Test +import java.math.BigDecimal + +class SwapAmountAnalyticsSenderTest { + + private val analyticsEventHandler = mockk(relaxed = true) + private val sender = SwapAmountAnalyticsSender(analyticsEventHandler) + + private val testProvider = ExpressProvider( + providerId = "test", + name = "Test Provider", + type = ExpressProviderType.CEX, + imageLarge = "", + termsOfUse = null, + privacyPolicy = null, + slippage = null, + ) + + @Test + fun `GIVEN empty quotes WHEN sendErrorIfNeeded THEN send no providers error`() { + val eventSlot = slot() + every { analyticsEventHandler.send(capture(eventSlot)) } returns Unit + + sender.sendErrorIfNeeded(quotes = emptyList(), selectedQuote = null) + + verify(exactly = 1) { analyticsEventHandler.send(any()) } + val event = eventSlot.captured as SendWithSwapAnalyticEvents.SendWithSwapError + assertThat(event.errorScreen).isEqualTo(SendWithSwapAnalyticEvents.ErrorScreen.Amount) + assertThat(event.message).isEqualTo(SendWithSwapAnalyticsErrorMessages.EXPRESS_QUOTE_NO_PROVIDERS) + } + + @Test + fun `GIVEN too small error quote WHEN sendErrorIfNeeded THEN send min amount error`() { + val errorQuote = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.AmountError.TooSmallError(code = 1001, amount = BigDecimal("0.01")), + ) + val eventSlot = slot() + every { analyticsEventHandler.send(capture(eventSlot)) } returns Unit + + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + + verify(exactly = 1) { analyticsEventHandler.send(any()) } + val event = eventSlot.captured as SendWithSwapAnalyticEvents.SendWithSwapError + assertThat(event.message).isEqualTo(SendWithSwapAnalyticsErrorMessages.MIN_AMOUNT) + } + + @Test + fun `GIVEN too big error quote WHEN sendErrorIfNeeded THEN send max amount error`() { + val errorQuote = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.AmountError.TooBigError(code = 1002, amount = BigDecimal("1000")), + ) + val eventSlot = slot() + every { analyticsEventHandler.send(capture(eventSlot)) } returns Unit + + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + + verify(exactly = 1) { analyticsEventHandler.send(any()) } + val event = eventSlot.captured as SendWithSwapAnalyticEvents.SendWithSwapError + assertThat(event.message).isEqualTo(SendWithSwapAnalyticsErrorMessages.MAX_AMOUNT) + } + + @Test + fun `GIVEN unknown express error WHEN sendErrorIfNeeded THEN send express quote error with code`() { + val errorQuote = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.InternalError(code = 500), + ) + val eventSlot = slot() + every { analyticsEventHandler.send(capture(eventSlot)) } returns Unit + + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + + verify(exactly = 1) { analyticsEventHandler.send(any()) } + val event = eventSlot.captured as SendWithSwapAnalyticEvents.SendWithSwapError + assertThat(event.message).isEqualTo("${SendWithSwapAnalyticsErrorMessages.EXPRESS_QUOTE}: code=500") + } + + @Test + fun `GIVEN content quote WHEN sendErrorIfNeeded THEN do not send analytics`() { + val contentQuote = mockk() + + sender.sendErrorIfNeeded(quotes = listOf(contentQuote), selectedQuote = contentQuote) + + verify(exactly = 0) { analyticsEventHandler.send(any()) } + } + + @Test + fun `GIVEN same error twice WHEN sendErrorIfNeeded THEN send analytics only once`() { + val errorQuote = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.AmountError.TooSmallError(code = 1001, amount = BigDecimal("0.01")), + ) + + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + + verify(exactly = 1) { analyticsEventHandler.send(any()) } + } + + @Test + fun `GIVEN error then different error WHEN sendErrorIfNeeded THEN send analytics twice`() { + val smallError = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.AmountError.TooSmallError(code = 1001, amount = BigDecimal("0.01")), + ) + val bigError = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.AmountError.TooBigError(code = 1002, amount = BigDecimal("1000")), + ) + + sender.sendErrorIfNeeded(quotes = listOf(smallError), selectedQuote = smallError) + sender.sendErrorIfNeeded(quotes = listOf(bigError), selectedQuote = bigError) + + verify(exactly = 2) { analyticsEventHandler.send(any()) } + } + + @Test + fun `GIVEN error then success then same error WHEN sendErrorIfNeeded THEN send analytics twice`() { + val errorQuote = SwapQuoteUM.Error( + provider = testProvider, + expressError = ExpressError.AmountError.TooSmallError(code = 1001, amount = BigDecimal("0.01")), + ) + val contentQuote = mockk() + + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + sender.sendErrorIfNeeded(quotes = listOf(contentQuote), selectedQuote = contentQuote) + sender.sendErrorIfNeeded(quotes = listOf(errorQuote), selectedQuote = errorQuote) + + verify(exactly = 2) { analyticsEventHandler.send(any()) } + } +} \ No newline at end of file From 8c9ae4842428ad800566cb20b8638cfe774cef99 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 16 Apr 2026 17:10:34 +0300 Subject: [PATCH 16/20] Updated on 2026-08-14 --- .../src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt b/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt index 7f1d0b8d98..b62a7c78ce 100644 --- a/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt +++ b/common/src/main/kotlin/com/tangem/common/TangemBlogUrlBuilder.kt @@ -25,7 +25,7 @@ object TangemBlogUrlBuilder { } data object SeedPhraseRiskySolution : Post { - override val path: String = "seed-phrase-a-risky-solution" + override val path: String = "seed-phrase-faq" } data object WhatWalletToChoose : Post { From c3a687213f14356201d35633bdde4e7c5c10bea6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 17 Apr 2026 16:20:14 +0500 Subject: [PATCH 17/20] Updated on 2026-08-14 --- .../tap/di/domain/AccountDomainModule.kt | 9 - .../DefaultPaymentAccountStatusFetcher.kt | 2 +- .../usecase/IsAccountsModeEnabledUseCase.kt | 35 --- .../IsAccountsModeEnabledUseCaseTest.kt | 159 ---------- .../status/di/AccountStatusUseCaseModule.kt | 8 + .../usecase/IsAccountsModeEnabledUseCase.kt | 50 ++++ .../status/utils/ExpandedAccountsHolder.kt | 2 +- .../IsAccountsModeEnabledUseCaseTest.kt | 272 ++++++++++++++++++ .../DefaultPortfolioSelectorController.kt | 2 +- .../selector/PortfolioSelectorModel.kt | 2 +- .../impl/model/MarketsPortfolioDelegate.kt | 2 +- features/nft/impl/build.gradle.kts | 2 +- .../collections/model/NFTCollectionsModel.kt | 2 +- .../nft/receive/model/NFTReceiveModel.kt | 2 +- .../entity/OnrampAddTokenUiBuilder.kt | 2 +- .../model/AvailableSwapPairsModel.kt | 2 +- .../swap/model/SwapSelectTokensModel.kt | 2 +- .../tokenlist/model/OnrampTokenListModel.kt | 2 +- .../features/send/v2/send/model/SendModel.kt | 2 +- .../send/v2/sendnft/model/NFTSendModel.kt | 2 +- .../destination/model/SendDestinationModel.kt | 2 +- .../impl/presentation/model/StakingModel.kt | 2 +- .../sendviaswap/model/SendWithSwapModel.kt | 2 +- .../choosetoken/api/SettingContextUseCase.kt | 2 +- .../tangem/feature/swap/model/SwapModel.kt | 2 +- .../model/WalletSettingsModel.kt | 2 +- .../model/OrganizeTokensModel.kt | 2 +- .../model/OrganizeTokensModelLegacy.kt | 2 +- .../wallet/child/wallet/model/WalletModel.kt | 2 +- .../account/AccountDependencies.kt | 2 +- .../connections/model/WcConnectionsModel.kt | 2 +- .../connections/model/WcPairModel.kt | 2 +- .../converter/WcPortfolioNameDelegate.kt | 2 +- 33 files changed, 357 insertions(+), 230 deletions(-) delete mode 100644 domain/account/src/main/java/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCase.kt delete mode 100644 domain/account/src/test/kotlin/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCaseTest.kt create mode 100644 domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt create mode 100644 domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt index 34a46c0524..023bc7c89a 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt @@ -6,7 +6,6 @@ import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.usecase.ArchiveCryptoPortfolioUseCase import com.tangem.domain.account.status.usecase.RecoverCryptoPortfolioUseCase import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher -import com.tangem.domain.account.supplier.MultiAccountListSupplier import com.tangem.domain.account.tokens.MainAccountTokensMigration import com.tangem.domain.account.usecase.* import com.tangem.feature.referral.data.ExternalReferralRepository @@ -91,14 +90,6 @@ internal object AccountDomainModule { return GetUnoccupiedAccountIndexUseCase(crudRepository = accountsCRUDRepository) } - @Provides - @Singleton - fun provideIsAccountsModeEnabledUseCase( - multiAccountListSupplier: MultiAccountListSupplier, - ): IsAccountsModeEnabledUseCase { - return IsAccountsModeEnabledUseCase(multiAccountListSupplier = multiAccountListSupplier) - } - @Provides @Singleton fun provideApplyAccountListSortingUseCase( diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt index 2802bbed8c..fa38de8fbd 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt @@ -106,7 +106,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor( private suspend fun fetchTangemPayAccountStatus(account: Account.Payment): PaymentAccountStatusValue { val prevResult = paymentAccountStatusesStore.getSyncOrNull(account.userWalletId) - if (prevResult == null || prevResult.value is PaymentAccountStatusValue.Error) { + if (prevResult == null || prevResult.value is PaymentAccountStatusValue.Error.Unavailable) { paymentAccountStatusesStore.store( userWalletId = account.userWalletId, status = AccountStatus.Payment(account = account, value = PaymentAccountStatusValue.Loading), diff --git a/domain/account/src/main/java/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCase.kt b/domain/account/src/main/java/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCase.kt deleted file mode 100644 index 735d837692..0000000000 --- a/domain/account/src/main/java/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCase.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.tangem.domain.account.usecase - -import com.tangem.domain.account.models.AccountList -import com.tangem.domain.account.supplier.MultiAccountListSupplier -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.map - -/** - * Use case to determine if the accounts mode is enabled. - * Accounts mode is considered enabled if any [AccountList] produced for the user's wallets contains at least two - * active accounts. - * - * @property multiAccountListSupplier supplier that provides a list of [AccountList]s for all user wallets - * -[REDACTED_AUTHOR] - */ -class IsAccountsModeEnabledUseCase( - private val multiAccountListSupplier: MultiAccountListSupplier, -) { - - operator fun invoke(): Flow { - return multiAccountListSupplier.invoke() - .map { accountsList -> accountsList.map(AccountList::activeAccounts).isModeEnabled() } - .distinctUntilChanged() - } - - suspend fun invokeSync(): Boolean { - return multiAccountListSupplier.getSyncOrNull(Unit) - ?.map(AccountList::activeAccounts) - ?.isModeEnabled() == true - } - - private fun List.isModeEnabled(): Boolean = any { it >= 2 } -} \ No newline at end of file diff --git a/domain/account/src/test/kotlin/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCaseTest.kt b/domain/account/src/test/kotlin/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCaseTest.kt deleted file mode 100644 index 71e7b32d89..0000000000 --- a/domain/account/src/test/kotlin/com/tangem/domain/account/usecase/IsAccountsModeEnabledUseCaseTest.kt +++ /dev/null @@ -1,159 +0,0 @@ -package com.tangem.domain.account.usecase - -import com.google.common.truth.Truth -import com.tangem.domain.account.models.AccountList -import com.tangem.domain.account.supplier.MultiAccountListSupplier -import io.mockk.clearMocks -import io.mockk.coEvery -import io.mockk.every -import io.mockk.mockk -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.Nested -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class IsAccountsModeEnabledUseCaseTest { - - private val multiAccountListSupplier: MultiAccountListSupplier = mockk() - - private val useCase = IsAccountsModeEnabledUseCase(multiAccountListSupplier = multiAccountListSupplier) - - @AfterEach - fun tearDown() { - clearMocks(multiAccountListSupplier) - } - - @Nested - @TestInstance(TestInstance.Lifecycle.PER_CLASS) - inner class Invoke { - - @Test - fun `returns false when supplier emits empty list`() = runTest { - // Arrange - every { multiAccountListSupplier.invoke() } returns flowOf(emptyList()) - - // Act - val actual = useCase.invoke().first() - - // Assert - Truth.assertThat(actual).isFalse() - } - - @Test - fun `returns false when supplier emits account list with one account`() = runTest { - // Arrange - val accountList = createAccountList(activeAccounts = 1) - every { multiAccountListSupplier.invoke() } returns flowOf(listOf(accountList)) - - // Act - val actual = useCase.invoke().first() - - // Assert - Truth.assertThat(actual).isFalse() - } - - @Test - fun `returns true when supplier emits account list with two accounts`() = runTest { - // Arrange - val accountList = createAccountList(activeAccounts = 2) - every { multiAccountListSupplier.invoke() } returns flowOf(listOf(accountList)) - - // Act - val actual = useCase.invoke().first() - - // Assert - Truth.assertThat(actual).isTrue() - } - - @Test - fun `returns true when supplier emits multiple account lists, one with two accounts`() = runTest { - // Arrange - val accountList1 = createAccountList(activeAccounts = 1) - val accountList2 = createAccountList(activeAccounts = 2) - every { multiAccountListSupplier.invoke() } returns flowOf(listOf(accountList1, accountList2)) - - // Act - val actual = useCase.invoke().first() - - // Assert - Truth.assertThat(actual).isTrue() - } - } - - @Nested - @TestInstance(TestInstance.Lifecycle.PER_CLASS) - inner class InvokeSync { - - @Test - fun `returns false when getSyncOrNull returns null`() = runTest { - // Arrange - coEvery { multiAccountListSupplier.getSyncOrNull(Unit, any()) } returns null - - // Act - val actual = useCase.invokeSync() - - // Assert - Truth.assertThat(actual).isFalse() - } - - @Test - fun `returns false when getSyncOrNull returns empty list`() = runTest { - // Arrange - coEvery { multiAccountListSupplier.getSyncOrNull(Unit, any()) } returns emptyList() - - // Act - val actual = useCase.invokeSync() - - // Assert - Truth.assertThat(actual).isFalse() - } - - @Test - fun `returns false when getSyncOrNull returns account list with one account`() = runTest { - // Arrange - val accountList = createAccountList(activeAccounts = 1) - coEvery { multiAccountListSupplier.getSyncOrNull(Unit, any()) } returns listOf(accountList) - - // Act - val actual = useCase.invokeSync() - - // Assert - Truth.assertThat(actual).isFalse() - } - - @Test - fun `returns true when getSyncOrNull returns account list with two accounts`() = runTest { - // Arrange - val accountList = createAccountList(activeAccounts = 2) - coEvery { multiAccountListSupplier.getSyncOrNull(Unit, any()) } returns listOf(accountList) - - // Act - val actual = useCase.invokeSync() - - // Assert - Truth.assertThat(actual).isTrue() - } - - @Test - fun `returns true when getSyncOrNull returns multiple account lists, one with two accounts`() = runTest { - // Arrange - val accountList1 = createAccountList(activeAccounts = 1) - val accountList2 = createAccountList(activeAccounts = 2) - coEvery { multiAccountListSupplier.getSyncOrNull(Unit, any()) } returns listOf(accountList1, accountList2) - - // Act - val actual = useCase.invokeSync() - - // Assert - Truth.assertThat(actual).isTrue() - } - } - - private fun createAccountList(activeAccounts: Int): AccountList = mockk { - every { this@mockk.activeAccounts } returns activeAccounts - } -} \ No newline at end of file diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/di/AccountStatusUseCaseModule.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/di/AccountStatusUseCaseModule.kt index befcbcbbb0..8318798036 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/di/AccountStatusUseCaseModule.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/di/AccountStatusUseCaseModule.kt @@ -48,6 +48,14 @@ internal object AccountStatusUseCaseModule { ) } + @Provides + @Singleton + fun provideIsAccountsModeEnabledUseCase( + multiAccountStatusListSupplier: MultiAccountStatusListSupplier, + ): IsAccountsModeEnabledUseCase { + return IsAccountsModeEnabledUseCase(multiAccountStatusListSupplier = multiAccountStatusListSupplier) + } + @Provides @Singleton fun provideGetCryptoCurrencyActionsUseCaseV2( diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt new file mode 100644 index 0000000000..1ae6967739 --- /dev/null +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt @@ -0,0 +1,50 @@ +package com.tangem.domain.account.status.usecase + +import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier +import com.tangem.domain.models.account.AccountStatus +import com.tangem.domain.models.account.PaymentAccountStatusValue +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map + +/** + * Use case to determine if the accounts mode is enabled. + * Accounts mode is considered enabled if any [com.tangem.domain.account.models.AccountStatusList] produced for the + * user's wallets has more than one [AccountStatus.CryptoPortfolio], or has a [AccountStatus.Payment] with any + + * + * @property multiAccountStatusListSupplier supplier that provides a list of + * [com.tangem.domain.account.models.AccountStatusList]s for all user wallets + * +[REDACTED_AUTHOR] + */ +class IsAccountsModeEnabledUseCase( + private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier, +) { + + operator fun invoke(): Flow { + return multiAccountStatusListSupplier.invoke() + .map { accountStatusLists -> accountStatusLists.any { it.accountStatuses.isModeEnabled() } } + .distinctUntilChanged() + } + + suspend fun invokeSync(): Boolean { + return multiAccountStatusListSupplier.getSyncOrNull(Unit) + ?.any { it.accountStatuses.isModeEnabled() } == true + } + + private fun List.isModeEnabled(): Boolean { + var cryptoPortfolioCount = 0 + for (status in this) { + when { + status is AccountStatus.CryptoPortfolio && ++cryptoPortfolioCount > 1 -> return true + status is AccountStatus.Payment && status.value.isActivePayment() -> return true + } + } + return false + } + + private fun PaymentAccountStatusValue.isActivePayment(): Boolean { + return this !is PaymentAccountStatusValue.NotCreated + } +} \ No newline at end of file diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/ExpandedAccountsHolder.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/ExpandedAccountsHolder.kt index 4a33fdf3b8..eb5e9abec1 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/ExpandedAccountsHolder.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/ExpandedAccountsHolder.kt @@ -4,7 +4,7 @@ import com.tangem.domain.account.models.AccountExpandedState import com.tangem.domain.account.models.AccountList import com.tangem.domain.account.repository.AccountsExpandedRepository import com.tangem.domain.account.supplier.SingleAccountListSupplier -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId diff --git a/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt b/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt new file mode 100644 index 0000000000..49a4a0bd50 --- /dev/null +++ b/domain/account/status/src/test/kotlin/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCaseTest.kt @@ -0,0 +1,272 @@ +package com.tangem.domain.account.status.usecase + +import com.google.common.truth.Truth +import com.tangem.domain.account.models.AccountStatusList +import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier +import com.tangem.domain.models.account.AccountStatus +import com.tangem.domain.models.account.PaymentAccountStatusValue +import io.mockk.clearMocks +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +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.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class IsAccountsModeEnabledUseCaseTest { + + private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier = mockk() + + private val useCase = IsAccountsModeEnabledUseCase(multiAccountStatusListSupplier = multiAccountStatusListSupplier) + + @AfterEach + fun tearDown() { + clearMocks(multiAccountStatusListSupplier) + } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + inner class Invoke { + + @Test + fun `returns false when supplier emits empty list`() = runTest { + every { multiAccountStatusListSupplier.invoke() } returns flowOf(emptyList()) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns false when single crypto portfolio account`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio()), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns true when two crypto portfolio accounts`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockCryptoPortfolio()), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when payment account is Loaded`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when payment account is Locked`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns false when payment account is NotCreated`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(PaymentAccountStatusValue.NotCreated)), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns true when payment account is UnderReview`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when payment account is IssuingCard`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when payment account is Loading`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(PaymentAccountStatusValue.Loading)), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when multiple status lists and one has two crypto portfolios`() = runTest { + val statusList1 = createAccountStatusList(statuses = listOf(mockCryptoPortfolio())) + val statusList2 = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockCryptoPortfolio()), + ) + every { multiAccountStatusListSupplier.invoke() } returns flowOf(listOf(statusList1, statusList2)) + + val actual = useCase.invoke().first() + + Truth.assertThat(actual).isTrue() + } + } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + inner class InvokeSync { + + @Test + fun `returns false when getSyncOrNull returns null`() = runTest { + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns null + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns false when getSyncOrNull returns empty list`() = runTest { + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns emptyList() + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns false when single crypto portfolio account`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio()), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns true when two crypto portfolio accounts`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockCryptoPortfolio()), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when payment account is Loaded`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when payment account is Locked`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns false when payment account is NotCreated`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(PaymentAccountStatusValue.NotCreated)), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isFalse() + } + + @Test + fun `returns true when payment account is UnderReview`() = runTest { + val statusList = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isTrue() + } + + @Test + fun `returns true when multiple status lists and one has loaded payment`() = runTest { + val statusList1 = createAccountStatusList(statuses = listOf(mockCryptoPortfolio())) + val statusList2 = createAccountStatusList( + statuses = listOf(mockCryptoPortfolio(), mockPayment(mockk())), + ) + coEvery { multiAccountStatusListSupplier.getSyncOrNull(Unit, any()) } returns listOf(statusList1, statusList2) + + val actual = useCase.invokeSync() + + Truth.assertThat(actual).isTrue() + } + } + + private fun mockCryptoPortfolio(): AccountStatus.CryptoPortfolio = mockk() + + private fun mockPayment(value: PaymentAccountStatusValue): AccountStatus.Payment = mockk { + every { this@mockk.value } returns value + } + + private fun createAccountStatusList(statuses: List): AccountStatusList = mockk { + every { accountStatuses } returns statuses + } +} \ No newline at end of file diff --git a/features/account/impl/src/main/java/com/tangem/features/account/selector/DefaultPortfolioSelectorController.kt b/features/account/impl/src/main/java/com/tangem/features/account/selector/DefaultPortfolioSelectorController.kt index c125505737..e2da9828c4 100644 --- a/features/account/impl/src/main/java/com/tangem/features/account/selector/DefaultPortfolioSelectorController.kt +++ b/features/account/impl/src/main/java/com/tangem/features/account/selector/DefaultPortfolioSelectorController.kt @@ -1,6 +1,6 @@ package com.tangem.features.account.selector -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.filterCryptoPortfolio diff --git a/features/account/impl/src/main/java/com/tangem/features/account/selector/PortfolioSelectorModel.kt b/features/account/impl/src/main/java/com/tangem/features/account/selector/PortfolioSelectorModel.kt index b70b65e101..58b5fd61ca 100644 --- a/features/account/impl/src/main/java/com/tangem/features/account/selector/PortfolioSelectorModel.kt +++ b/features/account/impl/src/main/java/com/tangem/features/account/selector/PortfolioSelectorModel.kt @@ -9,7 +9,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.filterCryptoPortfolio diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/details/portfolio/impl/model/MarketsPortfolioDelegate.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/details/portfolio/impl/model/MarketsPortfolioDelegate.kt index f10bf94e1f..7faa59b34f 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/details/portfolio/impl/model/MarketsPortfolioDelegate.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/market/details/portfolio/impl/model/MarketsPortfolioDelegate.kt @@ -10,7 +10,7 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.account.models.AccountStatusList import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2 -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/nft/impl/build.gradle.kts b/features/nft/impl/build.gradle.kts index 7db2bdc36d..be33a37a7f 100644 --- a/features/nft/impl/build.gradle.kts +++ b/features/nft/impl/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { implementation(projects.core.datasource) /** Domain modules */ - implementation(projects.domain.account) + implementation(projects.domain.account.status) implementation(projects.domain.wallets) implementation(projects.domain.appCurrency.models) implementation(projects.domain.appCurrency) diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt index 13fc9173de..0172c69c29 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt @@ -7,7 +7,7 @@ import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfi import com.tangem.core.ui.components.fields.InputManager import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.extensions.resourceReference -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase import com.tangem.domain.nft.GetNFTCollectionsUseCase import com.tangem.domain.nft.RefreshAllNFTUseCase diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt index f96d50af08..6deefd8ea5 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt @@ -17,7 +17,7 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.account.producer.SingleAccountProducer import com.tangem.domain.account.supplier.SingleAccountSupplier -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.TokenReceiveConfig import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.network.Network diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/entity/OnrampAddTokenUiBuilder.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/entity/OnrampAddTokenUiBuilder.kt index ac1f747c49..fe12663f1f 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/entity/OnrampAddTokenUiBuilder.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/entity/OnrampAddTokenUiBuilder.kt @@ -13,7 +13,7 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.iconResId import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.AccountStatus import com.tangem.features.onramp.hottokens.portfolio.OnrampAddTokenComponent import com.tangem.features.onramp.hottokens.portfolio.OnrampAddTokenComponent.AddHotCryptoData diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt index 23a6df2272..ed3d347418 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt @@ -17,7 +17,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt index dcf23013a0..cf05eb89cc 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt @@ -9,7 +9,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.components.token.state.TokenItemState import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.features.onramp.component.SwapSelectTokensComponent diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt index 0b7676b1e6..884058c33b 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt @@ -11,7 +11,7 @@ import com.tangem.core.ui.extensions.resourceReference 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.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt index de06ea2a08..9b4c0a31fa 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt @@ -18,7 +18,7 @@ import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.core.ui.utils.parseBigDecimalOrNull import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt index 54b8e11901..a0b35c9df4 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt @@ -15,7 +15,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.datasource.local.nft.converter.NFTSdkAssetConverter import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.feedback.GetWalletMetaInfoUseCase diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt index 4ca07d90b2..293f18bdc0 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt @@ -12,7 +12,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.currency.CryptoCurrency diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index ccceb6379c..abdb3b8c6c 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -36,7 +36,7 @@ import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.haptic.VibratorHapticManager import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt index 2ebed7f554..0ec7b02ecd 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt @@ -7,7 +7,7 @@ import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/api/SettingContextUseCase.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/api/SettingContextUseCase.kt index a40a2a311c..9eee2c081b 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/api/SettingContextUseCase.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/choosetoken/api/SettingContextUseCase.kt @@ -1,6 +1,6 @@ package com.tangem.feature.swap.choosetoken.api -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index 9acbb9438a..e0328dd545 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -38,7 +38,7 @@ import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase import com.tangem.domain.account.status.utils.CryptoCurrencyStatusOperations.getCryptoCurrencyStatus -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index 4391d1ca87..5ac502f555 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -25,7 +25,7 @@ import com.tangem.core.ui.message.EventMessageAction import com.tangem.core.ui.message.SnackbarMessage import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.domain.account.supplier.SingleAccountListSupplier -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.account.AccountId diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt index 6d6f148c84..d2607e3957 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModel.kt @@ -17,7 +17,7 @@ import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.usecase.ApplyTokenListSortingUseCase import com.tangem.domain.account.status.usecase.ToggleTokenListGroupingUseCase import com.tangem.domain.account.status.usecase.ToggleTokenListSortingUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModelLegacy.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModelLegacy.kt index 5a9359c88e..6e2ea1b370 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModelLegacy.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/model/OrganizeTokensModelLegacy.kt @@ -13,7 +13,7 @@ import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.usecase.ApplyTokenListSortingUseCase import com.tangem.domain.account.status.usecase.ToggleTokenListGroupingUseCase import com.tangem.domain.account.status.usecase.ToggleTokenListSortingUseCase -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 0c5b95efcd..5a2a395cfc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -15,7 +15,7 @@ import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.account.supplier.SingleAccountListSupplier -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.apptheme.GetAppThemeModeUseCase diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/account/AccountDependencies.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/account/AccountDependencies.kt index d30b9a4165..ec819b7869 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/account/AccountDependencies.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/account/AccountDependencies.kt @@ -4,7 +4,7 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.supplier.SingleAccountStatusSupplier import com.tangem.domain.account.status.utils.ExpandedAccountsHolder -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import javax.inject.Inject @ModelScoped diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt index cdccfa2ec0..b4fb74e59e 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcConnectionsModel.kt @@ -19,7 +19,7 @@ import com.tangem.core.ui.message.EventMessageAction import com.tangem.core.ui.message.SnackbarMessage import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.account.supplier.MultiAccountListSupplier -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.qrscanning.models.QrResultSource import com.tangem.domain.qrscanning.models.SourceType import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt index 36238a65fd..d51b17e8c5 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt @@ -21,7 +21,7 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.message.SnackbarMessage import com.tangem.core.ui.message.ToastMessage -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.network.Network diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcPortfolioNameDelegate.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcPortfolioNameDelegate.kt index cad34dfe8e..4f12adbf92 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcPortfolioNameDelegate.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcPortfolioNameDelegate.kt @@ -5,7 +5,7 @@ import com.tangem.common.ui.account.CryptoPortfolioIconConverter import com.tangem.common.ui.account.toUM import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference -import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase +import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.models.account.Account import com.tangem.domain.walletconnect.model.WcSession import dagger.assisted.Assisted From 02a90d4be3a569e44ee80134404326bd6a3253b9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 19 Apr 2026 23:59:39 +0500 Subject: [PATCH 18/20] Updated on 2026-08-14 --- .../DefaultTokenDetailsDeepLinkHandler.kt | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/deeplink/DefaultTokenDetailsDeepLinkHandler.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/deeplink/DefaultTokenDetailsDeepLinkHandler.kt index d375886c77..53c5cd58ec 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/deeplink/DefaultTokenDetailsDeepLinkHandler.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/deeplink/DefaultTokenDetailsDeepLinkHandler.kt @@ -20,6 +20,7 @@ import com.tangem.domain.models.wallet.isMultiCurrency import com.tangem.domain.notifications.models.NotificationType import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher import com.tangem.domain.tokens.wallet.WalletBalanceFetcher +import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.SelectWalletUseCase import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents @@ -45,6 +46,7 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor( private val walletDeepLinkActionTrigger: WalletDeepLinkActionTrigger, private val analyticsEventHandler: AnalyticsEventHandler, private val getUserWalletUseCase: GetUserWalletUseCase, + private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val walletBalanceFetcher: WalletBalanceFetcher, private val tangemPayFeatureToggles: TangemPayFeatureToggles, private val singleAccountListSupplier: SingleAccountListSupplier, @@ -63,15 +65,23 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor( scope.launch { val userWalletId = walletId?.let(::UserWalletId) - val userWallet = userWalletId?.let { getUserWalletUseCase(userWalletId) }?.getOrNull() + val selectedUserWallet = getSelectedWalletSyncUseCase().getOrNull() + val userWallet = if (userWalletId != null) { + getUserWalletUseCase(userWalletId).getOrNull() + } else { + selectedUserWallet + } // If wallet to select is null or locked, ignore deeplink if (userWallet == null || userWallet.isLocked) { TangemLogger.e("Error on getting user wallet") return@launch } - if (selectWalletUseCase(userWalletId).getOrNull() == null) { - TangemLogger.e("Error on selecting user wallet") - return@launch + if (userWalletId != null && selectedUserWallet?.walletId != userWalletId) { + val isSelectionFailed = selectWalletUseCase(userWalletId).getOrNull() == null + if (isSelectionFailed) { + TangemLogger.e("Error on selecting user wallet") + return@launch + } } val cryptoCurrency = findCryptoCurrency(userWallet = userWallet, networkId = networkId, tokenId = tokenId) From 84b2c6ffcd9b002149cc72087c414246af8b4750 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Apr 2026 12:29:21 +0300 Subject: [PATCH 19/20] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 1c95c2ee9a..498b0bcd0d 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 1c95c2ee9aaa0007ea203b1bd9477e874f8211be +Subproject commit 498b0bcd0d871ed60c43b5d44f646548a4f11d37 From 4eb3d80df44d4f961a5b40a8f2804db436cca1a7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Apr 2026 09:29:46 +0000 Subject: [PATCH 20/20] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 94aa5668ec..f1841ba8e2 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.37-1494" +tangemBlockchainSdk = "develop-1491" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.37-603" +tangemCardSdk = "develop-602" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "tangem-master-21" #tangemVico = "0.0.1" # Keep it! - used for local builds ^