Updated on 2026-08-14
This commit is contained in:
commit
81bd9875e0
87 changed files with 1128 additions and 225 deletions
|
|
@ -121,4 +121,38 @@ 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ 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.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
|
||||
|
|
@ -44,6 +46,10 @@ 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(
|
||||
source = AnalyticsParam.ScreensSources.Main,
|
||||
programName = "Travala",
|
||||
)
|
||||
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
|
||||
is WalletNotification.Informational.NoAccount,
|
||||
is WalletNotification.Warning.LowSignatures,
|
||||
|
|
|
|||
|
|
@ -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.ShouldShowSwapPromoWalletUseCase
|
||||
import com.tangem.domain.settings.ShouldShowTravalaPromoWalletUseCase
|
||||
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 shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase,
|
||||
private val shouldShowTravalaPromoWalletUseCase: ShouldShowTravalaPromoWalletUseCase,
|
||||
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 promoFlow = flow { emit(promoRepository.getChangellyPromoBanner()) }
|
||||
val travalaPromoFlow = flow { emit(promoRepository.getTravalaPromoBanner()) }
|
||||
return combine(
|
||||
flow = getTokenListUseCase.launch(userWallet.walletId).conflate(),
|
||||
flow2 = isReadyToShowRateAppUseCase().conflate(),
|
||||
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
|
||||
flow4 = shouldShowSwapPromoWalletUseCase().conflate(),
|
||||
flow5 = promoFlow,
|
||||
) { maybeTokenList, isReadyToShowRating, isNeedToBackup, shouldShowPromo, promoBanner ->
|
||||
flow4 = shouldShowTravalaPromoWalletUseCase().conflate(),
|
||||
flow5 = travalaPromoFlow.conflate(),
|
||||
) { maybeTokenList, isReadyToShowRating, isNeedToBackup, shouldShowTravalaPromo, promoBanner ->
|
||||
|
||||
readyForRateAppNotification = true
|
||||
buildList {
|
||||
addSwapPromoNotification(shouldShowPromo, promoBanner, clickIntents)
|
||||
addTravalaPromoNotification(shouldShowTravalaPromo, promoBanner, clickIntents)
|
||||
|
||||
addCriticalNotifications(userWallet)
|
||||
|
||||
|
|
@ -69,16 +69,18 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addSwapPromoNotification(
|
||||
private fun MutableList<WalletNotification>.addTravalaPromoNotification(
|
||||
shouldShowPromo: Boolean,
|
||||
promoBanner: PromoBanner?,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
promoBanner ?: return
|
||||
val promoNotification = WalletNotification.SwapPromo(
|
||||
val promoNotification = WalletNotification.TravalaPromo(
|
||||
startDateTime = promoBanner.bannerState.timeline.start,
|
||||
endDateTime = promoBanner.bannerState.timeline.end,
|
||||
onCloseClick = clickIntents::onCloseSwapPromoClick,
|
||||
bannerLink = promoBanner.bannerState.link,
|
||||
onBookNowButtonClick = clickIntents::onTravalaPromoClick,
|
||||
onCloseClick = clickIntents::onCloseTravalaPromoClick,
|
||||
)
|
||||
addIf(
|
||||
element = promoNotification,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ internal object WalletImageResolver {
|
|||
cardTypesResolver.isJrWallet() -> userWallet.resolveJrWallet()
|
||||
cardTypesResolver.isGrimWallet() -> userWallet.resolveGrimWallet()
|
||||
cardTypesResolver.isSatoshiFriendsWallet() -> userWallet.resolveSatoshiWallet()
|
||||
cardTypesResolver.isBitcoinPizzaDayWallet() -> userWallet.resolveBitcoinPizzaDayWallet()
|
||||
cardTypesResolver.isVeChainWallet() -> userWallet.resolveVeChainWallet()
|
||||
cardTypesResolver.isNewWorldEliteWallet() -> userWallet.resolveNewWorldEliteWallet()
|
||||
cardTypesResolver.isWallet2() -> userWallet.resolveWallet2()
|
||||
cardTypesResolver.isShibaWallet() -> userWallet.resolveShibaWallet()
|
||||
cardTypesResolver.isTangemWallet() -> userWallet.resolveWallet1()
|
||||
|
|
@ -130,6 +133,27 @@ internal object WalletImageResolver {
|
|||
)
|
||||
}
|
||||
|
||||
private fun UserWallet.resolveBitcoinPizzaDayWallet(): Int? {
|
||||
return resolveWallet2(
|
||||
oneBackupResId = R.drawable.ill_pizza_day_card2_120_106,
|
||||
twoBackupResId = R.drawable.ill_pizza_day_card3_120_106,
|
||||
)
|
||||
}
|
||||
|
||||
private fun UserWallet.resolveVeChainWallet(): Int? {
|
||||
return resolveWallet2(
|
||||
oneBackupResId = R.drawable.ill_vechain_card2_120_106,
|
||||
twoBackupResId = R.drawable.ill_vechain_card3_120_106,
|
||||
)
|
||||
}
|
||||
|
||||
private fun UserWallet.resolveNewWorldEliteWallet(): Int? {
|
||||
return resolveWallet2(
|
||||
oneBackupResId = R.drawable.ill_nwe_card2_120_106,
|
||||
twoBackupResId = R.drawable.ill_nwe_card3_120_106,
|
||||
)
|
||||
}
|
||||
|
||||
private fun UserWallet.resolveWallet1(): Int? {
|
||||
return resolveWalletWithBackups { count ->
|
||||
when (count) {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@ 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.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.extensions.*
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import org.joda.time.DateTime
|
||||
|
||||
|
|
@ -173,6 +171,34 @@ sealed class WalletNotification(val config: NotificationConfig) {
|
|||
),
|
||||
)
|
||||
|
||||
data class TravalaPromo(
|
||||
val startDateTime: DateTime,
|
||||
val endDateTime: DateTime,
|
||||
val bannerLink: String?,
|
||||
val onBookNowButtonClick: (String?) -> Unit,
|
||||
val onCloseClick: () -> Unit,
|
||||
) : WalletNotification(
|
||||
config = NotificationConfig(
|
||||
title = resourceReference(id = R.string.main_travala_promotion_title),
|
||||
subtitle = resourceReference(
|
||||
id = R.string.main_travala_promotion_description,
|
||||
wrappedList(
|
||||
DateTimeFormatters.formatDate(startDateTime, DateTimeFormatters.dateMMMMd),
|
||||
DateTimeFormatters.formatDate(endDateTime, DateTimeFormatters.dateMMMMd),
|
||||
),
|
||||
),
|
||||
// Stub. Travala has its own Composable implementation with correct img
|
||||
iconResId = R.drawable.ic_star_24,
|
||||
// Stub. Travala has its own Composable implementation with correct img
|
||||
backgroundResId = R.drawable.ic_star_24,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
onClick = { onBookNowButtonClick(bannerLink) },
|
||||
text = resourceReference(R.string.main_travala_promotion_button),
|
||||
),
|
||||
onCloseClick = onCloseClick,
|
||||
),
|
||||
)
|
||||
|
||||
data class SwapPromo(
|
||||
val startDateTime: DateTime,
|
||||
val endDateTime: DateTime,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ 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.TravalaNotificationWithBackground
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -25,23 +26,33 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
|||
key = { it::class.java },
|
||||
contentType = { it::class.java },
|
||||
itemContent = {
|
||||
if (it is WalletNotification.SwapPromo) {
|
||||
NotificationWithBackground(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
)
|
||||
} else {
|
||||
Notification(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
iconTint = when (it) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
// TODO develop promo banner general component
|
||||
when (it) {
|
||||
is WalletNotification.SwapPromo -> {
|
||||
NotificationWithBackground(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
)
|
||||
}
|
||||
is WalletNotification.TravalaPromo -> {
|
||||
TravalaNotificationWithBackground(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Notification(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
iconTint = when (it) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.UpdateWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
|
||||
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
|
||||
|
|
@ -32,9 +36,13 @@ internal class WalletCardClickIntentsImplementor @Inject constructor(
|
|||
private val stateHolder: WalletStateController,
|
||||
private val walletEventSender: WalletEventSender,
|
||||
private val walletScreenContentLoader: WalletScreenContentLoader,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val updateWalletUseCase: UpdateWalletUseCase,
|
||||
private val deleteWalletUseCase: DeleteWalletUseCase,
|
||||
private val deleteSavedAccessCodesUseCase: DeleteSavedAccessCodesUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : BaseWalletClickIntents(), WalletCardClickIntents {
|
||||
|
||||
|
|
@ -72,7 +80,18 @@ internal class WalletCardClickIntentsImplementor @Inject constructor(
|
|||
override fun onDeleteAfterConfirmationClick(userWalletId: UserWalletId) {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
walletScreenContentLoader.cancel(userWalletId)
|
||||
|
||||
val deletedUserWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: return@launch
|
||||
|
||||
deleteSavedAccessCodesUseCase(cardId = deletedUserWallet.cardId)
|
||||
.onLeft { Timber.e(it.toString()) }
|
||||
|
||||
deleteWalletUseCase(userWalletId)
|
||||
.onRight {
|
||||
getSelectedWalletSyncUseCase().getOrNull()?.let {
|
||||
reduxStateHolder.onUserWalletSelected(it)
|
||||
}
|
||||
}
|
||||
.onLeft { Timber.e(it.toString()) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.redux.ReduxStateHolder
|
|||
import com.tangem.domain.settings.NeverToSuggestRateAppUseCase
|
||||
import com.tangem.domain.settings.RemindToRateAppLaterUseCase
|
||||
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.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
|
||||
|
|
@ -19,6 +20,7 @@ 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
|
||||
|
|
@ -56,6 +58,10 @@ internal interface WalletWarningsClickIntents {
|
|||
fun onCloseRateAppWarningClick()
|
||||
|
||||
fun onCloseSwapPromoClick()
|
||||
|
||||
fun onTravalaPromoClick(link: String?)
|
||||
|
||||
fun onCloseTravalaPromoClick()
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
|
|
@ -75,6 +81,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase,
|
||||
private val shouldShowTravalaPromoWalletUseCase: ShouldShowTravalaPromoWalletUseCase,
|
||||
) : BaseWalletClickIntents(), WalletWarningsClickIntents {
|
||||
|
||||
override fun onAddBackupCardClick() {
|
||||
|
|
@ -212,6 +219,34 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onTravalaPromoClick(link: String?) {
|
||||
analyticsEventHandler.send(
|
||||
WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked(
|
||||
source = AnalyticsParam.ScreensSources.Main,
|
||||
programName = "Travala",
|
||||
action = WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked.BannerAction.Clicked,
|
||||
),
|
||||
)
|
||||
link?.let {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
router.openUrl(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCloseTravalaPromoClick() {
|
||||
analyticsEventHandler.send(
|
||||
WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked(
|
||||
source = AnalyticsParam.ScreensSources.Main,
|
||||
programName = "Travala",
|
||||
action = WalletScreenAnalyticsEvent.Promotion.PromotionBannerClicked.BannerAction.Closed,
|
||||
),
|
||||
)
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
shouldShowTravalaPromoWalletUseCase.neverToShow()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getSelectedUserWallet(): UserWallet? {
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
return getUserWalletUseCase(userWalletId).getOrElse {
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 129 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Loading…
Add table
Add a link
Reference in a new issue