From b4b35916d97c8a8d671783ea9d787cdef12f8398 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Jan 2026 15:55:18 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/notifications/NotificationsFactory.kt | 4 +++- .../api/ResettableOneTimeEventSender.kt | 19 ++++++++++++++++++ ...GetBalanceNotEnoughForFeeWarningUseCase.kt | 13 ++++++++---- .../analytics/CommonSendFeeAnalyticEvents.kt | 7 +++++++ .../notifications/model/NotificationsModel.kt | 20 +++++++++++++------ .../AddStakingNotificationsTransformer.kt | 1 + .../model/YieldSupplyNotificationsModel.kt | 3 ++- 7 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 core/analytics/src/main/java/com/tangem/core/analytics/api/ResettableOneTimeEventSender.kt diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt index 01eea336aa..1cedf7d5b3 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt @@ -314,12 +314,14 @@ object NotificationsFactory { } } + @Suppress("LongParameterList") fun MutableList.addExceedsBalanceNotification( cryptoCurrencyWarning: CryptoCurrencyWarning?, cryptoCurrencyStatus: CryptoCurrencyStatus, shouldMergeFeeNetworkName: Boolean, onClick: (CryptoCurrency) -> Unit, onAnalyticsEvent: (CryptoCurrency) -> Unit, + onResetAnalyticsEvent: (CryptoCurrency) -> Unit, ) { when (cryptoCurrencyWarning) { is CryptoCurrencyWarning.BalanceNotEnoughForFee -> { @@ -357,7 +359,7 @@ object NotificationsFactory { ) onAnalyticsEvent(cryptoCurrencyWarning.currency) } - else -> Unit + else -> onResetAnalyticsEvent(cryptoCurrencyStatus.currency) } } diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/api/ResettableOneTimeEventSender.kt b/core/analytics/src/main/java/com/tangem/core/analytics/api/ResettableOneTimeEventSender.kt new file mode 100644 index 0000000000..0f774cb099 --- /dev/null +++ b/core/analytics/src/main/java/com/tangem/core/analytics/api/ResettableOneTimeEventSender.kt @@ -0,0 +1,19 @@ +package com.tangem.core.analytics.api + +import com.tangem.core.analytics.models.AnalyticsEvent +import java.util.concurrent.ConcurrentHashMap + +class ResettableOneTimeEventSender(val analyticsEventHandler: AnalyticsEventHandler) { + + private val sentEvents = ConcurrentHashMap() + + fun sendEventOnce(key: String, event: AnalyticsEvent) { + if (sentEvents[key] != null) return + analyticsEventHandler.send(event) + sentEvents[key] = event + } + + fun reset(key: String) { + sentEvents.remove(key) + } +} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetBalanceNotEnoughForFeeWarningUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetBalanceNotEnoughForFeeWarningUseCase.kt index 102ad31f39..4f7dbc4e74 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetBalanceNotEnoughForFeeWarningUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetBalanceNotEnoughForFeeWarningUseCase.kt @@ -40,7 +40,7 @@ class GetBalanceNotEnoughForFeeWarningUseCase( val feePaidCurrency = currenciesRepository.getFeePaidCurrency(userWalletId, tokenStatus.currency.network) val feeTokenBalance = feeStatus.value.amount ?: BigDecimal.ZERO - val isFeePaidByCoin = tokenStatus.currency is CryptoCurrency.Token + val isSendingCurrencyToken = tokenStatus.currency is CryptoCurrency.Token val isFeePaidByToken = feePaidCurrency is FeePaidCurrency.Token && tokenStatus.currency.id != feePaidCurrency.tokenId @@ -49,10 +49,15 @@ class GetBalanceNotEnoughForFeeWarningUseCase( feeStatus.currency is CryptoCurrency.Token val warning = when { + isFeePaidByGaslessToken && feeTokenBalance == BigDecimal.ZERO -> { + CryptoCurrencyWarning.BalanceNotEnoughForFee( + tokenCurrency = tokenStatus.currency, + coinCurrency = feeStatus.currency, + ) + } feePaidCurrency is FeePaidCurrency.Coin && - isFeePaidByCoin && - fee > feeTokenBalance && - !isFeePaidByGaslessToken -> { + isSendingCurrencyToken && + fee > feeTokenBalance -> { CryptoCurrencyWarning.BalanceNotEnoughForFee( tokenCurrency = tokenStatus.currency, coinCurrency = feeStatus.currency, diff --git a/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/subcomponents/feeSelector/analytics/CommonSendFeeAnalyticEvents.kt b/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/subcomponents/feeSelector/analytics/CommonSendFeeAnalyticEvents.kt index 92e455c7a7..1daa74b204 100644 --- a/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/subcomponents/feeSelector/analytics/CommonSendFeeAnalyticEvents.kt +++ b/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/subcomponents/feeSelector/analytics/CommonSendFeeAnalyticEvents.kt @@ -2,6 +2,7 @@ package com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TOKEN import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TYPE import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE @@ -21,6 +22,7 @@ sealed class CommonSendFeeAnalyticEvents( val feeType: AnalyticsParam.FeeType, val source: CommonSendSource, val feeToken: String, + val blockchain: String, ) : CommonSendFeeAnalyticEvents( category = categoryName, event = "Fee Selected", @@ -28,15 +30,20 @@ sealed class CommonSendFeeAnalyticEvents( FEE_TYPE to feeType.value, SOURCE to source.analyticsName, FEE_TOKEN to feeToken, + BLOCKCHAIN to blockchain, ), ) /** Custom fee selected */ data class CustomFeeButtonClicked( override val categoryName: String, + val blockchain: String, ) : CommonSendFeeAnalyticEvents( category = categoryName, event = "Custom Fee Clicked", + params = mapOf( + BLOCKCHAIN to blockchain, + ), ) /** Custom fee edited */ 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 87cb0d5f97..12d24c74f6 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 @@ -20,6 +20,7 @@ import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountE import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification import com.tangem.common.ui.notifications.NotificationsFactory.addValidateTransactionNotifications import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.api.ResettableOneTimeEventSender import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -82,6 +83,7 @@ internal class NotificationsModel @Inject constructor( private val feeCryptoCurrencyStatus = params.notificationData.feeCryptoCurrencyStatus private val currency = cryptoCurrencyStatus.currency private val appCurrency = params.appCurrency + private val resettableOneTimeEventSender = ResettableOneTimeEventSender(analyticsEventHandler) private var notificationData = params.notificationData @@ -250,13 +252,18 @@ internal class NotificationsModel @Inject constructor( shouldMergeFeeNetworkName = BlockchainUtils.isArbitrum(currency.network.backendId), onClick = ::showTokenDetails, onAnalyticsEvent = { - analyticsEventHandler.send( - NotificationsAnalyticEvents.NoticeNotEnoughFee( - categoryName = analyticsCategoryName, - token = cryptoCurrencyStatus.currency.symbol, - blockchain = cryptoCurrencyStatus.currency.network.name, - ), + val event = NotificationsAnalyticEvents.NoticeNotEnoughFee( + categoryName = analyticsCategoryName, + token = cryptoCurrencyStatus.currency.symbol, + blockchain = cryptoCurrencyStatus.currency.network.name, ) + resettableOneTimeEventSender.sendEventOnce( + key = EXCEEDS_BALANCE_EVENT, + event = event, + ) + }, + onResetAnalyticsEvent = { + resettableOneTimeEventSender.reset(EXCEEDS_BALANCE_EVENT) }, ) if (!BlockchainUtils.isCardano(currency.network.rawId)) { @@ -389,5 +396,6 @@ internal class NotificationsModel @Inject constructor( companion object { const val TRON_FEE_NOTIFICATION_MAX_SHOW_COUNT = 3 + private const val EXCEEDS_BALANCE_EVENT = "EXCEED_BALANCE_EVENT" } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt index 6477acf20c..5a13a69a4b 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt @@ -235,6 +235,7 @@ internal class AddStakingNotificationsTransformer( shouldMergeFeeNetworkName = BlockchainUtils.isArbitrum(network.backendId), onClick = prevState.clickIntents::openTokenDetails, onAnalyticsEvent = { prevState.clickIntents.onNotEnoughFeeNotificationShow() }, + onResetAnalyticsEvent = { /*no-op*/ }, ) if (!BlockchainUtils.isCardano(network.rawId)) { addDustWarningNotification( diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt index f6163ccc3c..122487f1e7 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt @@ -64,7 +64,8 @@ internal class YieldSupplyNotificationsModel @Inject constructor( blockchainId = cryptoCurrencyStatus.currency.network.backendId, ), onClick = ::openTokenDetails, - onAnalyticsEvent = { }, + onAnalyticsEvent = { /*no-op*/ }, + onResetAnalyticsEvent = { /*no-op*/ }, ) addFeeUnreachableNotification(