Updated on 2026-08-14
This commit is contained in:
commit
9163a956aa
12 changed files with 106 additions and 21 deletions
|
|
@ -625,6 +625,8 @@
|
||||||
<string name="no_account_polkadot">Le compte de destination est inactif. Envoyez %s ou plus pour activer le compte.</string>
|
<string name="no_account_polkadot">Le compte de destination est inactif. Envoyez %s ou plus pour activer le compte.</string>
|
||||||
<string name="no_account_send_to_create">Pour créer un compte, envoyez des fonds à cette adresse</string>
|
<string name="no_account_send_to_create">Pour créer un compte, envoyez des fonds à cette adresse</string>
|
||||||
<string name="no_trustline_xlm_asset">Le compte destinataire n\'a pas de Trustline pour l\'actif envoyé qu\'il tente d\'envoyer.</string>
|
<string name="no_trustline_xlm_asset">Le compte destinataire n\'a pas de Trustline pour l\'actif envoyé qu\'il tente d\'envoyer.</string>
|
||||||
|
<string name="notification_black_friday_text">Obtenez 10 $ en BTC avec chaque wallet\nDépêchez-vous !</string>
|
||||||
|
<string name="notification_black_friday_title">Black Friday : jusqu\'à 30% de réduction</string>
|
||||||
<string name="notification_referral_promo_button">Rejoignez maintenant</string>
|
<string name="notification_referral_promo_button">Rejoignez maintenant</string>
|
||||||
<string name="notification_referral_promo_text">Partagez votre code et gagnez 5 USDT par vente. Votre ami bénéficie de 10 % de réduction.</string>
|
<string name="notification_referral_promo_text">Partagez votre code et gagnez 5 USDT par vente. Votre ami bénéficie de 10 % de réduction.</string>
|
||||||
<string name="notification_referral_promo_title">Recevez des RÉCOMPENSES pour chaque ami !</string>
|
<string name="notification_referral_promo_title">Recevez des RÉCOMPENSES pour chaque ami !</string>
|
||||||
|
|
|
||||||
BIN
core/ui/src/main/res/drawable/img_black_friday_promo.webp
Normal file
BIN
core/ui/src/main/res/drawable/img_black_friday_promo.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -46,12 +46,17 @@ internal class DefaultPromoRepository(
|
||||||
!referralRepository.isReferralParticipant(userWalletId) && shouldShow
|
!referralRepository.isReferralParticipant(userWalletId) && shouldShow
|
||||||
}.getOrDefault(false)
|
}.getOrDefault(false)
|
||||||
PromoId.Sepa -> {
|
PromoId.Sepa -> {
|
||||||
val isActive = getSepaPromoBanner()?.isActive ?: false
|
val isActive = getSepaPromoBanner()?.isActive == true
|
||||||
|
|
||||||
isActive && shouldShow
|
isActive && shouldShow
|
||||||
}
|
}
|
||||||
PromoId.VisaPresale -> {
|
PromoId.VisaPresale -> {
|
||||||
val isActive = getVisaPromoBanner()?.isActive ?: false
|
val isActive = getVisaPromoBanner()?.isActive == true
|
||||||
|
|
||||||
|
isActive && shouldShow
|
||||||
|
}
|
||||||
|
PromoId.BlackFriday -> {
|
||||||
|
val isActive = getBlackFridayPromoBanner()?.isActive == true
|
||||||
|
|
||||||
isActive && shouldShow
|
isActive && shouldShow
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +69,7 @@ internal class DefaultPromoRepository(
|
||||||
PromoId.Referral -> flowOf(false)
|
PromoId.Referral -> flowOf(false)
|
||||||
PromoId.Sepa -> flowOf(false)
|
PromoId.Sepa -> flowOf(false)
|
||||||
PromoId.VisaPresale -> flowOf(false)
|
PromoId.VisaPresale -> flowOf(false)
|
||||||
|
PromoId.BlackFriday -> flowOf(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,9 +153,18 @@ internal class DefaultPromoRepository(
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getBlackFridayPromoBanner(): PromoBanner? {
|
||||||
|
return runCatching(dispatchers.io) {
|
||||||
|
promoBannerConverter.convert(
|
||||||
|
tangemApi.getPromoBanner(BLACK_FRIDAY_NAME).getOrThrow(),
|
||||||
|
)
|
||||||
|
}.getOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val SEPA_NAME = "sepa"
|
const val SEPA_NAME = "sepa"
|
||||||
const val VISA_NAME = "visa-waitlist"
|
const val VISA_NAME = "visa-waitlist"
|
||||||
|
const val BLACK_FRIDAY_NAME = "black-friday"
|
||||||
const val STORIES_LOAD_DELAY = 1000L
|
const val STORIES_LOAD_DELAY = 1000L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,4 +29,5 @@ enum class PromoId {
|
||||||
Referral,
|
Referral,
|
||||||
Sepa,
|
Sepa,
|
||||||
VisaPresale,
|
VisaPresale,
|
||||||
|
BlackFriday,
|
||||||
}
|
}
|
||||||
|
|
@ -31,6 +31,7 @@ class ShouldShowPromoWalletUseCase(
|
||||||
return when (promoId) {
|
return when (promoId) {
|
||||||
PromoId.Referral,
|
PromoId.Referral,
|
||||||
PromoId.VisaPresale,
|
PromoId.VisaPresale,
|
||||||
|
PromoId.BlackFriday,
|
||||||
-> true
|
-> true
|
||||||
PromoId.Sepa -> {
|
PromoId.Sepa -> {
|
||||||
val walletFirstUsageDate = settingsRepository.getWalletFirstUsageDate()
|
val walletFirstUsageDate = settingsRepository.getWalletFirstUsageDate()
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ sealed class PromoAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = mapOf(),
|
||||||
) : AnalyticsEvent(category = "Promotion", event = event, params = params) {
|
) : AnalyticsEvent(category = "Promotion", event = event, params = params) {
|
||||||
class NoticePromotionBanner(
|
data class NoticePromotionBanner(
|
||||||
source: AnalyticsParam.ScreensSources,
|
private val source: AnalyticsParam.ScreensSources,
|
||||||
program: Program,
|
private val program: Program,
|
||||||
) : PromoAnalyticsEvent(
|
) : PromoAnalyticsEvent(
|
||||||
event = "Notice - Promotion Banner",
|
event = "Notice - Promotion Banner",
|
||||||
params = mapOf(
|
params = mapOf(
|
||||||
|
|
@ -18,10 +18,10 @@ sealed class PromoAnalyticsEvent(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
class PromotionBannerClicked(
|
data class PromotionBannerClicked(
|
||||||
source: AnalyticsParam.ScreensSources,
|
private val source: AnalyticsParam.ScreensSources,
|
||||||
program: Program,
|
private val program: Program,
|
||||||
action: BannerAction,
|
private val action: BannerAction,
|
||||||
) : PromoAnalyticsEvent(
|
) : PromoAnalyticsEvent(
|
||||||
event = "Promo Banner Clicked",
|
event = "Promo Banner Clicked",
|
||||||
params = mapOf(
|
params = mapOf(
|
||||||
|
|
@ -58,5 +58,6 @@ sealed class PromoAnalyticsEvent(
|
||||||
enum class Program(val programName: String) {
|
enum class Program(val programName: String) {
|
||||||
Empty("Empty"),
|
Empty("Empty"),
|
||||||
Sepa("Sepa"),
|
Sepa("Sepa"),
|
||||||
|
BlackFriday("Black Friday"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,6 +315,11 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
action = PromotionBannerClicked.BannerAction.Closed,
|
action = PromotionBannerClicked.BannerAction.Closed,
|
||||||
)
|
)
|
||||||
PromoId.VisaPresale -> PromoAnalyticsEvent.VisaWaitlistPromoDismiss
|
PromoId.VisaPresale -> PromoAnalyticsEvent.VisaWaitlistPromoDismiss
|
||||||
|
PromoId.BlackFriday -> PromotionBannerClicked(
|
||||||
|
source = AnalyticsParam.ScreensSources.Main,
|
||||||
|
program = Program.BlackFriday,
|
||||||
|
action = PromotionBannerClicked.BannerAction.Closed,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
@ -352,6 +357,16 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
analyticsEventHandler.send(PromoAnalyticsEvent.VisaWaitlistPromoJoin)
|
analyticsEventHandler.send(PromoAnalyticsEvent.VisaWaitlistPromoJoin)
|
||||||
urlOpener.openUrl(VISA_PROMO_LINK)
|
urlOpener.openUrl(VISA_PROMO_LINK)
|
||||||
}
|
}
|
||||||
|
PromoId.BlackFriday -> {
|
||||||
|
analyticsEventHandler.send(
|
||||||
|
PromotionBannerClicked(
|
||||||
|
source = AnalyticsParam.ScreensSources.Main,
|
||||||
|
program = Program.BlackFriday,
|
||||||
|
action = PromotionBannerClicked.BannerAction.Clicked,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
urlOpener.openUrl(BLACK_FRIDAY_PROMO_LINK)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,5 +606,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
const val VISA_PROMO_LINK = "https://tangem.com/en/cardwaitlist/?utm_source=tangem-app-banner" +
|
const val VISA_PROMO_LINK = "https://tangem.com/en/cardwaitlist/?utm_source=tangem-app-banner" +
|
||||||
"&utm_medium=banner" +
|
"&utm_medium=banner" +
|
||||||
"&utm_campaign=tangempaywaitlist"
|
"&utm_campaign=tangempaywaitlist"
|
||||||
|
const val BLACK_FRIDAY_PROMO_LINK = "https://tangem.com/en/pricing/" +
|
||||||
|
"?promocode=BF2025" +
|
||||||
|
"&utm_source=tangem-app-banner" +
|
||||||
|
"&utm_medium=banner" +
|
||||||
|
"&utm_campaign=BlackFriday2025"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,10 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
||||||
source = AnalyticsParam.ScreensSources.Main,
|
source = AnalyticsParam.ScreensSources.Main,
|
||||||
program = Program.Sepa,
|
program = Program.Sepa,
|
||||||
)
|
)
|
||||||
|
is WalletNotification.BlackFridayPromo -> NoticePromotionBanner(
|
||||||
|
source = AnalyticsParam.ScreensSources.Main,
|
||||||
|
program = Program.BlackFriday,
|
||||||
|
)
|
||||||
is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo
|
is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo
|
||||||
is WalletNotification.VisaPresalePromo -> VisaWaitlistPromo
|
is WalletNotification.VisaPresalePromo -> VisaWaitlistPromo
|
||||||
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
|
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,8 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
.distinctUntilChanged(),
|
.distinctUntilChanged(),
|
||||||
shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Sepa)
|
shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Sepa)
|
||||||
.distinctUntilChanged(),
|
.distinctUntilChanged(),
|
||||||
|
shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.BlackFriday)
|
||||||
|
.distinctUntilChanged(),
|
||||||
notificationsRepository.getShouldShowNotification(NotificationId.EnablePushesReminderNotification.key)
|
notificationsRepository.getShouldShowNotification(NotificationId.EnablePushesReminderNotification.key)
|
||||||
.distinctUntilChanged(),
|
.distinctUntilChanged(),
|
||||||
getAccessCodeSkippedUseCase(userWallet.walletId).distinctUntilChanged(),
|
getAccessCodeSkippedUseCase(userWallet.walletId).distinctUntilChanged(),
|
||||||
|
|
@ -117,15 +119,23 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
val seedPhraseIssueStatus = array[3] as SeedPhraseNotificationsStatus
|
val seedPhraseIssueStatus = array[3] as SeedPhraseNotificationsStatus
|
||||||
val shouldShowVisaPromo = array[4] as Boolean
|
val shouldShowVisaPromo = array[4] as Boolean
|
||||||
val shouldShowSepaBanner = array[5] as Boolean
|
val shouldShowSepaBanner = array[5] as Boolean
|
||||||
val shouldShowEnablePushesReminderNotification = array[6] as Boolean
|
val shouldShowBlackFridayPromo = array[6] as Boolean
|
||||||
val accessCodeSkipped = array[7] as Boolean
|
val shouldShowEnablePushesReminderNotification = array[7] as Boolean
|
||||||
|
val shouldAccessCodeSkipped = array[8] as Boolean
|
||||||
|
|
||||||
buildList {
|
buildList {
|
||||||
addUsedOutdatedDataNotification(totalFiatBalance)
|
addUsedOutdatedDataNotification(totalFiatBalance)
|
||||||
|
|
||||||
addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents)
|
addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents)
|
||||||
|
|
||||||
addFinishWalletActivationNotification(userWallet, totalFiatBalance, clickIntents, accessCodeSkipped)
|
addFinishWalletActivationNotification(
|
||||||
|
userWallet = userWallet,
|
||||||
|
totalFiatBalance = totalFiatBalance,
|
||||||
|
clickIntents = clickIntents,
|
||||||
|
shouldAccessCodeSkipped = shouldAccessCodeSkipped,
|
||||||
|
)
|
||||||
|
|
||||||
|
addBlackFridayPromoNotification(clickIntents, shouldShowBlackFridayPromo)
|
||||||
|
|
||||||
addVisaPresalePromoNotification(clickIntents, shouldShowVisaPromo)
|
addVisaPresalePromoNotification(clickIntents, shouldShowVisaPromo)
|
||||||
|
|
||||||
|
|
@ -300,6 +310,19 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun MutableList<WalletNotification>.addBlackFridayPromoNotification(
|
||||||
|
clickIntents: WalletClickIntents,
|
||||||
|
shouldShowPromo: Boolean,
|
||||||
|
) {
|
||||||
|
addIf(
|
||||||
|
element = WalletNotification.BlackFridayPromo(
|
||||||
|
onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.BlackFriday) },
|
||||||
|
onClick = { clickIntents.onPromoClick(promoId = PromoId.BlackFriday) },
|
||||||
|
),
|
||||||
|
condition = shouldShowPromo,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun MutableList<WalletNotification>.addSepaPromoNotification(
|
private suspend fun MutableList<WalletNotification>.addSepaPromoNotification(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
flattenCurrencies: Lce<TokenListError, List<CryptoCurrencyStatus>>,
|
flattenCurrencies: Lce<TokenListError, List<CryptoCurrencyStatus>>,
|
||||||
|
|
@ -427,13 +450,13 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
totalFiatBalance: Lce<TokenListError, TotalFiatBalance>,
|
totalFiatBalance: Lce<TokenListError, TotalFiatBalance>,
|
||||||
clickIntents: WalletClickIntents,
|
clickIntents: WalletClickIntents,
|
||||||
accessCodeSkipped: Boolean,
|
shouldAccessCodeSkipped: Boolean,
|
||||||
) {
|
) {
|
||||||
if (userWallet !is UserWallet.Hot) return
|
if (userWallet !is UserWallet.Hot) return
|
||||||
|
|
||||||
val isBackupExists = userWallet.backedUp
|
val isBackupExists = userWallet.backedUp
|
||||||
val isAccessCodeRequired = userWallet.hotWalletId.authType == HotWalletId.AuthType.NoPassword &&
|
val isAccessCodeRequired = userWallet.hotWalletId.authType == HotWalletId.AuthType.NoPassword &&
|
||||||
!accessCodeSkipped
|
!shouldAccessCodeSkipped
|
||||||
val shouldShowFinishActivation = !isBackupExists || isAccessCodeRequired
|
val shouldShowFinishActivation = !isBackupExists || isAccessCodeRequired
|
||||||
|
|
||||||
val type = totalFiatBalance.fold(
|
val type = totalFiatBalance.fold(
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,23 @@ sealed class WalletNotification(val config: NotificationConfig) {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class BlackFridayPromo(
|
||||||
|
val onCloseClick: () -> Unit,
|
||||||
|
val onClick: () -> Unit,
|
||||||
|
) : WalletNotification(
|
||||||
|
config = NotificationConfig(
|
||||||
|
title = resourceReference(R.string.notification_black_friday_title),
|
||||||
|
subtitle = resourceReference(R.string.notification_black_friday_text),
|
||||||
|
iconResId = R.drawable.img_black_friday_promo,
|
||||||
|
onCloseClick = onCloseClick,
|
||||||
|
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||||
|
text = resourceReference(R.string.common_claim),
|
||||||
|
onClick = onClick,
|
||||||
|
),
|
||||||
|
iconSize = 54.dp,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
data class PushNotifications(
|
data class PushNotifications(
|
||||||
val onCloseClick: () -> Unit,
|
val onCloseClick: () -> Unit,
|
||||||
val onEnabledClick: () -> Unit,
|
val onEnabledClick: () -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -22,29 +22,29 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
||||||
items = configs,
|
items = configs,
|
||||||
key = { it::class.java },
|
key = { it::class.java },
|
||||||
contentType = { it::class.java },
|
contentType = { it::class.java },
|
||||||
itemContent = {
|
itemContent = { item ->
|
||||||
// TODO develop promo banner general component
|
// TODO develop promo banner general component
|
||||||
when (it) {
|
when (item) {
|
||||||
is WalletNotification.SwapPromo -> {
|
is WalletNotification.SwapPromo -> {
|
||||||
// Use it on new promo action
|
// Use it on new promo action
|
||||||
}
|
}
|
||||||
is WalletNotification.NoteMigration -> {
|
is WalletNotification.NoteMigration -> {
|
||||||
NoteMigrationNotification(
|
NoteMigrationNotification(
|
||||||
config = it.config,
|
config = item.config,
|
||||||
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is WalletNotification.FinishWalletActivation -> {
|
is WalletNotification.FinishWalletActivation -> {
|
||||||
Notification(
|
Notification(
|
||||||
config = it.config,
|
config = item.config,
|
||||||
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Notification(
|
Notification(
|
||||||
config = it.config,
|
config = item.config,
|
||||||
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
||||||
iconTint = when (it) {
|
iconTint = when (item) {
|
||||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||||
|
|
@ -52,6 +52,7 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
||||||
is WalletNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
is WalletNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||||
else -> null
|
else -> null
|
||||||
},
|
},
|
||||||
|
subtitleColor = TangemTheme.colors.text.secondary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 92c1bfd3123f0b2fd9e5a80b9d69bbc17a6e1160
|
Subproject commit 3da4c865da5f2a61d5170357c60de4ddd8425815
|
||||||
Loading…
Add table
Add a link
Reference in a new issue