Updated on 2026-08-14
This commit is contained in:
parent
bb541e6a3f
commit
ec9bd02e35
23 changed files with 42 additions and 722 deletions
|
|
@ -19,12 +19,6 @@ internal object PromoDomainModule {
|
||||||
return ShouldShowSwapPromoWalletUseCase(promoSettingsRepository)
|
return ShouldShowSwapPromoWalletUseCase(promoSettingsRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideShouldShowRingPromoUseCase(promoRepository: PromoRepository): ShouldShowRingPromoUseCase {
|
|
||||||
return ShouldShowRingPromoUseCase(promoRepository)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideShouldShowSwapPromoTokenUseCase(promoRepository: PromoRepository): ShouldShowSwapPromoTokenUseCase {
|
fun provideShouldShowSwapPromoTokenUseCase(promoRepository: PromoRepository): ShouldShowSwapPromoTokenUseCase {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ import androidx.datastore.preferences.core.emptyPreferences
|
||||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||||
import com.tangem.datasource.local.preferences.PreferencesDataStore.INSTANCE
|
import com.tangem.datasource.local.preferences.PreferencesDataStore.INSTANCE
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys.APP_LOGS_KEY
|
import com.tangem.datasource.local.preferences.PreferencesKeys.APP_LOGS_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.SHOULD_SHOW_RING_PROMO_KEY
|
||||||
import com.tangem.datasource.local.preferences.utils.CleanupKeyMigration
|
import com.tangem.datasource.local.preferences.utils.CleanupKeyMigration
|
||||||
import com.tangem.datasource.local.preferences.utils.SharedPreferencesKeyMigration
|
import com.tangem.datasource.local.preferences.utils.SharedPreferencesKeyMigration
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -80,6 +83,9 @@ internal object PreferencesDataStore {
|
||||||
keyName = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY.name,
|
keyName = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY.name,
|
||||||
),
|
),
|
||||||
CleanupKeyMigration(key = APP_LOGS_KEY),
|
CleanupKeyMigration(key = APP_LOGS_KEY),
|
||||||
|
CleanupKeyMigration(key = IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY),
|
||||||
|
CleanupKeyMigration(key = IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY),
|
||||||
|
CleanupKeyMigration(key = SHOULD_SHOW_RING_PROMO_KEY),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,6 +17,9 @@ import com.tangem.datasource.local.preferences.PreferencesKeys.WAS_TWINS_ONBOARD
|
||||||
/**
|
/**
|
||||||
* All preferences keys that DataStore<Preferences> is stored.
|
* All preferences keys that DataStore<Preferences> is stored.
|
||||||
*
|
*
|
||||||
|
* !!!IMPORTANT!!!
|
||||||
|
* Before DELETING active key do [CleanupKeyMigration] in [PreferencesDataStore]
|
||||||
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
object PreferencesKeys {
|
object PreferencesKeys {
|
||||||
|
|
@ -87,10 +90,12 @@ object PreferencesKeys {
|
||||||
|
|
||||||
val UNSUBMITTED_TRANSACTIONS_KEY by lazy { stringPreferencesKey(name = "unsubmittedTransactions") }
|
val UNSUBMITTED_TRANSACTIONS_KEY by lazy { stringPreferencesKey(name = "unsubmittedTransactions") }
|
||||||
|
|
||||||
|
@Deprecated("Remove after CleanupKeyMigration")
|
||||||
val IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY by lazy {
|
val IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY by lazy {
|
||||||
booleanPreferencesKey(name = "isWalletSwapPromoOkxShown")
|
booleanPreferencesKey(name = "isWalletSwapPromoOkxShown")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Remove after CleanupKeyMigration")
|
||||||
val IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY by lazy {
|
val IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY by lazy {
|
||||||
booleanPreferencesKey(name = "isTokenSwapPromoOkxShown")
|
booleanPreferencesKey(name = "isTokenSwapPromoOkxShown")
|
||||||
}
|
}
|
||||||
|
|
@ -99,6 +104,7 @@ object PreferencesKeys {
|
||||||
|
|
||||||
val ADDED_WALLETS_WITH_RING_KEY by lazy { stringSetPreferencesKey(name = "addedWalletsWithRing") }
|
val ADDED_WALLETS_WITH_RING_KEY by lazy { stringSetPreferencesKey(name = "addedWalletsWithRing") }
|
||||||
|
|
||||||
|
@Deprecated("Remove after CleanupKeyMigration")
|
||||||
val SHOULD_SHOW_RING_PROMO_KEY by lazy { booleanPreferencesKey(name = "shouldShowRingPromo") }
|
val SHOULD_SHOW_RING_PROMO_KEY by lazy { booleanPreferencesKey(name = "shouldShowRingPromo") }
|
||||||
|
|
||||||
val ONRAMP_DEFAULT_COUNTRY by lazy { stringPreferencesKey(name = "onrampDefaultCountry") }
|
val ONRAMP_DEFAULT_COUNTRY by lazy { stringPreferencesKey(name = "onrampDefaultCountry") }
|
||||||
|
|
|
||||||
|
|
@ -1,206 +0,0 @@
|
||||||
package com.tangem.core.ui.components.notifications
|
|
||||||
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.defaultMinSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.material3.ButtonColors
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.ripple
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|
||||||
import androidx.constraintlayout.compose.ConstraintLayout
|
|
||||||
import androidx.constraintlayout.compose.Dimension
|
|
||||||
import androidx.constraintlayout.compose.Visibility
|
|
||||||
import com.tangem.core.ui.R
|
|
||||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
|
||||||
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.extensions.stringReference
|
|
||||||
import com.tangem.core.ui.extensions.wrappedList
|
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom notification with image background
|
|
||||||
* @see [Swap Promo](https://www.figma.com/file/Vs6SkVsFnUPsSCNwlnVf5U/Android-%E2%80%93-UI?type=design&node-id=8713-6307&mode=dev)
|
|
||||||
*/
|
|
||||||
@Suppress("LongMethod", "DestructuringDeclarationWithTooManyEntries")
|
|
||||||
@Composable
|
|
||||||
fun NotificationWithBackground(config: NotificationConfig, modifier: Modifier = Modifier) {
|
|
||||||
val button = config.buttonsState as? NotificationConfig.ButtonsState.SecondaryButtonConfig
|
|
||||||
|
|
||||||
ConstraintLayout(
|
|
||||||
modifier = modifier
|
|
||||||
.defaultMinSize(minHeight = TangemTheme.dimens.size62)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
|
||||||
.clickable(
|
|
||||||
enabled = config.onClick != null,
|
|
||||||
onClick = config.onClick ?: {},
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
val (iconRef, titleRef, subtitleRef, closeIconRef, buttonRef, backgroundRef) = createRefs()
|
|
||||||
|
|
||||||
val spacing2 = TangemTheme.dimens.spacing2
|
|
||||||
val spacing12 = TangemTheme.dimens.spacing12
|
|
||||||
val spacing14 = TangemTheme.dimens.spacing14
|
|
||||||
|
|
||||||
Image(
|
|
||||||
painter = painterResource(config.backgroundResId ?: R.drawable.img_swap_promo_blue_banner_background),
|
|
||||||
contentDescription = null,
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
modifier = Modifier.constrainAs(backgroundRef) {
|
|
||||||
top.linkTo(parent.top)
|
|
||||||
start.linkTo(parent.start)
|
|
||||||
end.linkTo(parent.end)
|
|
||||||
bottom.linkTo(parent.bottom)
|
|
||||||
width = Dimension.fillToConstraints
|
|
||||||
height = Dimension.fillToConstraints
|
|
||||||
visibility = if (config.backgroundResId == null) Visibility.Gone else Visibility.Visible
|
|
||||||
},
|
|
||||||
)
|
|
||||||
Image(
|
|
||||||
painter = painterResource(config.iconResId),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(TangemTheme.dimens.size34)
|
|
||||||
.constrainAs(iconRef) {
|
|
||||||
start.linkTo(parent.start, spacing12)
|
|
||||||
linkTo(titleRef.top, subtitleRef.bottom, bias = 0.1f)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
val titleText = config.title?.resolveReference()
|
|
||||||
if (titleText != null) {
|
|
||||||
Text(
|
|
||||||
text = titleText,
|
|
||||||
style = TangemTheme.typography.button,
|
|
||||||
color = TangemTheme.colors.text.constantWhite,
|
|
||||||
modifier = Modifier.constrainAs(titleRef) {
|
|
||||||
top.linkTo(parent.top, spacing12)
|
|
||||||
start.linkTo(iconRef.end, spacing12)
|
|
||||||
end.linkTo(closeIconRef.start, spacing2)
|
|
||||||
width = Dimension.fillToConstraints
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = config.subtitle.resolveReference(),
|
|
||||||
style = TangemTheme.typography.caption2,
|
|
||||||
color = TangemTheme.colors.text.constantWhite,
|
|
||||||
modifier = Modifier.constrainAs(subtitleRef) {
|
|
||||||
top.linkTo(titleRef.bottom, spacing2)
|
|
||||||
start.linkTo(iconRef.end, spacing12)
|
|
||||||
end.linkTo(parent.end, spacing12)
|
|
||||||
bottom.linkTo(buttonRef.top, spacing12, spacing14)
|
|
||||||
width = Dimension.fillToConstraints
|
|
||||||
},
|
|
||||||
)
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_close_24),
|
|
||||||
contentDescription = null,
|
|
||||||
tint = TangemTheme.colors.text.constantWhite,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(TangemTheme.dimens.size16)
|
|
||||||
.constrainAs(closeIconRef) {
|
|
||||||
top.linkTo(parent.top, spacing12)
|
|
||||||
end.linkTo(parent.end, spacing12)
|
|
||||||
}
|
|
||||||
.clickable(
|
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
|
||||||
indication = ripple(bounded = false),
|
|
||||||
) {
|
|
||||||
config.onCloseClick?.invoke()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
val isDarkMode = LocalIsInDarkTheme.current
|
|
||||||
TangemButton(
|
|
||||||
modifier = Modifier.constrainAs(buttonRef) {
|
|
||||||
start.linkTo(parent.start, spacing12)
|
|
||||||
end.linkTo(parent.end, spacing12)
|
|
||||||
bottom.linkTo(parent.bottom, spacing12)
|
|
||||||
width = Dimension.fillToConstraints
|
|
||||||
visibility = if (button == null) {
|
|
||||||
Visibility.Gone
|
|
||||||
} else {
|
|
||||||
Visibility.Visible
|
|
||||||
}
|
|
||||||
},
|
|
||||||
text = button?.text?.resolveReference().orEmpty(),
|
|
||||||
icon = TangemButtonIconPosition.Start(button?.iconResId ?: R.drawable.ic_exchange_vertical_24),
|
|
||||||
onClick = button?.onClick ?: {},
|
|
||||||
colors = ButtonColors(
|
|
||||||
containerColor = if (isDarkMode) Light4 else TangemTheme.colors.button.secondary,
|
|
||||||
contentColor = Dark6,
|
|
||||||
disabledContainerColor = TangemTheme.colors.button.disabled,
|
|
||||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
|
||||||
),
|
|
||||||
textStyle = TangemTheme.typography.subtitle1,
|
|
||||||
enabled = true,
|
|
||||||
showProgress = false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//region preview
|
|
||||||
@Preview
|
|
||||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
|
||||||
@Composable
|
|
||||||
private fun NotificationWithBackgroundPreview(
|
|
||||||
@PreviewParameter(NotificationWithBackgroundPreviewProvider::class) config: NotificationConfig,
|
|
||||||
) {
|
|
||||||
TangemThemePreview {
|
|
||||||
NotificationWithBackground(config = config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvider<NotificationConfig> {
|
|
||||||
override val values: Sequence<NotificationConfig>
|
|
||||||
get() = sequenceOf(
|
|
||||||
NotificationConfig(
|
|
||||||
title = resourceReference(id = R.string.main_swap_changelly_promotion_title),
|
|
||||||
subtitle = resourceReference(
|
|
||||||
id = R.string.main_swap_changelly_promotion_message,
|
|
||||||
formatArgs = wrappedList("1", "2", "3"),
|
|
||||||
),
|
|
||||||
iconResId = R.drawable.img_swap_promo,
|
|
||||||
backgroundResId = R.drawable.img_swap_promo_blue_banner_background,
|
|
||||||
),
|
|
||||||
NotificationConfig(
|
|
||||||
title = resourceReference(
|
|
||||||
id = R.string.token_swap_changelly_promotion_title,
|
|
||||||
formatArgs = wrappedList("1"),
|
|
||||||
),
|
|
||||||
subtitle = stringReference(
|
|
||||||
"Swap multiple currencies between any chains you wish. Swap multiple " +
|
|
||||||
"currencies between any chains you wish. Swap multiple " +
|
|
||||||
"currencies between any chains you wish. Commission free period " +
|
|
||||||
"till Dec 31.",
|
|
||||||
),
|
|
||||||
iconResId = R.drawable.img_swap_promo,
|
|
||||||
backgroundResId = R.drawable.img_swap_promo_blue_banner_background,
|
|
||||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
|
||||||
text = resourceReference(id = R.string.token_swap_promotion_button),
|
|
||||||
onClick = {},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
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.material3.ButtonColors
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.ripple
|
|
||||||
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.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.spacing2),
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.padding(TangemTheme.dimens.spacing12),
|
|
||||||
) {
|
|
||||||
val titleText = config.title?.resolveReference()
|
|
||||||
|
|
||||||
if (titleText != null) {
|
|
||||||
Text(
|
|
||||||
text = titleText,
|
|
||||||
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 = ripple(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(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(
|
|
||||||
start = TangemTheme.dimens.spacing12,
|
|
||||||
end = TangemTheme.dimens.spacing12,
|
|
||||||
bottom = TangemTheme.dimens.spacing12,
|
|
||||||
),
|
|
||||||
text = button.text.resolveReference(),
|
|
||||||
icon = TangemButtonIconPosition.Start(button.iconResId ?: R.drawable.ic_exchange_vertical_24),
|
|
||||||
onClick = button.onClick,
|
|
||||||
colors = ButtonColors(
|
|
||||||
containerColor = if (isDarkMode) Light4 else TangemTheme.colors.button.secondary,
|
|
||||||
contentColor = Dark6,
|
|
||||||
disabledContainerColor = TangemTheme.colors.button.disabled,
|
|
||||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
|
||||||
),
|
|
||||||
textStyle = TangemTheme.typography.subtitle1,
|
|
||||||
enabled = true,
|
|
||||||
showProgress = false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
package com.tangem.core.ui.components.notifications
|
|
||||||
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.layout.FixedScale
|
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.constraintlayout.compose.ConstraintLayout
|
|
||||||
import com.tangem.core.ui.R
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
import com.tangem.core.ui.res.TangemColorPalette
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RingPromoNotification(config: NotificationConfig, modifier: Modifier = Modifier) {
|
|
||||||
var textHeightDp by remember { mutableStateOf(0.dp) }
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
|
|
||||||
.background(TangemColorPalette.Dark6),
|
|
||||||
) {
|
|
||||||
PromoImage(
|
|
||||||
backgroundRes = config.backgroundResId,
|
|
||||||
iconRes = config.iconResId,
|
|
||||||
modifier = Modifier.height(textHeightDp),
|
|
||||||
)
|
|
||||||
PromoText(
|
|
||||||
title = config.title,
|
|
||||||
subtitle = config.subtitle,
|
|
||||||
onSizeChange = { textHeightDp = it },
|
|
||||||
)
|
|
||||||
CloseableIconButton(
|
|
||||||
onClick = config.onCloseClick,
|
|
||||||
modifier = Modifier.align(alignment = Alignment.TopEnd),
|
|
||||||
iconTint = TangemTheme.colors.icon.informative,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun PromoImage(@DrawableRes backgroundRes: Int?, @DrawableRes iconRes: Int, modifier: Modifier = Modifier) {
|
|
||||||
if (backgroundRes == null) return
|
|
||||||
ConstraintLayout(
|
|
||||||
modifier = modifier,
|
|
||||||
) {
|
|
||||||
val (background, image) = createRefs()
|
|
||||||
|
|
||||||
Image(
|
|
||||||
painter = painterResource(backgroundRes),
|
|
||||||
contentDescription = null,
|
|
||||||
contentScale = FixedScale(2f),
|
|
||||||
modifier = Modifier
|
|
||||||
.constrainAs(background) {
|
|
||||||
top.linkTo(parent.top)
|
|
||||||
start.linkTo(image.start)
|
|
||||||
end.linkTo(image.end)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = iconRes),
|
|
||||||
contentDescription = null,
|
|
||||||
contentScale = ContentScale.FillWidth,
|
|
||||||
modifier = Modifier
|
|
||||||
.requiredWidth(width = 60.dp)
|
|
||||||
.wrapContentHeight(Alignment.Top, unbounded = true)
|
|
||||||
.constrainAs(image) {
|
|
||||||
top.linkTo(parent.top, 11.dp)
|
|
||||||
start.linkTo(parent.start, 9.dp)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun PromoText(title: TextReference?, subtitle: TextReference, onSizeChange: (Dp) -> Unit) {
|
|
||||||
val density = LocalDensity.current
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.onSizeChanged {
|
|
||||||
with(density) { onSizeChange(it.height.toDp()) }
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
TextsBlock(
|
|
||||||
title = title,
|
|
||||||
subtitle = subtitle,
|
|
||||||
subtitleColor = TangemTheme.colors.text.tertiary,
|
|
||||||
titleColor = TangemTheme.colors.text.constantWhite,
|
|
||||||
modifier = Modifier
|
|
||||||
.wrapContentHeight()
|
|
||||||
.align(Alignment.CenterStart)
|
|
||||||
.padding(start = 80.dp, top = 12.dp, end = 12.dp, bottom = 12.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// region Preview
|
|
||||||
@Preview(showBackground = true, widthDp = 360)
|
|
||||||
@Preview(showBackground = true, widthDp = 360, locale = "fr")
|
|
||||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
|
||||||
@Composable
|
|
||||||
private fun RingPromoNotification_Preview() {
|
|
||||||
TangemThemePreview {
|
|
||||||
RingPromoNotification(
|
|
||||||
NotificationConfig(
|
|
||||||
title = resourceReference(id = R.string.ring_promo_title),
|
|
||||||
subtitle = resourceReference(id = R.string.ring_promo_text),
|
|
||||||
iconResId = R.drawable.img_card_with_ring,
|
|
||||||
backgroundResId = R.drawable.img_ring_promo_background,
|
|
||||||
onCloseClick = { },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
|
|
@ -1,94 +1,32 @@
|
||||||
package com.tangem.data.promo
|
package com.tangem.data.promo
|
||||||
|
|
||||||
import com.tangem.data.promo.converters.PromoResponseConverter
|
|
||||||
import com.tangem.datasource.api.common.response.getOrThrow
|
|
||||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys.ADDED_WALLETS_WITH_RING_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.SHOULD_SHOW_RING_PROMO_KEY
|
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys.SHOULD_SHOW_SWAP_STORIES_KEY
|
import com.tangem.datasource.local.preferences.PreferencesKeys.SHOULD_SHOW_SWAP_STORIES_KEY
|
||||||
import com.tangem.datasource.local.preferences.utils.get
|
import com.tangem.datasource.local.preferences.utils.get
|
||||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||||
import com.tangem.datasource.local.preferences.utils.store
|
import com.tangem.datasource.local.preferences.utils.store
|
||||||
import com.tangem.domain.promo.PromoRepository
|
import com.tangem.domain.promo.PromoRepository
|
||||||
import com.tangem.domain.promo.models.PromoBanner
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|
||||||
import com.tangem.utils.coroutines.runCatching
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
internal class DefaultPromoRepository(
|
internal class DefaultPromoRepository(
|
||||||
private val tangemApi: TangemTechApi,
|
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
|
||||||
) : PromoRepository {
|
) : PromoRepository {
|
||||||
|
|
||||||
private val promoResponseConverter = PromoResponseConverter()
|
|
||||||
override suspend fun getChangellyPromoBanner(): PromoBanner? {
|
|
||||||
return runCatching(dispatchers.io) {
|
|
||||||
promoResponseConverter.convert(
|
|
||||||
tangemApi.getPromotionInfo(CHANGELLY_NAME)
|
|
||||||
.getOrThrow(),
|
|
||||||
)
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getOkxPromoBanner(): PromoBanner? {
|
|
||||||
return runCatching(dispatchers.io) {
|
|
||||||
promoResponseConverter.convert(
|
|
||||||
tangemApi.getPromotionInfo(OKX)
|
|
||||||
.getOrThrow(),
|
|
||||||
)
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getRingPromoBanner(): PromoBanner? {
|
|
||||||
return runCatching(dispatchers.io) {
|
|
||||||
promoResponseConverter.convert(
|
|
||||||
tangemApi.getPromotionInfo(RING)
|
|
||||||
.getOrThrow(),
|
|
||||||
)
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isReadyToShowWalletSwapPromo(): Flow<Boolean> {
|
override fun isReadyToShowWalletSwapPromo(): Flow<Boolean> {
|
||||||
return appPreferencesStore.get(IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY, true)
|
return flowOf(false) // Use it on new promo action
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isReadyToShowTokenSwapPromo(): Flow<Boolean> {
|
override fun isReadyToShowTokenSwapPromo(): Flow<Boolean> {
|
||||||
return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY, true)
|
return flowOf(false) // Use it on new promo action
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setNeverToShowWalletSwapPromo() {
|
override suspend fun setNeverToShowWalletSwapPromo() {
|
||||||
appPreferencesStore.store(
|
// Use it on new promo action
|
||||||
key = IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY,
|
|
||||||
value = false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setNeverToShowTokenSwapPromo() {
|
override suspend fun setNeverToShowTokenSwapPromo() {
|
||||||
appPreferencesStore.store(
|
// Use it on new promo action
|
||||||
key = IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY,
|
|
||||||
value = false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isReadyToShowRingPromo(userWalletId: UserWalletId): Flow<Boolean> {
|
|
||||||
return combine(
|
|
||||||
flow = appPreferencesStore
|
|
||||||
.get(key = ADDED_WALLETS_WITH_RING_KEY, default = emptySet())
|
|
||||||
.map { userWalletId.stringValue in it },
|
|
||||||
flow2 = appPreferencesStore.get(key = SHOULD_SHOW_RING_PROMO_KEY, default = true),
|
|
||||||
transform = { isRingAdded, shouldShowRingPromo -> isRingAdded && shouldShowRingPromo },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun setNeverToShowRingPromo() {
|
|
||||||
appPreferencesStore.store(key = SHOULD_SHOW_RING_PROMO_KEY, value = false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isReadyToShowSwapStories(): Flow<Boolean> {
|
override fun isReadyToShowSwapStories(): Flow<Boolean> {
|
||||||
|
|
@ -105,10 +43,4 @@ internal class DefaultPromoRepository(
|
||||||
value = false,
|
value = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
|
||||||
private const val CHANGELLY_NAME = "changelly"
|
|
||||||
private const val OKX = "okx"
|
|
||||||
private const val RING = "ring"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package com.tangem.data.promo.di
|
package com.tangem.data.promo.di
|
||||||
|
|
||||||
import com.tangem.data.promo.DefaultPromoRepository
|
import com.tangem.data.promo.DefaultPromoRepository
|
||||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.domain.promo.PromoRepository
|
import com.tangem.domain.promo.PromoRepository
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
|
@ -17,11 +15,7 @@ internal object PromoDataModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providePromoRepository(
|
fun providePromoRepository(appPreferencesStore: AppPreferencesStore): PromoRepository {
|
||||||
tangemTechApi: TangemTechApi,
|
return DefaultPromoRepository(appPreferencesStore)
|
||||||
appPreferencesStore: AppPreferencesStore,
|
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
|
||||||
): PromoRepository {
|
|
||||||
return DefaultPromoRepository(tangemTechApi, appPreferencesStore, dispatchers)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,17 +1,9 @@
|
||||||
package com.tangem.domain.promo
|
package com.tangem.domain.promo
|
||||||
|
|
||||||
import com.tangem.domain.promo.models.PromoBanner
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface PromoRepository {
|
interface PromoRepository {
|
||||||
|
|
||||||
suspend fun getChangellyPromoBanner(): PromoBanner?
|
|
||||||
|
|
||||||
suspend fun getOkxPromoBanner(): PromoBanner?
|
|
||||||
|
|
||||||
suspend fun getRingPromoBanner(): PromoBanner?
|
|
||||||
|
|
||||||
fun isReadyToShowWalletSwapPromo(): Flow<Boolean>
|
fun isReadyToShowWalletSwapPromo(): Flow<Boolean>
|
||||||
|
|
||||||
fun isReadyToShowTokenSwapPromo(): Flow<Boolean>
|
fun isReadyToShowTokenSwapPromo(): Flow<Boolean>
|
||||||
|
|
@ -20,10 +12,6 @@ interface PromoRepository {
|
||||||
|
|
||||||
suspend fun setNeverToShowTokenSwapPromo()
|
suspend fun setNeverToShowTokenSwapPromo()
|
||||||
|
|
||||||
fun isReadyToShowRingPromo(userWalletId: UserWalletId): Flow<Boolean>
|
|
||||||
|
|
||||||
suspend fun setNeverToShowRingPromo()
|
|
||||||
|
|
||||||
fun isReadyToShowSwapStories(): Flow<Boolean>
|
fun isReadyToShowSwapStories(): Flow<Boolean>
|
||||||
|
|
||||||
suspend fun isReadyToShowSwapStoriesSync(): Boolean
|
suspend fun isReadyToShowSwapStoriesSync(): Boolean
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package com.tangem.domain.promo
|
|
||||||
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
|
|
||||||
class ShouldShowRingPromoUseCase(private val promoRepository: PromoRepository) {
|
|
||||||
|
|
||||||
operator fun invoke(userWalletId: UserWalletId): Flow<Boolean> {
|
|
||||||
return promoRepository.isReadyToShowRingPromo(userWalletId)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun neverToShow() = promoRepository.setNeverToShowRingPromo()
|
|
||||||
}
|
|
||||||
|
|
@ -36,8 +36,8 @@ sealed class TokenSwapPromoAnalyticsEvent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use it on new promo action
|
||||||
enum class ProgramName {
|
enum class ProgramName {
|
||||||
OKX,
|
Empty,
|
||||||
Ring,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ internal class TokenDetailsNotificationsAnalyticsSender(
|
||||||
currency = cryptoCurrency,
|
currency = cryptoCurrency,
|
||||||
)
|
)
|
||||||
is TokenDetailsNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner(
|
is TokenDetailsNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner(
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX,
|
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
|
||||||
source = AnalyticsParam.ScreensSources.Token,
|
source = AnalyticsParam.ScreensSources.Token,
|
||||||
)
|
)
|
||||||
is TokenDetailsNotification.KaspaIncompleteTransactionWarning -> TokenDetailsAnalyticsEvent.Notice.Reveal(
|
is TokenDetailsNotification.KaspaIncompleteTransactionWarning -> TokenDetailsAnalyticsEvent.Notice.Reveal(
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBotto
|
||||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
|
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
|
||||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||||
import com.tangem.core.ui.components.notifications.Notification
|
import com.tangem.core.ui.components.notifications.Notification
|
||||||
import com.tangem.core.ui.components.notifications.OkxPromoNotification
|
|
||||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||||
import com.tangem.core.ui.components.transactions.txHistoryItems
|
import com.tangem.core.ui.components.transactions.txHistoryItems
|
||||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||||
|
|
@ -92,12 +91,6 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
||||||
key = { it::class.java },
|
key = { it::class.java },
|
||||||
contentType = { it.config::class.java },
|
contentType = { it.config::class.java },
|
||||||
itemContent = {
|
itemContent = {
|
||||||
if (it is TokenDetailsNotification.SwapPromo) {
|
|
||||||
OkxPromoNotification(
|
|
||||||
config = it.config,
|
|
||||||
modifier = itemModifier.animateItem(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Notification(
|
Notification(
|
||||||
modifier = itemModifier.animateItem(),
|
modifier = itemModifier.animateItem(),
|
||||||
config = it.config,
|
config = it.config,
|
||||||
|
|
@ -106,7 +99,6 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
||||||
else -> null
|
else -> null
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ import com.tangem.domain.card.NetworkHasDerivationUseCase
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||||
import com.tangem.domain.onramp.model.OnrampSource
|
import com.tangem.domain.onramp.model.OnrampSource
|
||||||
import com.tangem.domain.promo.ShouldShowSwapPromoTokenUseCase
|
|
||||||
import com.tangem.domain.redux.ReduxStateHolder
|
import com.tangem.domain.redux.ReduxStateHolder
|
||||||
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
||||||
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
|
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
|
||||||
|
|
@ -74,6 +73,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBala
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
||||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory
|
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory
|
||||||
|
import com.tangem.domain.promo.ShouldShowSwapPromoTokenUseCase
|
||||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||||
import com.tangem.features.tokendetails.impl.R
|
import com.tangem.features.tokendetails.impl.R
|
||||||
import com.tangem.utils.Provider
|
import com.tangem.utils.Provider
|
||||||
|
|
@ -807,7 +807,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
||||||
analyticsEventsHandler.send(
|
analyticsEventsHandler.send(
|
||||||
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
||||||
source = AnalyticsParam.ScreensSources.Token,
|
source = AnalyticsParam.ScreensSources.Token,
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX,
|
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
|
||||||
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
|
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -820,7 +820,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
||||||
analyticsEventsHandler.send(
|
analyticsEventsHandler.send(
|
||||||
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
||||||
source = AnalyticsParam.ScreensSources.Token,
|
source = AnalyticsParam.ScreensSources.Token,
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX,
|
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
|
||||||
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked,
|
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
|
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
|
||||||
|
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent.ProgramName
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
|
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.WalletNotification
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||||
|
|
@ -50,7 +51,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
||||||
is WalletNotification.NoteMigration -> MainScreen.NotePromo
|
is WalletNotification.NoteMigration -> MainScreen.NotePromo
|
||||||
is WalletNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner(
|
is WalletNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner(
|
||||||
source = AnalyticsParam.ScreensSources.Main,
|
source = AnalyticsParam.ScreensSources.Main,
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX,
|
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
|
||||||
)
|
)
|
||||||
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
|
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
|
||||||
is WalletNotification.Informational.NoAccount,
|
is WalletNotification.Informational.NoAccount,
|
||||||
|
|
@ -58,10 +59,6 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
||||||
is WalletNotification.Warning.SomeNetworksUnreachable,
|
is WalletNotification.Warning.SomeNetworksUnreachable,
|
||||||
is WalletNotification.Warning.NetworksUnreachable,
|
is WalletNotification.Warning.NetworksUnreachable,
|
||||||
-> null
|
-> null
|
||||||
is WalletNotification.RingPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner(
|
|
||||||
source = AnalyticsParam.ScreensSources.Main,
|
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Ring,
|
|
||||||
)
|
|
||||||
is WalletNotification.Critical.SeedPhraseNotification -> MainScreen.NoticeSeedPhraseSupport
|
is WalletNotification.Critical.SeedPhraseNotification -> MainScreen.NoticeSeedPhraseSupport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@ import com.tangem.domain.common.CardTypesResolver
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.core.lce.Lce
|
import com.tangem.domain.core.lce.Lce
|
||||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||||
import com.tangem.domain.promo.PromoRepository
|
|
||||||
import com.tangem.domain.promo.ShouldShowRingPromoUseCase
|
|
||||||
import com.tangem.domain.promo.models.PromoBanner
|
|
||||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||||
import com.tangem.domain.tokens.error.TokenListError
|
import com.tangem.domain.tokens.error.TokenListError
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
|
|
@ -22,7 +19,6 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flow
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.count
|
import kotlin.collections.count
|
||||||
|
|
||||||
|
|
@ -32,8 +28,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
private val tokenListStore: MultiWalletTokenListStore,
|
private val tokenListStore: MultiWalletTokenListStore,
|
||||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||||
private val shouldShowRingPromoUseCase: ShouldShowRingPromoUseCase,
|
|
||||||
private val promoRepository: PromoRepository,
|
|
||||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||||
private val backupValidator: BackupValidator,
|
private val backupValidator: BackupValidator,
|
||||||
private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase,
|
private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase,
|
||||||
|
|
@ -43,25 +37,13 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotification>> {
|
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotification>> {
|
||||||
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
|
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
|
||||||
|
|
||||||
val promoFlow = flow { emit(promoRepository.getRingPromoBanner()) }
|
|
||||||
return combine(
|
return combine(
|
||||||
tokenListStore.getOrThrow(userWallet.walletId),
|
flow = tokenListStore.getOrThrow(userWallet.walletId),
|
||||||
isReadyToShowRateAppUseCase(),
|
flow2 = isReadyToShowRateAppUseCase(),
|
||||||
isNeedToBackupUseCase(userWallet.walletId),
|
flow3 = isNeedToBackupUseCase(userWallet.walletId),
|
||||||
shouldShowRingPromoUseCase(userWalletId = userWallet.walletId),
|
flow4 = seedPhraseNotificationUseCase(userWalletId = userWallet.walletId),
|
||||||
promoFlow,
|
) { maybeTokenList, isReadyToShowRating, isNeedToBackup, seedPhraseIssueStatus ->
|
||||||
seedPhraseNotificationUseCase(userWalletId = userWallet.walletId),
|
|
||||||
) {
|
|
||||||
val maybeTokenList = it[0] as Lce<TokenListError, TokenList>
|
|
||||||
val isReadyToShowRating = it[1] as Boolean
|
|
||||||
val isNeedToBackup = it[2] as Boolean
|
|
||||||
val shouldShowPromo = it[3] as Boolean
|
|
||||||
val promoBanner = it[4] as? PromoBanner
|
|
||||||
val seedPhraseIssueStatus = it[5] as Boolean
|
|
||||||
|
|
||||||
buildList {
|
buildList {
|
||||||
addRingPromoNotification(shouldShowPromo, promoBanner, clickIntents)
|
|
||||||
|
|
||||||
addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents)
|
addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents)
|
||||||
|
|
||||||
addInformationalNotifications(cardTypesResolver, maybeTokenList, clickIntents)
|
addInformationalNotifications(cardTypesResolver, maybeTokenList, clickIntents)
|
||||||
|
|
@ -79,19 +61,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableList<WalletNotification>.addRingPromoNotification(
|
|
||||||
shouldShowPromo: Boolean,
|
|
||||||
promoBanner: PromoBanner?,
|
|
||||||
clickIntents: WalletClickIntents,
|
|
||||||
) {
|
|
||||||
promoBanner ?: return
|
|
||||||
val promoNotification = WalletNotification.RingPromo(onCloseClick = clickIntents::onCloseRingPromoClick)
|
|
||||||
addIf(
|
|
||||||
element = promoNotification,
|
|
||||||
condition = shouldShowPromo && promoBanner.isActive,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MutableList<WalletNotification>.addCriticalNotifications(
|
private fun MutableList<WalletNotification>.addCriticalNotifications(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
seedPhraseIssueStatus: Boolean,
|
seedPhraseIssueStatus: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -206,16 +206,6 @@ sealed class WalletNotification(val config: NotificationConfig) {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class RingPromo(val onCloseClick: () -> Unit) : WalletNotification(
|
|
||||||
config = NotificationConfig(
|
|
||||||
title = resourceReference(id = R.string.ring_promo_title),
|
|
||||||
subtitle = resourceReference(id = R.string.ring_promo_text),
|
|
||||||
iconResId = R.drawable.img_card_with_ring,
|
|
||||||
backgroundResId = R.drawable.img_ring_promo_background,
|
|
||||||
onCloseClick = onCloseClick,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
data class NoteMigration(val onClick: () -> Unit) : WalletNotification(
|
data class NoteMigration(val onClick: () -> Unit) : WalletNotification(
|
||||||
config = NotificationConfig(
|
config = NotificationConfig(
|
||||||
title = resourceReference(R.string.wallet_promo_banner_title),
|
title = resourceReference(R.string.wallet_promo_banner_title),
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@ import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.tangem.core.ui.components.notifications.NoteMigrationNotification
|
import com.tangem.core.ui.components.notifications.NoteMigrationNotification
|
||||||
import com.tangem.core.ui.components.notifications.Notification
|
import com.tangem.core.ui.components.notifications.Notification
|
||||||
import com.tangem.core.ui.components.notifications.OkxPromoNotification
|
|
||||||
import com.tangem.core.ui.components.notifications.RingPromoNotification
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
@ -28,16 +26,7 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
||||||
// TODO develop promo banner general component
|
// TODO develop promo banner general component
|
||||||
when (it) {
|
when (it) {
|
||||||
is WalletNotification.SwapPromo -> {
|
is WalletNotification.SwapPromo -> {
|
||||||
OkxPromoNotification(
|
// Use it on new promo action
|
||||||
config = it.config,
|
|
||||||
modifier = modifier.animateItem(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is WalletNotification.RingPromo -> {
|
|
||||||
RingPromoNotification(
|
|
||||||
config = it.config,
|
|
||||||
modifier = modifier.animateItem(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
is WalletNotification.NoteMigration -> {
|
is WalletNotification.NoteMigration -> {
|
||||||
NoteMigrationNotification(
|
NoteMigrationNotification(
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import com.tangem.domain.card.SetCardWasScannedUseCase
|
||||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||||
import com.tangem.domain.promo.ShouldShowRingPromoUseCase
|
|
||||||
import com.tangem.domain.promo.ShouldShowSwapPromoWalletUseCase
|
import com.tangem.domain.promo.ShouldShowSwapPromoWalletUseCase
|
||||||
import com.tangem.domain.redux.LegacyAction
|
import com.tangem.domain.redux.LegacyAction
|
||||||
import com.tangem.domain.redux.ReduxStateHolder
|
import com.tangem.domain.redux.ReduxStateHolder
|
||||||
|
|
@ -66,8 +65,6 @@ internal interface WalletWarningsClickIntents {
|
||||||
|
|
||||||
fun onCloseSwapPromoClick()
|
fun onCloseSwapPromoClick()
|
||||||
|
|
||||||
fun onCloseRingPromoClick()
|
|
||||||
|
|
||||||
fun onSupportClick()
|
fun onSupportClick()
|
||||||
|
|
||||||
fun onNoteMigrationButtonClick(url: String)
|
fun onNoteMigrationButtonClick(url: String)
|
||||||
|
|
@ -94,7 +91,6 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
private val reduxStateHolder: ReduxStateHolder,
|
private val reduxStateHolder: ReduxStateHolder,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase,
|
private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase,
|
||||||
private val shouldShowRingPromoUseCase: ShouldShowRingPromoUseCase,
|
|
||||||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||||
private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase,
|
private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase,
|
||||||
|
|
@ -249,7 +245,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
||||||
source = AnalyticsParam.ScreensSources.Main,
|
source = AnalyticsParam.ScreensSources.Main,
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.OKX,
|
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action
|
||||||
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
|
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -258,20 +254,6 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCloseRingPromoClick() {
|
|
||||||
analyticsEventHandler.send(
|
|
||||||
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
|
|
||||||
source = AnalyticsParam.ScreensSources.Main,
|
|
||||||
programName = TokenSwapPromoAnalyticsEvent.ProgramName.Ring,
|
|
||||||
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
|
||||||
shouldShowRingPromoUseCase.neverToShow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSupportClick() {
|
override fun onSupportClick() {
|
||||||
val scanResponse = getSelectedUserWallet()?.scanResponse ?: return
|
val scanResponse = getSelectedUserWallet()?.scanResponse ?: return
|
||||||
val cardInfo = getCardInfoUseCase(scanResponse).getOrNull() ?: return
|
val cardInfo = getCardInfoUseCase(scanResponse).getOrNull() ?: return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue