Updated on 2026-08-14
This commit is contained in:
parent
13c3b6d4e2
commit
2d2d157943
14 changed files with 105 additions and 8 deletions
|
|
@ -520,6 +520,9 @@
|
|||
<string name="nft_wallet_title">NFT collections</string>
|
||||
<string name="nft_wallet_unable_to_load">Unable to load the data</string>
|
||||
<string name="nft_receive_choose_network">Choose network</string>
|
||||
<string name="notification_referral_promo_button">Join Now</string>
|
||||
<string name="notification_referral_promo_text">Share your code - earn 5 USDT per sale. Your friend gets 10% OFF.</string>
|
||||
<string name="notification_referral_promo_title">Get REWARDS for every friend!</string>
|
||||
<string name="nft_details_last_sale_price">Last sale price</string>
|
||||
<string name="nft_details_rarity_label">Rarity label</string>
|
||||
<string name="nft_details_rarity_rank">Rarity rank</string>
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
|
||||
|
|
|
|||
BIN
core/ui/src/main/res/drawable/img_referral_promo.webp
Normal file
BIN
core/ui/src/main/res/drawable/img_referral_promo.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<Boolean> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<WalletNotification>.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<WalletNotification>.addWarningNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
tokenList: Lce<TokenListError, TokenList>,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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<WalletNotificati
|
|||
Notification(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
||||
iconSize = if (it is WalletNotification.ReferralPromo) {
|
||||
54.dp
|
||||
} else {
|
||||
20.dp
|
||||
},
|
||||
iconTint = when (it) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue