Updated on 2026-08-14
This commit is contained in:
commit
2ccf6ba96e
22 changed files with 329 additions and 109 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -550,6 +550,8 @@
|
|||
<string name="story_meet_title">Встречайте Tangem</string>
|
||||
<string name="story_web3_description">Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах</string>
|
||||
<string name="story_web3_title">Поддержка Web 3.0</string>
|
||||
<string name="swap_promo_text">Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке.</string>
|
||||
<string name="swap_promo_title">Новый провайдер обмена!</string>
|
||||
<string name="swapping_alert_cex_description">В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %s от биржи обратно на адрес пользователя</string>
|
||||
<string name="swapping_alert_dex_description">В сумму включена комиссия провайдера сервиса.</string>
|
||||
<string name="swapping_alert_title">Комиссии</string>
|
||||
|
|
|
|||
|
|
@ -543,6 +543,8 @@
|
|||
<string name="story_meet_title">Meet Tangem</string>
|
||||
<string name="story_web3_description">Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services</string>
|
||||
<string name="story_web3_title">Web 3.0 Compatible</string>
|
||||
<string name="swap_promo_text">Exchange more tokens at better rates directly in your wallet.</string>
|
||||
<string name="swap_promo_title">New Swap Provider Available!</string>
|
||||
<string name="swapping_alert_cex_description">The amount includes:\n• service provider\'s fee\n• network fee for sending %s from the exchange back to the user\'s address.</string>
|
||||
<string name="swapping_alert_dex_description">The amount includes the service provider\'s fee.</string>
|
||||
<string name="swapping_alert_title">Fees</string>
|
||||
|
|
|
|||
|
|
@ -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<NotificationConfig> {
|
||||
override val values: Sequence<NotificationConfig>
|
||||
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
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
29
core/ui/src/main/res/drawable/img_okx_dex_logo.xml
Normal file
29
core/ui/src/main/res/drawable/img_okx_dex_logo.xml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="1232.1" android:viewportWidth="2516" android:width="49.00901dp">
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m740.2,0L23.5,0c-4.4,0 -8.7,1.6 -11.8,4.6 -3.1,2.9 -4.9,6.9 -4.9,11v670.6c0,4.1 1.8,8.1 4.9,11 3.1,2.9 7.4,4.6 11.8,4.6h716.7c4.4,0 8.7,-1.6 11.8,-4.6 3.1,-2.9 4.9,-6.9 4.9,-11L756.9,15.6c0,-4.1 -1.8,-8.1 -4.9,-11 -3.1,-2.9 -7.4,-4.6 -11.8,-4.6ZM506.9,452.3c0,4.1 -1.8,8.1 -4.9,11 -3.1,2.9 -7.4,4.6 -11.8,4.6h-216.7c-4.4,0 -8.7,-1.6 -11.8,-4.6 -3.1,-2.9 -4.9,-6.9 -4.9,-11v-202.8c0,-4.1 1.8,-8.1 4.9,-11 3.1,-2.9 7.4,-4.6 11.8,-4.6h216.7c4.4,0 8.7,1.6 11.8,4.6 3.1,2.9 4.9,6.9 4.9,11v202.8Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m2240.6,234h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6v-202.8c0,-8.6 -7.5,-15.6 -16.7,-15.6h0Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m1990.7,0h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6V15.6c0,-8.6 -7.5,-15.6 -16.7,-15.6Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m2490.8,0h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6V15.6c0,-8.6 -7.5,-15.6 -16.7,-15.6Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m1990.7,467.9h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6v-202.8c0,-8.6 -7.5,-15.6 -16.7,-15.6Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m2490.8,467.9h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6v-202.8c0,-8.6 -7.5,-15.6 -16.7,-15.6Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m1615.3,0h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6V15.6c0,-8.6 -7.5,-15.6 -16.7,-15.6Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m1615.3,467.9h-216.7c-9.2,0 -16.7,7 -16.7,15.6v202.8c0,8.6 7.5,15.6 16.7,15.6h216.7c9.2,0 16.7,-7 16.7,-15.6v-202.8c0,-8.6 -7.5,-15.6 -16.7,-15.6Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m1381.9,249.4c0,-4.1 -1.8,-8.1 -4.9,-11 -3.1,-2.9 -7.4,-4.6 -11.8,-4.6h-233.4V15.6c0,-4.1 -1.8,-8.1 -4.9,-11 -3.1,-2.9 -7.4,-4.6 -11.8,-4.6h-216.7c-4.4,0 -8.7,1.6 -11.8,4.6 -3.1,2.9 -4.9,6.9 -4.9,11v670.3c0,4.1 1.8,8.1 4.9,11 3.1,2.9 7.4,4.6 11.8,4.6h216.7c4.4,0 8.7,-1.6 11.8,-4.6 3.1,-2.9 4.9,-6.9 4.9,-11v-218.2h233.4c4.4,0 8.7,-1.6 11.8,-4.6 3.1,-2.9 4.9,-6.9 4.9,-11v-202.8Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m1675.2,885c33.8,0 64.5,6.8 92,20.4 27.5,13.6 49.2,33.4 65.2,59.5 16,26.1 24,57.2 24,93.2s-8,67.2 -24,93.4c-16,26.3 -37.6,46.2 -65,60 -27.4,13.8 -58.1,20.6 -92.2,20.6h-125.2v-347.1h125.2ZM1666.2,1163.8c34.5,0 60.5,-9.2 78.3,-27.5 17.7,-18.3 26.6,-44.4 26.6,-78.3s-8.9,-59.4 -26.8,-77.5c-17.9,-18.2 -43.9,-27.3 -78,-27.3h-35.1v210.6h35.1Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m2125.7,1092.2h-135.6v69.7h157v70.2h-238.1v-347.1h232.4v69.7h-151.3v68.3h135.6v69.2Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="m2509.8,885l-121.4,168.4 127.6,178.8h-100.1l-77.3,-112.9 -78.7,112.9h-92.9l127.6,-176.9 -121.4,-170.3h99.1l71.6,104.3 72.6,-104.3h93.4Z"/>
|
||||
|
||||
<path android:fillColor="#FF000000" android:pathData="M0,1033.9h1381.6v49h-1381.6z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Boolean> {
|
||||
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<Boolean> {
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String, String> = 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,
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ class GetCurrencyWarningsUseCase(
|
|||
): Flow<CryptoCurrencyWarning?> {
|
||||
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(),
|
||||
|
|
|
|||
|
|
@ -7,4 +7,6 @@ interface PromoRepository {
|
|||
suspend fun getChangellyPromoBanner(): PromoBanner?
|
||||
|
||||
suspend fun getTravalaPromoBanner(): PromoBanner?
|
||||
|
||||
suspend fun getOkxPromoBanner(): PromoBanner?
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,38 +121,4 @@ sealed class WalletScreenAnalyticsEvent {
|
|||
|
||||
data object DeleteWalletTapped : MainScreen(event = "Button - Delete Wallet Tapped")
|
||||
}
|
||||
|
||||
sealed class Promotion(
|
||||
event: String,
|
||||
params: Map<String, String> = 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ImmutableList<WalletNotification>> {
|
||||
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<WalletNotification>.addTravalaPromoNotification(
|
||||
private fun MutableList<WalletNotification>.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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<WalletNotificati
|
|||
// TODO develop promo banner general component
|
||||
when (it) {
|
||||
is WalletNotification.SwapPromo -> {
|
||||
NotificationWithBackground(
|
||||
OkxPromoNotification(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue