diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 5f2e9a67e9..34d5e51c71 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -625,6 +625,8 @@ Le compte de destination est inactif. Envoyez %s ou plus pour activer le compte. Pour créer un compte, envoyez des fonds à cette adresse Le compte destinataire n\'a pas de Trustline pour l\'actif envoyé qu\'il tente d\'envoyer. + Obtenez 10 $ en BTC avec chaque wallet\nDépêchez-vous ! + Black Friday : jusqu\'à 30% de réduction Rejoignez maintenant Partagez votre code et gagnez 5 USDT par vente. Votre ami bénéficie de 10 % de réduction. Recevez des RÉCOMPENSES pour chaque ami ! diff --git a/core/ui/src/main/res/drawable/img_black_friday_promo.webp b/core/ui/src/main/res/drawable/img_black_friday_promo.webp new file mode 100644 index 0000000000..18ad834359 Binary files /dev/null and b/core/ui/src/main/res/drawable/img_black_friday_promo.webp differ 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 c8261d32ea..86c501406d 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 @@ -46,12 +46,17 @@ internal class DefaultPromoRepository( !referralRepository.isReferralParticipant(userWalletId) && shouldShow }.getOrDefault(false) PromoId.Sepa -> { - val isActive = getSepaPromoBanner()?.isActive ?: false + val isActive = getSepaPromoBanner()?.isActive == true isActive && shouldShow } PromoId.VisaPresale -> { - val isActive = getVisaPromoBanner()?.isActive ?: false + val isActive = getVisaPromoBanner()?.isActive == true + + isActive && shouldShow + } + PromoId.BlackFriday -> { + val isActive = getBlackFridayPromoBanner()?.isActive == true isActive && shouldShow } @@ -64,6 +69,7 @@ internal class DefaultPromoRepository( PromoId.Referral -> flowOf(false) PromoId.Sepa -> flowOf(false) PromoId.VisaPresale -> flowOf(false) + PromoId.BlackFriday -> flowOf(false) } } @@ -147,9 +153,18 @@ internal class DefaultPromoRepository( }.getOrNull() } + private suspend fun getBlackFridayPromoBanner(): PromoBanner? { + return runCatching(dispatchers.io) { + promoBannerConverter.convert( + tangemApi.getPromoBanner(BLACK_FRIDAY_NAME).getOrThrow(), + ) + }.getOrNull() + } + private companion object { const val SEPA_NAME = "sepa" const val VISA_NAME = "visa-waitlist" + const val BLACK_FRIDAY_NAME = "black-friday" const val STORIES_LOAD_DELAY = 1000L } } \ No newline at end of file diff --git a/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt b/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt index 452445b991..764871ed95 100644 --- a/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt +++ b/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt @@ -29,4 +29,5 @@ enum class PromoId { Referral, Sepa, VisaPresale, + BlackFriday, } \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt index 396e1d8e90..d5b48a464e 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt @@ -31,6 +31,7 @@ class ShouldShowPromoWalletUseCase( return when (promoId) { PromoId.Referral, PromoId.VisaPresale, + PromoId.BlackFriday, -> true PromoId.Sepa -> { val walletFirstUsageDate = settingsRepository.getWalletFirstUsageDate() diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt index 1dcd4490f4..e0c863bf61 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt @@ -7,9 +7,9 @@ sealed class PromoAnalyticsEvent( event: String, params: Map = mapOf(), ) : AnalyticsEvent(category = "Promotion", event = event, params = params) { - class NoticePromotionBanner( - source: AnalyticsParam.ScreensSources, - program: Program, + data class NoticePromotionBanner( + private val source: AnalyticsParam.ScreensSources, + private val program: Program, ) : PromoAnalyticsEvent( event = "Notice - Promotion Banner", params = mapOf( @@ -18,10 +18,10 @@ sealed class PromoAnalyticsEvent( ), ) - class PromotionBannerClicked( - source: AnalyticsParam.ScreensSources, - program: Program, - action: BannerAction, + data class PromotionBannerClicked( + private val source: AnalyticsParam.ScreensSources, + private val program: Program, + private val action: BannerAction, ) : PromoAnalyticsEvent( event = "Promo Banner Clicked", params = mapOf( @@ -58,5 +58,6 @@ sealed class PromoAnalyticsEvent( enum class Program(val programName: String) { Empty("Empty"), Sepa("Sepa"), + BlackFriday("Black Friday"), } } \ No newline at end of file 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 e078030757..e4f32d06b9 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 @@ -315,6 +315,11 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( action = PromotionBannerClicked.BannerAction.Closed, ) 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) 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" + "&utm_medium=banner" + "&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" } } \ 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 ab979acec8..b080fd487e 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 @@ -57,6 +57,10 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( source = AnalyticsParam.ScreensSources.Main, program = Program.Sepa, ) + is WalletNotification.BlackFridayPromo -> NoticePromotionBanner( + source = AnalyticsParam.ScreensSources.Main, + program = Program.BlackFriday, + ) is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo is WalletNotification.VisaPresalePromo -> VisaWaitlistPromo is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender] 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 5d05c74f9f..c2db89f8c8 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 @@ -103,6 +103,8 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( .distinctUntilChanged(), shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Sepa) .distinctUntilChanged(), + shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.BlackFriday) + .distinctUntilChanged(), notificationsRepository.getShouldShowNotification(NotificationId.EnablePushesReminderNotification.key) .distinctUntilChanged(), getAccessCodeSkippedUseCase(userWallet.walletId).distinctUntilChanged(), @@ -117,15 +119,23 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( val seedPhraseIssueStatus = array[3] as SeedPhraseNotificationsStatus val shouldShowVisaPromo = array[4] as Boolean val shouldShowSepaBanner = array[5] as Boolean - val shouldShowEnablePushesReminderNotification = array[6] as Boolean - val accessCodeSkipped = array[7] as Boolean + val shouldShowBlackFridayPromo = array[6] as Boolean + val shouldShowEnablePushesReminderNotification = array[7] as Boolean + val shouldAccessCodeSkipped = array[8] as Boolean buildList { addUsedOutdatedDataNotification(totalFiatBalance) addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents) - addFinishWalletActivationNotification(userWallet, totalFiatBalance, clickIntents, accessCodeSkipped) + addFinishWalletActivationNotification( + userWallet = userWallet, + totalFiatBalance = totalFiatBalance, + clickIntents = clickIntents, + shouldAccessCodeSkipped = shouldAccessCodeSkipped, + ) + + addBlackFridayPromoNotification(clickIntents, shouldShowBlackFridayPromo) addVisaPresalePromoNotification(clickIntents, shouldShowVisaPromo) @@ -300,6 +310,19 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( ) } + private fun MutableList.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.addSepaPromoNotification( userWallet: UserWallet, flattenCurrencies: Lce>, @@ -427,13 +450,13 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( userWallet: UserWallet, totalFiatBalance: Lce, clickIntents: WalletClickIntents, - accessCodeSkipped: Boolean, + shouldAccessCodeSkipped: Boolean, ) { if (userWallet !is UserWallet.Hot) return val isBackupExists = userWallet.backedUp val isAccessCodeRequired = userWallet.hotWalletId.authType == HotWalletId.AuthType.NoPassword && - !accessCodeSkipped + !shouldAccessCodeSkipped val shouldShowFinishActivation = !isBackupExists || isAccessCodeRequired val type = totalFiatBalance.fold( 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 638da3f2e3..4553d72fc9 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 @@ -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( val onCloseClick: () -> Unit, val onEnabledClick: () -> Unit, 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 172ab84fbe..d8b52ad1ad 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 @@ -22,29 +22,29 @@ internal fun LazyListScope.notifications(configs: ImmutableList // TODO develop promo banner general component - when (it) { + when (item) { is WalletNotification.SwapPromo -> { // Use it on new promo action } is WalletNotification.NoteMigration -> { NoteMigrationNotification( - config = it.config, + config = item.config, modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null), ) } is WalletNotification.FinishWalletActivation -> { Notification( - config = it.config, + config = item.config, modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null), ) } else -> { Notification( - config = it.config, + config = item.config, modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null), - iconTint = when (it) { + iconTint = when (item) { is WalletNotification.Critical -> TangemTheme.colors.icon.warning is WalletNotification.Informational -> TangemTheme.colors.icon.accent is WalletNotification.RateApp -> TangemTheme.colors.icon.attention @@ -52,6 +52,7 @@ internal fun LazyListScope.notifications(configs: ImmutableList TangemTheme.colors.text.attention else -> null }, + subtitleColor = TangemTheme.colors.text.secondary, ) } } diff --git a/tangem-android-tools b/tangem-android-tools index 92c1bfd312..3da4c865da 160000 --- a/tangem-android-tools +++ b/tangem-android-tools @@ -1 +1 @@ -Subproject commit 92c1bfd3123f0b2fd9e5a80b9d69bbc17a6e1160 +Subproject commit 3da4c865da5f2a61d5170357c60de4ddd8425815