From 353efc2c213f6c22a4c335448ad0fa1a1e3d7ce4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 3 Jul 2024 18:36:02 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../core/analytics/models/AnalyticsParam.kt | 1 + .../local/preferences/PreferencesKeys.kt | 16 +- core/res/src/main/res/values-ru/strings.xml | 2 + core/res/src/main/res/values/strings.xml | 2 + .../notifications/OkxPromoNotification.kt | 163 ++++++++++++++++++ .../com/tangem/core/ui/res/TangemColors.kt | 2 + .../main/res/drawable/img_okx_dex_logo.xml | 29 ++++ .../data/promo/DefaultPromoRepository.kt | 10 ++ .../DefaultPromoSettingsRepository.kt | 12 +- .../analytics/TokenSwapPromoAnalyticsEvent.kt | 41 ++++- .../tokens/GetCurrencyWarningsUseCase.kt | 2 +- .../tokens/repository/PromoRepository.kt | 2 + ...okenDetailsNotificationsAnalyticsSender.kt | 7 +- .../components/TokenDetailsNotification.kt | 18 +- .../tokendetails/ui/TokenDetailsScreen.kt | 4 +- .../viewmodels/TokenDetailsViewModel.kt | 17 +- .../analytics/WalletScreenAnalyticsEvent.kt | 34 ---- .../utils/WalletWarningsAnalyticsSender.kt | 11 +- .../domain/GetMultiWalletWarningsFactory.kt | 22 ++- .../wallet/state/model/WalletNotification.kt | 18 +- .../components/common/WalletNotifications.kt | 4 +- .../intents/WalletWarningsClickIntents.kt | 21 ++- 22 files changed, 329 insertions(+), 109 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt create mode 100644 core/ui/src/main/res/drawable/img_okx_dex_logo.xml diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index b77078a426..c7c73612f8 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -64,6 +64,7 @@ sealed class AnalyticsParam { data object Send : ScreensSources("Send") data object Intro : ScreensSources("Introduction") data object MyWallets : ScreensSources("My Wallets") + data object Token : ScreensSources("Token") } sealed class TxSentFrom(val value: String) { diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index e069422752..52b037fd6d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -53,14 +53,6 @@ object PreferencesKeys { val LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY by lazy { stringPreferencesKey(name = "lastSwappedCryptoCurrency") } - val IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY by lazy { - booleanPreferencesKey(name = "isWalletSwapPromoChangellyShown") - } - - val IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY by lazy { - booleanPreferencesKey(name = "isTokenSwapPromoChangellyShown") - } - val IS_WALLET_TRAVALA_PROMO_SHOWN_KEY by lazy { booleanPreferencesKey(name = "isWalletTravalaPromoShown") } @@ -93,6 +85,14 @@ object PreferencesKeys { val IS_WALLET_NAMES_MIGRATION_DONE_KEY by lazy { booleanPreferencesKey(name = "isWalletNamesMigrationDone") } + val IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY by lazy { + booleanPreferencesKey(name = "isWalletSwapPromoOkxShown") + } + + val IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY by lazy { + booleanPreferencesKey(name = "isTokenSwapPromoOkxShown") + } + fun getStart2CoinTOSAcceptedKey(region: String?) = booleanPreferencesKey(name = "start2Coin_tos_accepted_$region") } diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 4772a93753..453bf3dd9b 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -550,6 +550,8 @@ Встречайте Tangem Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах Поддержка Web 3.0 + Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке. + Новый провайдер обмена! В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %s от биржи обратно на адрес пользователя В сумму включена комиссия провайдера сервиса. Комиссии diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 6a39461d9a..c712fdab72 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -543,6 +543,8 @@ Meet Tangem Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services Web 3.0 Compatible + Exchange more tokens at better rates directly in your wallet. + New Swap Provider Available! The amount includes:\n• service provider\'s fee\n• network fee for sending %s from the exchange back to the user\'s address. The amount includes the service provider\'s fee. Fees diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt new file mode 100644 index 0000000000..9d6d403946 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt @@ -0,0 +1,163 @@ +package com.tangem.core.ui.components.notifications + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.material.ripple.rememberRipple +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import com.tangem.core.ui.R +import com.tangem.core.ui.components.buttons.common.TangemButton +import com.tangem.core.ui.components.buttons.common.TangemButtonColors +import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.res.LocalIsInDarkTheme +import com.tangem.core.ui.res.TangemColorPalette.Dark6 +import com.tangem.core.ui.res.TangemColorPalette.Light4 +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview + +private val OxkPromoColor = Color(0xFFBCFF2F) + +@Composable +fun OkxPromoNotification(config: NotificationConfig, modifier: Modifier = Modifier) { + Column( + modifier + .clip(TangemTheme.shapes.roundedCornersXMedium) + .background(Dark6), + ) { + Content(config = config) + Button(config = config) + } +} + +@Composable +private fun Content(config: NotificationConfig) { + Row { + Icon( + painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.img_okx_dex_logo)), + contentDescription = null, + tint = TangemTheme.colors.icon.constant, + modifier = Modifier + .padding(start = TangemTheme.dimens.spacing12) + .align(Alignment.CenterVertically), + ) + Column( + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), + modifier = Modifier + .weight(1f) + .padding(TangemTheme.dimens.spacing12), + ) { + Text( + text = config.title.resolveReference(), + style = TangemTheme.typography.button, + color = OxkPromoColor, + ) + Text( + text = config.subtitle.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.constantWhite, + ) + } + config.onCloseClick?.let { + Icon( + painter = rememberVectorPainter( + image = ImageVector.vectorResource(R.drawable.ic_close_24), + ), + contentDescription = null, + tint = TangemTheme.colors.icon.constant, + modifier = + Modifier + .padding( + top = TangemTheme.dimens.spacing8, + end = TangemTheme.dimens.spacing8, + ) + .size(TangemTheme.dimens.size20) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(radius = TangemTheme.dimens.radius10), + onClick = it, + ), + ) + } + } +} + +@Composable +private fun Button(config: NotificationConfig) { + val button = config.buttonsState as? NotificationConfig.ButtonsState.SecondaryButtonConfig + + button?.let { + val isDarkMode = LocalIsInDarkTheme.current + TangemButton( + text = button.text.resolveReference(), + icon = TangemButtonIconPosition.Start(button.iconResId ?: R.drawable.ic_exchange_vertical_24), + onClick = button.onClick, + colors = TangemButtonColors( + backgroundColor = if (isDarkMode) Light4 else TangemTheme.colors.button.secondary, + contentColor = Dark6, + disabledBackgroundColor = TangemTheme.colors.button.disabled, + disabledContentColor = TangemTheme.colors.text.disabled, + ), + enabled = true, + showProgress = false, + modifier = Modifier + .fillMaxWidth() + .padding( + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing12, + ), + ) + } +} + +// region Preview +@Preview(widthDp = 360) +@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun OkxPromoNotification_Preview( + @PreviewParameter(OkxPromoNotificationPreviewProvider::class) data: NotificationConfig, +) { + TangemThemePreview { + OkxPromoNotification(data) + } +} + +private class OkxPromoNotificationPreviewProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + NotificationConfig( + title = resourceReference(R.string.swap_promo_title), + subtitle = resourceReference(R.string.swap_promo_text), + iconResId = R.drawable.img_okx_dex_logo, + onCloseClick = {}, + ), + NotificationConfig( + title = resourceReference(R.string.swap_promo_title), + subtitle = resourceReference(R.string.swap_promo_text), + iconResId = R.drawable.img_okx_dex_logo, + onCloseClick = {}, + buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( + text = resourceReference(R.string.token_swap_promotion_button), + onClick = {}, + ), + ), + ) +} +// endregion \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemColors.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemColors.kt index 451207be18..2a78787608 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemColors.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemColors.kt @@ -101,6 +101,7 @@ class TangemColors internal constructor( private set var attention by mutableStateOf(attention) private set + var constant by mutableStateOf(constant) fun update(other: Icon) { primary1 = other.primary1 @@ -111,6 +112,7 @@ class TangemColors internal constructor( accent = other.accent warning = other.warning attention = other.attention + constant = other.constant } } diff --git a/core/ui/src/main/res/drawable/img_okx_dex_logo.xml b/core/ui/src/main/res/drawable/img_okx_dex_logo.xml new file mode 100644 index 0000000000..3a4ba80759 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_okx_dex_logo.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 a92a4f5eb9..94a184fb73 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 @@ -32,8 +32,18 @@ internal class DefaultPromoRepository( }.getOrNull() } + override suspend fun getOkxPromoBanner(): PromoBanner? { + return runCatching(dispatchers.io) { + promoResponseConverter.convert( + tangemApi.getPromotionInfo(OKX) + .getOrThrow(), + ) + }.getOrNull() + } + private companion object { private const val CHANGELLY_NAME = "changelly" private const val TRAVALA = "travala" + private const val OKX = "okx" } } \ No newline at end of file diff --git a/data/settings/src/main/java/com/tangem/data/settings/DefaultPromoSettingsRepository.kt b/data/settings/src/main/java/com/tangem/data/settings/DefaultPromoSettingsRepository.kt index 80ba44157d..ce6d3fa236 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/DefaultPromoSettingsRepository.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/DefaultPromoSettingsRepository.kt @@ -1,8 +1,8 @@ package com.tangem.data.settings import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.preferences.PreferencesKeys.IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY -import com.tangem.datasource.local.preferences.PreferencesKeys.IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY import com.tangem.datasource.local.preferences.PreferencesKeys.IS_WALLET_TRAVALA_PROMO_SHOWN_KEY import com.tangem.datasource.local.preferences.utils.get import com.tangem.datasource.local.preferences.utils.store @@ -16,23 +16,23 @@ class DefaultPromoSettingsRepository( private val appPreferencesStore: AppPreferencesStore, ) : PromoSettingsRepository { override fun isReadyToShowWalletSwapPromo(): Flow { - return appPreferencesStore.get(IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY, true) + return appPreferencesStore.get(IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY, true) } override fun isReadyToShowTokenSwapPromo(): Flow { - return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY, true) + return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY, true) } override suspend fun setNeverToShowWalletSwapPromo() { appPreferencesStore.store( - key = IS_WALLET_SWAP_PROMO_CHANGELLY_SHOW_KEY, + key = IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY, value = false, ) } override suspend fun setNeverToShowTokenSwapPromo() { appPreferencesStore.store( - key = IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY, + key = IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY, value = false, ) } diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenSwapPromoAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenSwapPromoAnalyticsEvent.kt index cc39985633..9e9156c366 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenSwapPromoAnalyticsEvent.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/analytics/TokenSwapPromoAnalyticsEvent.kt @@ -1,18 +1,43 @@ package com.tangem.domain.tokens.models.analytics import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam sealed class TokenSwapPromoAnalyticsEvent( event: String, params: Map = mapOf(), -) : AnalyticsEvent("Swap Promo", event, params, null) { - - object Close : TokenSwapPromoAnalyticsEvent(event = "Button - Close") - - class Exchange( - token: String, +) : AnalyticsEvent(category = "Promotion", event = event, params = params) { + class NoticePromotionBanner( + source: AnalyticsParam.ScreensSources, + programName: ProgramName, ) : TokenSwapPromoAnalyticsEvent( - event = "Button - Exchange Now", - params = mapOf("Token" to token), + event = "Notice - Promotion Banner", + params = mapOf( + AnalyticsParam.SOURCE to source.value, + "Program Name" to programName.name, + ), ) + + class PromotionBannerClicked( + source: AnalyticsParam.ScreensSources, + programName: ProgramName, + action: BannerAction, + ) : TokenSwapPromoAnalyticsEvent( + event = "Promo Banner Clicked", + params = mapOf( + AnalyticsParam.SOURCE to source.value, + "Program Name" to programName.name, + "Action" to action.action, + ), + ) { + sealed class BannerAction(val action: String) { + data object Clicked : BannerAction(action = "Clicked") + data object Closed : BannerAction(action = "Closed") + } + } + + enum class ProgramName { + Travala, + OKX, + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index eb7296acea..93ff397011 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -84,7 +84,7 @@ class GetCurrencyWarningsUseCase( ): Flow { val currency = currencyStatus.currency val cryptoStatuses = operations.getCurrenciesStatusesSync() - val promoBanner = promoRepository.getChangellyPromoBanner() + val promoBanner = promoRepository.getOkxPromoBanner() return combine( showSwapPromoTokenUseCase().conflate(), flowOf(marketCryptoCurrencyRepository.isExchangeable(userWalletId, currency)).conflate(), diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt index ed42ab1cfc..51ba0a57f9 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/PromoRepository.kt @@ -7,4 +7,6 @@ interface PromoRepository { suspend fun getChangellyPromoBanner(): PromoBanner? suspend fun getTravalaPromoBanner(): PromoBanner? + + suspend fun getOkxPromoBanner(): PromoBanner? } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt index a69442cd51..878dc66047 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt @@ -2,7 +2,9 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.analytics import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.models.analytics.TokenSwapPromoAnalyticsEvent import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification @@ -35,12 +37,15 @@ internal class TokenDetailsNotificationsAnalyticsSender( -> TokenDetailsAnalyticsEvent.Notice.NotEnoughFee( currency = cryptoCurrency, ) + is TokenDetailsNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner( + programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX, + source = AnalyticsParam.ScreensSources.Token, + ) is TokenDetailsNotification.NetworksUnreachable, is TokenDetailsNotification.ExistentialDeposit, is TokenDetailsNotification.NetworksNoAccount, is TokenDetailsNotification.TopUpWithoutReserve, is TokenDetailsNotification.RentInfo, - is TokenDetailsNotification.SwapPromo, is TokenDetailsNotification.NetworkShutdown, is TokenDetailsNotification.HederaAssociateWarning, is TokenDetailsNotification.KoinosMana, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt index 950f24a218..a09065820b 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt @@ -2,7 +2,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.componen import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.networkIconResId +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.features.tokendetails.impl.R @@ -45,16 +48,9 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) { val onCloseClick: () -> Unit, ) : TokenDetailsNotification( config = NotificationConfig( - title = resourceReference( - id = R.string.token_swap_changelly_promotion_title, - formatArgs = wrappedList("0%"), - ), - subtitle = resourceReference( - id = R.string.token_swap_changelly_promotion_message, - formatArgs = wrappedList("0%", startDateTime.dayOfMonth, endDateTime.dayOfMonth), - ), - iconResId = R.drawable.img_swap_promo, - backgroundResId = R.drawable.img_swap_promo_green_banner_background, + title = resourceReference(id = R.string.swap_promo_title), + subtitle = resourceReference(id = R.string.swap_promo_text), + iconResId = R.drawable.img_okx_dex_logo, onCloseClick = onCloseClick, buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( text = resourceReference(id = com.tangem.core.ui.R.string.token_swap_promotion_button), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index d9eb9ec18d..c24ca651d8 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -32,7 +32,7 @@ import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBotto import com.tangem.core.ui.components.marketprice.MarketPriceBlock import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.notifications.Notification -import com.tangem.core.ui.components.notifications.NotificationWithBackground +import com.tangem.core.ui.components.notifications.OkxPromoNotification import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.txHistoryItems import com.tangem.core.ui.event.EventEffect @@ -111,7 +111,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) { contentType = { it.config::class.java }, itemContent = { if (it is TokenDetailsNotification.SwapPromo) { - NotificationWithBackground( + OkxPromoNotification( config = it.config, modifier = itemModifier.animateItemPlacement(), ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index d4e58af373..c2ff51d2d6 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -5,6 +5,7 @@ import androidx.paging.cachedIn import arrow.core.getOrElse import com.tangem.blockchain.common.address.AddressType import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.core.deeplink.global.BuyCurrencyDeepLink import com.tangem.core.ui.clipboard.ClipboardManager @@ -709,14 +710,26 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onSwapPromoDismiss() { viewModelScope.launch(dispatchers.main) { shouldShowSwapPromoTokenUseCase.neverToShow() - analyticsEventsHandler.send(TokenSwapPromoAnalyticsEvent.Close) + analyticsEventsHandler.send( + TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( + source = AnalyticsParam.ScreensSources.Token, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX, + action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed, + ), + ) } } override fun onSwapPromoClick() { viewModelScope.launch(dispatchers.main) { shouldShowSwapPromoTokenUseCase.neverToShow() - analyticsEventsHandler.send(TokenSwapPromoAnalyticsEvent.Exchange(cryptoCurrency.symbol)) + analyticsEventsHandler.send( + TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( + source = AnalyticsParam.ScreensSources.Token, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX, + action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked, + ), + ) } onSwapClick(ScenarioUnavailabilityReason.None) } 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 f39a38511b..de6ddf8b1b 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 @@ -121,38 +121,4 @@ sealed class WalletScreenAnalyticsEvent { data object DeleteWalletTapped : MainScreen(event = "Button - Delete Wallet Tapped") } - - sealed class Promotion( - event: String, - params: Map = mapOf(), - ) : AnalyticsEvent(category = "Promotion", event = event, params = params) { - class NoticePromotionBanner( - source: AnalyticsParam.ScreensSources, - programName: String, - ) : Promotion( - event = "Notice - Promotion Banner", - params = mapOf( - AnalyticsParam.SOURCE to source.value, - "Program Name" to programName, - ), - ) - - class PromotionBannerClicked( - source: AnalyticsParam.ScreensSources, - programName: String, - action: BannerAction, - ) : Promotion( - event = "Promo Banner Clicked", - params = mapOf( - AnalyticsParam.SOURCE to source.value, - "Program Name" to programName, - "Action" to action.action, - ), - ) { - sealed class BannerAction(val action: String) { - data object Clicked : BannerAction(action = "Clicked") - data object Closed : BannerAction(action = "Closed") - } - } - } } \ 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 59d4331387..398372e208 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 @@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.analytics.utils import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent +import com.tangem.domain.tokens.models.analytics.TokenSwapPromoAnalyticsEvent import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState @@ -46,16 +46,19 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( is WalletNotification.Informational.MissingAddresses -> MainScreen.MissingAddresses is WalletNotification.RateApp -> MainScreen.HowDoYouLikeTangem is WalletNotification.Critical.BackupError -> MainScreen.BackupError - is WalletNotification.TravalaPromo -> WalletScreenAnalyticsEvent.Promotion.NoticePromotionBanner( + is WalletNotification.TravalaPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner( source = AnalyticsParam.ScreensSources.Main, - programName = "Travala", + programName = TokenSwapPromoAnalyticsEvent.ProgramName.Travala, + ) + is WalletNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner( + source = AnalyticsParam.ScreensSources.Main, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX, ) is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender] is WalletNotification.Informational.NoAccount, is WalletNotification.Warning.LowSignatures, is WalletNotification.Warning.SomeNetworksUnreachable, is WalletNotification.Warning.NetworksUnreachable, - is WalletNotification.SwapPromo, -> null } } 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 a2adf6b292..b0513c7656 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,7 +6,7 @@ import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.promo.PromoBanner import com.tangem.domain.settings.IsReadyToShowRateAppUseCase -import com.tangem.domain.settings.ShouldShowTravalaPromoWalletUseCase +import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.CryptoCurrency @@ -34,7 +34,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( private val getTokenListUseCase: GetTokenListUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, - private val shouldShowTravalaPromoWalletUseCase: ShouldShowTravalaPromoWalletUseCase, + private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, private val promoRepository: PromoRepository, private val isNeedToBackupUseCase: IsNeedToBackupUseCase, private val backupValidator: BackupValidator, @@ -45,18 +45,18 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow> { val cardTypesResolver = userWallet.scanResponse.cardTypesResolver - val travalaPromoFlow = flow { emit(promoRepository.getTravalaPromoBanner()) } + val promoFlow = flow { emit(promoRepository.getOkxPromoBanner()) } return combine( flow = getTokenListUseCase.launch(userWallet.walletId).conflate(), flow2 = isReadyToShowRateAppUseCase().conflate(), flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(), - flow4 = shouldShowTravalaPromoWalletUseCase().conflate(), - flow5 = travalaPromoFlow.conflate(), - ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, shouldShowTravalaPromo, promoBanner -> + flow4 = shouldShowSwapPromoWalletUseCase().conflate(), + flow5 = promoFlow.conflate(), + ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, shouldShowPromo, promoBanner -> readyForRateAppNotification = true buildList { - addTravalaPromoNotification(shouldShowTravalaPromo, promoBanner, clickIntents) + addSwapPromoNotification(shouldShowPromo, promoBanner, clickIntents) addCriticalNotifications(userWallet) @@ -69,18 +69,16 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( } } - private fun MutableList.addTravalaPromoNotification( + private fun MutableList.addSwapPromoNotification( shouldShowPromo: Boolean, promoBanner: PromoBanner?, clickIntents: WalletClickIntents, ) { promoBanner ?: return - val promoNotification = WalletNotification.TravalaPromo( + val promoNotification = WalletNotification.SwapPromo( startDateTime = promoBanner.bannerState.timeline.start, endDateTime = promoBanner.bannerState.timeline.end, - bannerLink = promoBanner.bannerState.link, - onBookNowButtonClick = clickIntents::onTravalaPromoClick, - onCloseClick = clickIntents::onCloseTravalaPromoClick, + onCloseClick = clickIntents::onCloseSwapPromoClick, ) addIf( element = promoNotification, 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 c34e986c29..4a3247b5e1 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 @@ -2,7 +2,10 @@ package com.tangem.feature.wallet.presentation.wallet.state.model import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.pluralReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.feature.wallet.impl.R import org.joda.time.DateTime @@ -205,16 +208,9 @@ sealed class WalletNotification(val config: NotificationConfig) { val onCloseClick: () -> Unit, ) : WalletNotification( config = NotificationConfig( - title = resourceReference( - id = R.string.main_swap_changelly_promotion_title, - formatArgs = wrappedList("0%"), - ), - subtitle = resourceReference( - id = R.string.main_swap_changelly_promotion_message, - formatArgs = wrappedList("0%", startDateTime.dayOfMonth, endDateTime.dayOfMonth), - ), - iconResId = R.drawable.img_swap_promo, - backgroundResId = R.drawable.img_swap_promo_green_banner_background, + title = resourceReference(id = R.string.swap_promo_title), + subtitle = resourceReference(id = R.string.swap_promo_text), + iconResId = R.drawable.img_okx_dex_logo, onCloseClick = onCloseClick, ), ) 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 6b783e0eb0..08a341ebb7 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 @@ -5,7 +5,7 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.ui.Modifier import com.tangem.core.ui.components.notifications.Notification -import com.tangem.core.ui.components.notifications.NotificationWithBackground +import com.tangem.core.ui.components.notifications.OkxPromoNotification import com.tangem.core.ui.components.notifications.TravalaNotificationWithBackground import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification @@ -29,7 +29,7 @@ internal fun LazyListScope.notifications(configs: ImmutableList { - NotificationWithBackground( + OkxPromoNotification( config = it.config, modifier = modifier.animateItemPlacement(), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index 21982d8010..d2af11e81b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -14,13 +14,13 @@ import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase import com.tangem.domain.settings.ShouldShowTravalaPromoWalletUseCase import com.tangem.domain.tokens.FetchTokenListUseCase import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.models.analytics.TokenSwapPromoAnalyticsEvent import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType import com.tangem.domain.wallets.models.UnlockWalletsError import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.UnlockWalletsUseCase import com.tangem.feature.wallet.impl.R -import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.domain.ScanCardToUnlockWalletClickHandler @@ -214,6 +214,13 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } override fun onCloseSwapPromoClick() { + analyticsEventHandler.send( + TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( + source = AnalyticsParam.ScreensSources.Main, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX, + action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed, + ), + ) viewModelScope.launch(dispatchers.main) { shouldShowSwapPromoWalletUseCase.neverToShow() } @@ -221,10 +228,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onTravalaPromoClick(link: String?) { analyticsEventHandler.send( - WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked( + TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( source = AnalyticsParam.ScreensSources.Main, - programName = "Travala", - action = WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked.BannerAction.Clicked, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.Travala, + action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked, ), ) link?.let { @@ -236,10 +243,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onCloseTravalaPromoClick() { analyticsEventHandler.send( - WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked( + TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( source = AnalyticsParam.ScreensSources.Main, - programName = "Travala", - action = WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked.BannerAction.Closed, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.Travala, + action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed, ), ) viewModelScope.launch(dispatchers.main) {