diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index a23e1b705f..48b2496729 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -520,6 +520,9 @@
NFT collections
Unable to load the data
Choose network
+ Join Now
+ Share your code - earn 5 USDT per sale. Your friend gets 10% OFF.
+ Get REWARDS for every friend!
Last sale price
Rarity label
Rarity rank
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt
index 7bd5322685..5d1f6b11fd 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt
@@ -25,6 +25,8 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
@@ -55,6 +57,7 @@ fun Notification(
subtitleColor: Color = TangemTheme.colors.text.tertiary,
containerColor: Color? = null,
iconTint: Color? = null,
+ iconSize: Dp = 20.dp,
isEnabled: Boolean = true,
) {
NotificationBaseContainer(
@@ -68,6 +71,7 @@ fun Notification(
MainContent(
iconResId = config.iconResId,
iconTint = iconTint,
+ iconSize = iconSize,
title = config.title,
subtitle = config.subtitle,
subtitleColor = subtitleColor,
@@ -127,6 +131,7 @@ internal fun NotificationBaseContainer(
private fun MainContent(
iconResId: Int,
iconTint: Color?,
+ iconSize: Dp,
title: TextReference?,
subtitle: TextReference,
subtitleColor: Color,
@@ -137,7 +142,7 @@ private fun MainContent(
iconResId = iconResId,
tint = iconTint,
modifier = Modifier
- .size(size = TangemTheme.dimens.size20)
+ .size(size = iconSize)
.align(alignment = Alignment.CenterVertically),
)
diff --git a/core/ui/src/main/res/drawable/img_referral_promo.webp b/core/ui/src/main/res/drawable/img_referral_promo.webp
new file mode 100644
index 0000000000..25a0af2e67
Binary files /dev/null and b/core/ui/src/main/res/drawable/img_referral_promo.webp differ
diff --git a/data/promo/build.gradle.kts b/data/promo/build.gradle.kts
index e2dd74f43c..7573a1e454 100644
--- a/data/promo/build.gradle.kts
+++ b/data/promo/build.gradle.kts
@@ -22,6 +22,7 @@ dependencies {
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.wallets.models)
+ implementation(projects.features.referral.domain)
implementation(projects.core.datasource)
implementation(projects.core.utils)
diff --git a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt
index 2c409f90fd..c80337d42b 100644
--- a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt
+++ b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt
@@ -14,9 +14,11 @@ import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.promo.models.PromoId
import com.tangem.domain.promo.models.StoryContent
import com.tangem.domain.wallets.models.UserWalletId
+import com.tangem.feature.referral.domain.ReferralRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
@@ -26,6 +28,7 @@ internal class DefaultPromoRepository(
private val appPreferencesStore: AppPreferencesStore,
private val promoStoriesStore: PromoStoriesStore,
private val dispatchers: CoroutineDispatcherProvider,
+ private val referralRepository: ReferralRepository,
) : PromoRepository {
private val storyContentConverter = StoryContentResponseConverter()
@@ -34,7 +37,13 @@ internal class DefaultPromoRepository(
return appPreferencesStore.get(
key = PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name),
default = true,
- )
+ ).map { shouldShow ->
+ if (promoId == PromoId.Referral) {
+ !referralRepository.isReferralParticipant(userWalletId) && shouldShow
+ } else {
+ shouldShow
+ }
+ }
}
override fun isReadyToShowTokenPromo(promoId: PromoId): Flow {
diff --git a/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt b/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt
index a564ef0509..69d489a2dc 100644
--- a/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt
+++ b/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt
@@ -5,6 +5,7 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.promo.PromoStoriesStore
import com.tangem.domain.promo.PromoRepository
+import com.tangem.feature.referral.domain.ReferralRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@@ -23,12 +24,14 @@ internal object PromoDataModule {
appPreferencesStore: AppPreferencesStore,
promoStoriesStore: PromoStoriesStore,
dispatchers: CoroutineDispatcherProvider,
+ referralRepository: ReferralRepository,
): PromoRepository {
return DefaultPromoRepository(
tangemApi = tangemTechApi,
appPreferencesStore = appPreferencesStore,
promoStoriesStore = promoStoriesStore,
dispatchers = dispatchers,
+ referralRepository = referralRepository,
)
}
}
\ No newline at end of file
diff --git a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt
index f33ab65ce4..714e0e29dc 100644
--- a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt
+++ b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt
@@ -39,6 +39,10 @@ internal class ReferralRepositoryImpl @Inject constructor(
}
}
+ override suspend fun isReferralParticipant(userWalletId: UserWalletId): Boolean {
+ return getReferralData(userWalletId.stringValue) is ReferralData.ParticipantData
+ }
+
override suspend fun startReferral(
walletId: String,
networkId: String,
diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt
index 760277f9f8..9c890ff038 100644
--- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt
+++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt
@@ -10,6 +10,9 @@ interface ReferralRepository {
/** Returns data object of [ReferralData] depends on user program status */
suspend fun getReferralData(walletId: String): ReferralData
+ /** Returns whether user is participating in referral program */
+ suspend fun isReferralParticipant(userWalletId: UserWalletId): Boolean
+
/** Starts user referral program */
suspend fun startReferral(walletId: String, networkId: String, tokenId: String, address: String): ReferralData
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt
index 2688e82b36..316ee31a8a 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt
@@ -2,6 +2,8 @@ package com.tangem.feature.wallet.child.wallet.model.intents
import arrow.core.getOrElse
import com.tangem.common.TangemBlogUrlBuilder
+import com.tangem.common.routing.AppRoute
+import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.di.ModelScoped
@@ -70,6 +72,8 @@ internal interface WalletWarningsClickIntents {
fun onClosePromoClick(promoId: PromoId)
+ fun onPromoClick(promoId: PromoId)
+
fun onSupportClick()
fun onNoteMigrationButtonClick(url: String)
@@ -106,6 +110,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
private val urlOpener: UrlOpener,
private val tokensFeatureToggles: TokensFeatureToggles,
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
+ private val appRouter: AppRouter,
) : BaseWalletClickIntents(), WalletWarningsClickIntents {
override fun onAddBackupCardClick() {
@@ -271,17 +276,32 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
override fun onClosePromoClick(promoId: PromoId) {
analyticsEventHandler.send(
- TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
- source = AnalyticsParam.ScreensSources.Main,
- programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
- action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
- ),
+ if (promoId == PromoId.Referral) {
+ MainScreen.ReferralPromoButtonDismiss
+ } else {
+ TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
+ source = AnalyticsParam.ScreensSources.Main,
+ programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
+ action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
+ )
+ },
)
modelScope.launch(dispatchers.main) {
shouldShowPromoWalletUseCase.neverToShow(promoId)
}
}
+ override fun onPromoClick(promoId: PromoId) {
+ if (promoId == PromoId.Referral) {
+ val userWallet = getSelectedUserWallet() ?: return
+ analyticsEventHandler.send(MainScreen.ReferralPromoButtonParticipate)
+ modelScope.launch {
+ shouldShowPromoWalletUseCase.neverToShow(promoId)
+ appRouter.push(AppRoute.ReferralProgram(userWalletId = userWallet.walletId))
+ }
+ }
+ }
+
override fun onSupportClick() {
val scanResponse = getSelectedUserWallet()?.scanResponse ?: return
val cardInfo = getCardInfoUseCase(scanResponse).getOrNull() ?: return
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt
index a07053ba04..523e8923de 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt
@@ -137,5 +137,11 @@ sealed class WalletScreenAnalyticsEvent {
data object NoticeSeedPhraseSupportButtonUsed : MainScreen(event = "Button - Support Used")
data object NoticeSeedPhraseSupportButtonDeclined : MainScreen(event = "Button - Support Declined")
+
+ // region Referral Promo
+ data object ReferralPromo : MainScreen(event = "Referral Banner")
+ data object ReferralPromoButtonParticipate : MainScreen(event = "Button - Referral Participate")
+ data object ReferralPromoButtonDismiss : MainScreen(event = "Button - Referral Dismiss")
+ //endregion
}
}
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt
index 36ed315d4b..0db4af387d 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt
@@ -53,6 +53,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
source = AnalyticsParam.ScreensSources.Main,
programName = ProgramName.Empty, // Use it on new promo action
)
+ is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
is WalletNotification.Informational.NoAccount,
is WalletNotification.Warning.LowSignatures,
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt
index 5ca74067c5..f50c6ea080 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt
@@ -6,6 +6,8 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.models.StatusSource
+import com.tangem.domain.promo.ShouldShowPromoWalletUseCase
+import com.tangem.domain.promo.models.PromoId
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.CryptoCurrency
@@ -34,6 +36,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
private val backupValidator: BackupValidator,
private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase,
+ private val shouldShowPromoWalletUseCase: ShouldShowPromoWalletUseCase,
) {
@Suppress("MagicNumber", "MaximumLineLength")
@@ -45,12 +48,15 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
flow2 = isReadyToShowRateAppUseCase(),
flow3 = isNeedToBackupUseCase(userWallet.walletId),
flow4 = seedPhraseNotificationUseCase(userWalletId = userWallet.walletId),
- ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, seedPhraseIssueStatus ->
+ flow5 = shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Referral),
+ ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, seedPhraseIssueStatus, shouldShowReferralPromo ->
buildList {
addUsedOutdatedDataNotification(maybeTokenList)
addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents)
+ addReferralPromoNotification(cardTypesResolver, clickIntents, shouldShowReferralPromo)
+
addInformationalNotifications(cardTypesResolver, maybeTokenList, clickIntents)
addWarningNotifications(cardTypesResolver, maybeTokenList, isNeedToBackup, clickIntents)
@@ -187,6 +193,20 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
.map(CryptoCurrencyStatus::currency)
}
+ private fun MutableList.addReferralPromoNotification(
+ cardTypesResolver: CardTypesResolver,
+ clickIntents: WalletClickIntents,
+ shouldShowPromo: Boolean,
+ ) {
+ addIf(
+ element = WalletNotification.ReferralPromo(
+ onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.Referral) },
+ onClick = { clickIntents.onPromoClick(promoId = PromoId.Referral) },
+ ),
+ condition = shouldShowPromo && cardTypesResolver.isTangemWallet(),
+ )
+ }
+
private fun MutableList.addWarningNotifications(
cardTypesResolver: CardTypesResolver,
tokenList: Lce,
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt
index 203a35a3a8..8315a590cd 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt
@@ -254,4 +254,20 @@ sealed class WalletNotification(val config: NotificationConfig) {
iconResId = R.drawable.ic_error_sync_24,
),
)
+
+ data class ReferralPromo(
+ val onCloseClick: () -> Unit,
+ val onClick: () -> Unit,
+ ) : WalletNotification(
+ config = NotificationConfig(
+ title = resourceReference(R.string.notification_referral_promo_title),
+ subtitle = resourceReference(R.string.notification_referral_promo_text),
+ iconResId = R.drawable.img_referral_promo,
+ onCloseClick = onCloseClick,
+ buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
+ text = resourceReference(R.string.notification_referral_promo_button),
+ onClick = onClick,
+ ),
+ ),
+ )
}
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt
index 211ce57e2d..0227a5339a 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt
@@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.notifications.NoteMigrationNotification
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.res.TangemTheme
@@ -38,6 +39,11 @@ internal fun LazyListScope.notifications(configs: ImmutableList TangemTheme.colors.icon.warning
is WalletNotification.Informational -> TangemTheme.colors.icon.accent