Updated on 2026-08-14
This commit is contained in:
commit
3b596e41d5
14 changed files with 914 additions and 177 deletions
|
|
@ -9,6 +9,8 @@ import kotlin.coroutines.suspendCoroutine
|
|||
|
||||
object TangemSiteUrlBuilder {
|
||||
|
||||
const val NOTE_MIGRATION_URL = "https://tangem.com/en/?promocode=Note10"
|
||||
|
||||
suspend fun getUtmTags(campaign: String?): String {
|
||||
val langCode = Locale.getDefault().language
|
||||
val utmCampaignPart = campaign?.let { "&utm_campaign=$it-$langCode" }.orEmpty()
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ fun LazyListScope.notifications(
|
|||
contentColor = contentColor,
|
||||
modifier = modifier
|
||||
.padding(top = topPadding)
|
||||
.animateItem(),
|
||||
.animateItem(null, null, null),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.flicker
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig.ButtonsState
|
||||
import com.tangem.core.ui.ds.button.*
|
||||
import com.tangem.core.ui.ds.image.TangemIcon
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
|
@ -58,7 +58,15 @@ fun TangemMessage(
|
|||
if (messageUM.iconUM != null) {
|
||||
TangemIcon(
|
||||
tangemIconUM = messageUM.iconUM,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x8),
|
||||
modifier = Modifier
|
||||
.align(
|
||||
if (messageUM.buttonsUM.isEmpty()) {
|
||||
Alignment.CenterVertically
|
||||
} else {
|
||||
Alignment.Top
|
||||
},
|
||||
)
|
||||
.size(TangemTheme.dimens2.x7),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
@ -342,6 +350,7 @@ private class TangemMessagePreviewProvider : PreviewParameterProvider<TangemMess
|
|||
id = "1",
|
||||
title = stringReference("Title text"),
|
||||
subtitle = stringReference("Subtext"),
|
||||
iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
isCentered = true,
|
||||
),
|
||||
|
|
@ -350,6 +359,7 @@ private class TangemMessagePreviewProvider : PreviewParameterProvider<TangemMess
|
|||
title = stringReference("Title text"),
|
||||
subtitle = stringReference("Subtext"),
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24),
|
||||
isCentered = false,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
|
|
@ -405,9 +415,8 @@ private fun TangemMessage2_Preview() {
|
|||
content = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens2.x10)
|
||||
.size(TangemTheme.dimens2.x7)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens2.x2))
|
||||
.flicker(isFlickering = true)
|
||||
.background(TangemTheme.colors2.text.neutral.primary),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.*
|
|||
import com.tangem.feature.wallet.child.wallet.model.WalletActivationBannerType
|
||||
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.analytics.WalletScreenAnalyticsEvent.PushBannerPromo.*
|
||||
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.analytics.WalletScreenAnalyticsEvent.PushBannerPromo.PushBanner
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -34,10 +33,29 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun send(displayedWalletUM: WalletUM?, newNotifications: List<WalletNotificationUM>) {
|
||||
if (screenLifecycleProvider.isBackgroundState.value) return
|
||||
if (newNotifications.isEmpty()) return
|
||||
if (displayedWalletUM == null || displayedWalletUM.pullToRefreshConfig.isRefreshing) return
|
||||
|
||||
val totalNotifications = displayedWalletUM.notifications + displayedWalletUM.notificationsCarousel
|
||||
val notificationsDiff = newNotifications.filter { it !in totalNotifications }
|
||||
|
||||
val eventsToSend = getEvents2(notificationsDiff)
|
||||
|
||||
eventsToSend.forEach { event ->
|
||||
analyticsEventHandler.send(event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEvents(warnings: List<WalletNotification>): Set<AnalyticsEvent> {
|
||||
return warnings.mapNotNullTo(mutableSetOf(), ::getEvent)
|
||||
}
|
||||
|
||||
private fun getEvents2(notifications: List<WalletNotificationUM>): Set<AnalyticsEvent> {
|
||||
return notifications.mapNotNullTo(mutableSetOf(), ::getEvent2)
|
||||
}
|
||||
|
||||
@Suppress("CyclomaticComplexMethod")
|
||||
private fun getEvent(warning: WalletNotification): AnalyticsEvent? {
|
||||
return when (warning) {
|
||||
|
|
@ -106,4 +124,53 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
is WalletNotification.UpgradeHotWalletPromo -> null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("CyclomaticComplexMethod")
|
||||
private fun getEvent2(notificationUM: WalletNotificationUM): AnalyticsEvent? {
|
||||
return when (notificationUM) {
|
||||
WalletNotificationUM.DevCard -> DevelopmentCard()
|
||||
WalletNotificationUM.FailedCardValidation -> ProductSampleCard()
|
||||
is WalletNotificationUM.MissingBackup -> BackupYourWallet()
|
||||
is WalletNotificationUM.NumberOfSignedHashesIncorrect -> CardSignedTransactions()
|
||||
WalletNotificationUM.TestnetCard -> TestnetCard()
|
||||
WalletNotificationUM.DemoCard -> DemoCard()
|
||||
is WalletNotificationUM.MissingAddresses -> MissingAddresses()
|
||||
is WalletNotificationUM.RateApp -> HowDoYouLikeTangem()
|
||||
is WalletNotificationUM.BackupError -> BackupError()
|
||||
is WalletNotificationUM.NoteMigration -> NotePromo()
|
||||
is WalletNotificationUM.OnePlusOnePromo -> NoticePromotionBanner(
|
||||
source = AnalyticsParam.ScreensSources.Main,
|
||||
program = Program.OnePlusOne,
|
||||
)
|
||||
is WalletNotificationUM.YieldPromo -> NoticePromotionBanner(
|
||||
source = AnalyticsParam.ScreensSources.Main,
|
||||
program = Program.YieldPromo,
|
||||
)
|
||||
is WalletNotificationUM.FinishWalletActivation -> {
|
||||
val activationState = if (notificationUM.isBackupExists) {
|
||||
NoticeFinishActivation.ActivationState.Unfinished
|
||||
} else {
|
||||
NoticeFinishActivation.ActivationState.NotStarted
|
||||
}
|
||||
val balanceState = when (notificationUM.type) {
|
||||
WalletNotificationType.Warning -> AnalyticsParam.EmptyFull.Full
|
||||
else -> AnalyticsParam.EmptyFull.Empty
|
||||
}
|
||||
NoticeFinishActivation(
|
||||
activationState = activationState,
|
||||
balanceState = balanceState,
|
||||
)
|
||||
}
|
||||
is WalletNotificationUM.SeedPhraseNotification -> NoticeSeedPhraseSupport()
|
||||
is WalletNotificationUM.SeedPhraseSecondNotification -> NoticeSeedPhraseSupportSecond()
|
||||
is WalletNotificationUM.PushNotifications -> PushBanner()
|
||||
is WalletNotificationUM.UnlockWallets,
|
||||
is WalletNotificationUM.NoAccount,
|
||||
is WalletNotificationUM.LowSignatures,
|
||||
WalletNotificationUM.SomeNetworksUnreachable,
|
||||
is WalletNotificationUM.UsedOutdatedData,
|
||||
is WalletNotificationUM.CloreMigration,
|
||||
-> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,12 +4,8 @@ import com.tangem.common.routing.AppRoute.WalletBackup
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
|
||||
import com.tangem.core.ui.components.bottomsheets.message.icon
|
||||
import com.tangem.core.ui.components.bottomsheets.message.infoBlock
|
||||
import com.tangem.core.ui.components.bottomsheets.message.onClick
|
||||
import com.tangem.core.ui.components.bottomsheets.message.primaryButton
|
||||
import com.tangem.core.ui.components.bottomsheets.message.secondaryButton
|
||||
import com.tangem.core.ui.components.bottomsheets.message.*
|
||||
import com.tangem.core.ui.ds.message.TangemMessageEffect
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.bottomSheetMessage
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
|
|
@ -19,7 +15,9 @@ import com.tangem.domain.wallets.usecase.SeedPhraseNotificationUseCase
|
|||
import com.tangem.feature.wallet.child.wallet.model.WalletActivationBannerType
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
|
@ -71,6 +69,44 @@ internal class WalletWarningsSingleEventSender @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun send(
|
||||
userWalletId: UserWalletId,
|
||||
displayedWalletUM: WalletUM?,
|
||||
newNotifications: List<WalletNotificationUM>,
|
||||
) {
|
||||
if (screenLifecycleProvider.isBackgroundState.value) return
|
||||
if (newNotifications.isEmpty()) return
|
||||
if (displayedWalletUM == null || displayedWalletUM.pullToRefreshConfig.isRefreshing) return
|
||||
|
||||
val totalNotifications = displayedWalletUM.notifications + displayedWalletUM.notificationsCarousel
|
||||
val events = newNotifications.filter { it !in totalNotifications }
|
||||
|
||||
// We must show activation bs only for the first seen wallet when open the app (if need, see conditions below),
|
||||
// so we keep this wallet id and use for future checks, ignore other wallets during the app session.
|
||||
if (isActivationBottomSheetShown.isEmpty()) {
|
||||
isActivationBottomSheetShown[userWalletId] = false
|
||||
}
|
||||
|
||||
events.forEach { event ->
|
||||
when (event) {
|
||||
is WalletNotificationUM.SeedPhraseNotification -> {
|
||||
seedPhraseNotificationUseCase.notified(userWalletId = userWalletId)
|
||||
}
|
||||
is WalletNotificationUM.FinishWalletActivation -> {
|
||||
// We check that map contains the first seen wallet (will return null instead false/true otherwise)
|
||||
// and for this wallet we haven't shown the activation bs yet (check that returns false, not true)
|
||||
if (isActivationBottomSheetShown[userWalletId] == false) {
|
||||
if (event.messageEffect == TangemMessageEffect.Warning && event.isBackupExists.not()) {
|
||||
showFinishActivationBottomSheet(userWalletId)
|
||||
}
|
||||
isActivationBottomSheetShown[userWalletId] = true
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFinishActivationBottomSheet(userWalletId: UserWalletId) {
|
||||
val userWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: return
|
||||
if (userWallet !is UserWallet.Hot) return
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import com.tangem.common.TangemSiteUrlBuilder
|
||||
import com.tangem.common.ui.notifications.NotificationId
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.promo.ShouldShowPromoWalletUseCase
|
||||
import com.tangem.domain.promo.models.PromoId
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.utils.extensions.addIf
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Factory for creating a list of notifications that can be shown on the wallet screen.
|
||||
* These notifications are not critical and can be stacked with each other.
|
||||
*/
|
||||
@ModelScoped
|
||||
internal class GetWalletNotificationsCarouselFactory @Inject constructor(
|
||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val shouldShowPromoWalletUseCase: ShouldShowPromoWalletUseCase,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
) {
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotificationUM>> {
|
||||
return combine(
|
||||
flow = shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.YieldPromo)
|
||||
.distinctUntilChanged(),
|
||||
flow2 = notificationsRepository.getShouldShowNotification(
|
||||
NotificationId.EnablePushesReminderNotification.key,
|
||||
).distinctUntilChanged(),
|
||||
flow3 = shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.OnePlusOne)
|
||||
.distinctUntilChanged(),
|
||||
flow4 = isReadyToShowRateAppUseCase().distinctUntilChanged(),
|
||||
flow5 = getWalletsUseCase().conflate(),
|
||||
) { showYieldPromo, showPushesNotification, showOnePlusOnePromo, showRateAppPromo, wallets ->
|
||||
|
||||
buildList {
|
||||
addNoteMigrationNotification(userWallet, wallets, clickIntents)
|
||||
addRateAppNotification(showRateAppPromo, clickIntents)
|
||||
addOnePlusOnePromoNotification(clickIntents, showOnePlusOnePromo)
|
||||
addYieldPromoNotification(clickIntents, showYieldPromo)
|
||||
|
||||
addPushNotification(
|
||||
shouldShow = showPushesNotification,
|
||||
isPushesAllowed = notificationsRepository.isUserAllowToSubscribeOnPushNotifications(),
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
}.sortedBy { it.type.ordinal }.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addRateAppNotification(
|
||||
isReadyToShowRating: Boolean,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
addIf(isReadyToShowRating) {
|
||||
WalletNotificationUM.RateApp(
|
||||
onLikeClick = clickIntents::onLikeAppClick,
|
||||
onDislikeClick = clickIntents::onDislikeAppClick,
|
||||
onCloseClick = clickIntents::onCloseRateAppWarningClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addYieldPromoNotification(
|
||||
clickIntents: WalletClickIntents,
|
||||
shouldShowPromo: Boolean,
|
||||
) {
|
||||
addIf(shouldShowPromo) {
|
||||
WalletNotificationUM.YieldPromo(
|
||||
onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.YieldPromo) },
|
||||
onTermsAndConditionsClick = { clickIntents.onYieldPromoTermsAndConditionsClick() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addOnePlusOnePromoNotification(
|
||||
clickIntents: WalletClickIntents,
|
||||
shouldShowPromo: Boolean,
|
||||
) {
|
||||
addIf(shouldShowPromo) {
|
||||
WalletNotificationUM.OnePlusOnePromo(
|
||||
onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.OnePlusOne) },
|
||||
onClick = { clickIntents.onPromoClick(promoId = PromoId.OnePlusOne) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addNoteMigrationNotification(
|
||||
userWallet: UserWallet,
|
||||
userWallets: List<UserWallet>,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
val cardTypesResolver = (userWallet as? UserWallet.Cold)?.scanResponse?.cardTypesResolver
|
||||
|
||||
val isUserHasWalletOrWallet2 = userWallets.filterIsInstance<UserWallet.Cold>().any { wallet ->
|
||||
val typesResolver = wallet.scanResponse.cardTypesResolver
|
||||
typesResolver.isTangemWallet() || typesResolver.isWallet2()
|
||||
}
|
||||
|
||||
addIf(cardTypesResolver != null && cardTypesResolver.isTangemNote() && !isUserHasWalletOrWallet2) {
|
||||
WalletNotificationUM.NoteMigration(
|
||||
onClick = { clickIntents.onNoteMigrationButtonClick(TangemSiteUrlBuilder.NOTE_MIGRATION_URL) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addPushNotification(
|
||||
shouldShow: Boolean,
|
||||
isPushesAllowed: Boolean,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
addIf(shouldShow && !isPushesAllowed) {
|
||||
WalletNotificationUM.PushNotifications(
|
||||
onCloseClick = clickIntents::onDenyPermissions,
|
||||
onEnabledClick = clickIntents::onAllowPermissions,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.ui.ds.message.TangemMessageEffect
|
||||
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
||||
import com.tangem.domain.card.CardTypesResolver
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.hotwallet.GetAccessCodeSkippedUseCase
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.models.SeedPhraseNotificationsStatus
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.domain.wallets.usecase.SeedPhraseNotificationUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.hot.sdk.model.HotWalletId
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.extensions.addIf
|
||||
import com.tangem.utils.extensions.isPositive
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Factory for creating a list of notifications that can be shown on the wallet screen.
|
||||
* These notifications are critical and should be shown separately from each other.
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@ModelScoped
|
||||
internal class GetWalletWarningsFactory @Inject constructor(
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
private val backupValidator: BackupValidator,
|
||||
private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase,
|
||||
private val accountDependencies: AccountDependencies,
|
||||
private val getAccessCodeSkippedUseCase: GetAccessCodeSkippedUseCase,
|
||||
private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase,
|
||||
) {
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotificationUM>> {
|
||||
val cardTypesResolver = (userWallet as? UserWallet.Cold)?.scanResponse?.cardTypesResolver
|
||||
|
||||
val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
|
||||
val accountStatusListFlow = accountDependencies.singleAccountStatusListSupplier(params)
|
||||
|
||||
return combine(
|
||||
flow = accountStatusListFlow,
|
||||
flow2 = isNeedToBackupUseCase(userWallet.walletId).distinctUntilChanged(),
|
||||
flow3 = seedPhraseNotificationUseCase(userWalletId = userWallet.walletId).distinctUntilChanged(),
|
||||
flow4 = getAccessCodeSkippedUseCase(userWallet.walletId).distinctUntilChanged(),
|
||||
) { accountList, isNeedToBackup, seedPhraseIssueStatus, shouldAccessCodeSkipped ->
|
||||
val totalFiatBalance = accountList.totalFiatBalance
|
||||
val flattenCurrencies = accountList.flattenCurrencies()
|
||||
|
||||
buildList {
|
||||
addUsedOutdatedDataNotification(totalFiatBalance)
|
||||
|
||||
addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents)
|
||||
|
||||
addFinishWalletActivationNotification(
|
||||
userWallet = userWallet,
|
||||
totalFiatBalance = totalFiatBalance,
|
||||
clickIntents = clickIntents,
|
||||
shouldAccessCodeSkipped = shouldAccessCodeSkipped,
|
||||
)
|
||||
|
||||
addInformationalNotifications(
|
||||
userWallet = userWallet,
|
||||
cardTypesResolver = cardTypesResolver,
|
||||
flattenCurrencies = flattenCurrencies,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
addWarningNotifications(
|
||||
userWallet = userWallet,
|
||||
cardTypesResolver = cardTypesResolver,
|
||||
flattenCurrencies = flattenCurrencies,
|
||||
isNeedToBackup = isNeedToBackup,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
}.sortedBy { it.type.ordinal }.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addUsedOutdatedDataNotification(totalFiatBalance: TotalFiatBalance) {
|
||||
addIf(
|
||||
element = WalletNotificationUM.UsedOutdatedData,
|
||||
condition = (totalFiatBalance as? TotalFiatBalance.Loaded)?.source == StatusSource.ONLY_CACHE,
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addCriticalNotifications(
|
||||
userWallet: UserWallet,
|
||||
seedPhraseIssueStatus: SeedPhraseNotificationsStatus,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
if (userWallet !is UserWallet.Cold) {
|
||||
return
|
||||
}
|
||||
|
||||
addSeedNotificationIfNeeded(userWallet, seedPhraseIssueStatus, clickIntents)
|
||||
|
||||
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
|
||||
addIf(
|
||||
element = WalletNotificationUM.BackupError { clickIntents.onSupportClick() },
|
||||
condition = !backupValidator.isValidBackupStatus(userWallet.scanResponse.card) || userWallet.hasBackupError,
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.DevCard,
|
||||
condition = !cardTypesResolver.isReleaseFirmwareType(),
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.FailedCardValidation,
|
||||
condition = cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.isAttestationFailed(),
|
||||
)
|
||||
|
||||
cardTypesResolver.getRemainingSignatures()?.let { remainingSignatures ->
|
||||
addIf(
|
||||
element = WalletNotificationUM.LowSignatures(count = remainingSignatures),
|
||||
condition = remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addInformationalNotifications(
|
||||
userWallet: UserWallet,
|
||||
cardTypesResolver: CardTypesResolver?,
|
||||
flattenCurrencies: List<CryptoCurrencyStatus>,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotificationUM.DemoCard,
|
||||
condition = cardTypesResolver != null && isDemoCardUseCase(cardId = cardTypesResolver.getCardId()),
|
||||
)
|
||||
|
||||
addMissingAddressesNotification(userWallet, flattenCurrencies, clickIntents)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addMissingAddressesNotification(
|
||||
userWallet: UserWallet,
|
||||
flattenCurrencies: List<CryptoCurrencyStatus>,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
val currencies = flattenCurrencies.getMissingAddressCurrencies().ifEmpty { return }
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.MissingAddresses(
|
||||
tangemIcon = walletInterationIcon(userWallet),
|
||||
missingAddressesCount = currencies.count(),
|
||||
onGenerateClick = {
|
||||
clickIntents.onGenerateMissedAddressesClick(missedAddressCurrencies = currencies)
|
||||
},
|
||||
),
|
||||
condition = currencies.isNotEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.getMissingAddressCurrencies(): List<CryptoCurrency> {
|
||||
return this
|
||||
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
|
||||
.map(CryptoCurrencyStatus::currency)
|
||||
}
|
||||
|
||||
private suspend fun MutableList<WalletNotificationUM>.addWarningNotifications(
|
||||
userWallet: UserWallet,
|
||||
cardTypesResolver: CardTypesResolver?,
|
||||
flattenCurrencies: List<CryptoCurrencyStatus>,
|
||||
isNeedToBackup: Boolean,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotificationUM.MissingBackup(
|
||||
onClick = clickIntents::onAddBackupCardClick,
|
||||
),
|
||||
condition = isNeedToBackup,
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.TestnetCard,
|
||||
condition = cardTypesResolver?.isTestCard() == true,
|
||||
)
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.SomeNetworksUnreachable,
|
||||
condition = flattenCurrencies.hasUnreachableNetworks(),
|
||||
)
|
||||
|
||||
addCloreMigrationNotification(flattenCurrencies, clickIntents)
|
||||
|
||||
addNoAccountWarning(cryptoCurrencyStatus = flattenCurrencies.firstOrNull())
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.NumberOfSignedHashesIncorrect(
|
||||
onCloseClick = clickIntents::onCloseAlreadySignedHashesWarningClick,
|
||||
),
|
||||
condition = hasSignedHashes(userWallet, flattenCurrencies.firstOrNull()),
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addNoAccountWarning(cryptoCurrencyStatus: CryptoCurrencyStatus?) {
|
||||
val noAccountStatus = cryptoCurrencyStatus?.value as? CryptoCurrencyStatus.NoAccount
|
||||
if (noAccountStatus != null) {
|
||||
add(
|
||||
element = WalletNotificationUM.NoAccount(
|
||||
network = cryptoCurrencyStatus.currency.name,
|
||||
amount = noAccountStatus.amountToCreateAccount.toString(),
|
||||
symbol = cryptoCurrencyStatus.currency.symbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addCloreMigrationNotification(
|
||||
flattenCurrencies: List<CryptoCurrencyStatus>,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
val cloreCurrency = flattenCurrencies.findCloreCurrency() ?: return
|
||||
|
||||
add(
|
||||
WalletNotificationUM.CloreMigration(
|
||||
onStartMigrationClick = { clickIntents.onCloreMigrationClick(cloreCurrency) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.findCloreCurrency(): CryptoCurrencyStatus? {
|
||||
return find { currencyStatus ->
|
||||
BlockchainUtils.isClore(currencyStatus.currency.network.rawId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.hasUnreachableNetworks(): Boolean {
|
||||
return any { it.value is CryptoCurrencyStatus.Unreachable }
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addFinishWalletActivationNotification(
|
||||
userWallet: UserWallet,
|
||||
totalFiatBalance: TotalFiatBalance,
|
||||
clickIntents: WalletClickIntents,
|
||||
shouldAccessCodeSkipped: Boolean,
|
||||
) {
|
||||
if (userWallet !is UserWallet.Hot) return
|
||||
|
||||
val isBackupExists = userWallet.backedUp
|
||||
val isAccessCodeRequired = userWallet.hotWalletId.authType == HotWalletId.AuthType.NoPassword &&
|
||||
!shouldAccessCodeSkipped
|
||||
val shouldShowFinishActivation = !isBackupExists || isAccessCodeRequired
|
||||
|
||||
val messageEffect = when (totalFiatBalance) {
|
||||
TotalFiatBalance.Failed,
|
||||
TotalFiatBalance.Loading,
|
||||
-> TangemMessageEffect.None
|
||||
is TotalFiatBalance.Loaded -> if (totalFiatBalance.amount.orZero().isPositive()) {
|
||||
TangemMessageEffect.Warning
|
||||
} else {
|
||||
TangemMessageEffect.None
|
||||
}
|
||||
}
|
||||
|
||||
addIf(
|
||||
element = WalletNotificationUM.FinishWalletActivation(
|
||||
messageEffect = messageEffect,
|
||||
onClick = { clickIntents.onFinishWalletActivationClick(isBackupExists) },
|
||||
isBackupExists = isBackupExists,
|
||||
),
|
||||
condition = shouldShowFinishActivation,
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotificationUM>.addSeedNotificationIfNeeded(
|
||||
userWallet: UserWallet.Cold,
|
||||
seedPhraseIssueStatus: SeedPhraseNotificationsStatus,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
val isNotificationAvailable = with(userWallet) {
|
||||
val isDemo = isDemoCardUseCase(cardId = userWallet.cardId)
|
||||
val isWalletWithSeedPhrase = scanResponse.cardTypesResolver.isWallet2() && userWallet.isImported
|
||||
|
||||
!isDemo && isWalletWithSeedPhrase
|
||||
}
|
||||
|
||||
when (seedPhraseIssueStatus) {
|
||||
SeedPhraseNotificationsStatus.SHOW_FIRST -> addIf(
|
||||
element = WalletNotificationUM.SeedPhraseNotification(
|
||||
onDeclineClick = clickIntents::onSeedPhraseNotificationDecline,
|
||||
onConfirmClick = clickIntents::onSeedPhraseNotificationConfirm,
|
||||
),
|
||||
condition = isNotificationAvailable,
|
||||
)
|
||||
SeedPhraseNotificationsStatus.SHOW_SECOND -> addIf(
|
||||
element = WalletNotificationUM.SeedPhraseSecondNotification(
|
||||
onDeclineClick = clickIntents::onSeedPhraseSecondNotificationReject,
|
||||
onConfirmClick = clickIntents::onSeedPhraseSecondNotificationAccept,
|
||||
),
|
||||
condition = isNotificationAvailable,
|
||||
)
|
||||
SeedPhraseNotificationsStatus.NOT_NEEDED -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun hasSignedHashes(
|
||||
selectedWallet: UserWallet,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
): Boolean {
|
||||
if (selectedWallet !is UserWallet.Cold || !selectedWallet.isMultiCurrency) return false
|
||||
val network = cryptoCurrencyStatus?.currency?.network ?: return false
|
||||
|
||||
return hasSingleWalletSignedHashesUseCase(userWallet = selectedWallet, network = network)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.firstOrNull() == true
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_REMAINING_SIGNATURES_COUNT = 10
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,17 @@ import androidx.compose.runtime.Immutable
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
/** Wallet card state */
|
||||
/**
|
||||
* Represents the state of the wallet balance in the UI.
|
||||
*
|
||||
* The sealed interface has three implementations:
|
||||
* - [Content]: Represents the state when the wallet balance is successfully loaded.
|
||||
* - [Error]: Represents the state when there was an error loading the wallet balance.
|
||||
* - [Loading]: Represents the state when the wallet balance is currently being loaded.
|
||||
*
|
||||
* @property id The unique identifier of the wallet.
|
||||
* @property name The name of the wallet.
|
||||
*/
|
||||
@Immutable
|
||||
internal sealed interface WalletBalanceUM {
|
||||
|
||||
|
|
@ -27,7 +37,6 @@ internal sealed interface WalletBalanceUM {
|
|||
val balance: TextReference,
|
||||
val isBalanceFlickering: Boolean,
|
||||
val isZeroBalance: Boolean?,
|
||||
|
||||
) : WalletBalanceUM
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,14 +34,33 @@ internal enum class WalletNotificationType {
|
|||
*/
|
||||
internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val type: WalletNotificationType) {
|
||||
|
||||
data object DevCard : WalletNotificationUM(
|
||||
// region Status
|
||||
data object SomeNetworksUnreachable : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "DevCardNotification",
|
||||
title = resourceReference(id = R.string.warning_developer_card_title),
|
||||
subtitle = resourceReference(id = R.string.warning_developer_card_message),
|
||||
id = "SomeNetworksUnreachableNotification",
|
||||
title = resourceReference(id = R.string.warning_some_networks_unreachable_title),
|
||||
subtitle = resourceReference(id = R.string.warning_some_networks_unreachable_message),
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Warning,
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data object UsedOutdatedData : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "UsedOutdatedDataNotification",
|
||||
title = stringReference("Missing some token balances"), // todo redesign main lokalise
|
||||
subtitle = stringReference("Will be updated as soon as possible"), // todo redesign main lokalise
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_error_sync_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data object FailedCardValidation : WalletNotificationUM(
|
||||
|
|
@ -49,17 +68,69 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
id = "FailedCardValidationNotification",
|
||||
title = resourceReference(id = R.string.warning_failed_to_verify_card_title),
|
||||
subtitle = resourceReference(id = R.string.warning_failed_to_verify_card_message),
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data object DevCard : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "DevCardNotification",
|
||||
title = resourceReference(id = R.string.warning_developer_card_title),
|
||||
subtitle = resourceReference(id = R.string.warning_developer_card_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data object TestnetCard : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "TestnetCardNotification",
|
||||
title = resourceReference(id = R.string.warning_testnet_card_title),
|
||||
subtitle = resourceReference(id = R.string.warning_testnet_card_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data object DemoCard : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "DemoCardNotification",
|
||||
title = resourceReference(id = R.string.warning_demo_mode_title),
|
||||
subtitle = resourceReference(id = R.string.warning_demo_mode_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
// endregion
|
||||
|
||||
// region Critical
|
||||
data class BackupError(val onClick: () -> Unit) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "BackupErrorNotification",
|
||||
title = resourceReference(id = R.string.warning_backup_errors_title),
|
||||
subtitle = resourceReference(id = R.string.warning_backup_errors_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(id = R.string.common_contact_support),
|
||||
|
|
@ -68,7 +139,7 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Warning,
|
||||
type = WalletNotificationType.Critical,
|
||||
)
|
||||
|
||||
data class SeedPhraseNotification(
|
||||
|
|
@ -92,6 +163,10 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
onClick = onConfirmClick,
|
||||
),
|
||||
),
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Critical,
|
||||
)
|
||||
|
|
@ -105,6 +180,10 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
title = resourceReference(id = R.string.warning_seedphrase_action_required_title),
|
||||
subtitle = resourceReference(id = R.string.warning_seedphrase_contacted_support),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(id = R.string.seed_warning_no),
|
||||
|
|
@ -117,6 +196,7 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
onClick = onConfirmClick,
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
type = WalletNotificationType.Critical,
|
||||
)
|
||||
|
|
@ -127,6 +207,10 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
title = resourceReference(id = R.string.warning_no_backup_title),
|
||||
subtitle = resourceReference(id = R.string.warning_no_backup_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(id = R.string.button_start_backup_process),
|
||||
|
|
@ -138,37 +222,6 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
type = WalletNotificationType.Critical,
|
||||
)
|
||||
|
||||
data object SomeNetworksUnreachable : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "SomeNetworksUnreachableNotification",
|
||||
title = resourceReference(id = R.string.warning_some_networks_unreachable_title),
|
||||
subtitle = resourceReference(id = R.string.warning_some_networks_unreachable_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data class NumberOfSignedHashesIncorrect(val onCloseClick: () -> Unit) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "NumberOfSignedHashesIncorrectNotification",
|
||||
title = resourceReference(id = R.string.warning_number_of_signed_hashes_incorrect_title),
|
||||
subtitle = resourceReference(id = R.string.warning_number_of_signed_hashes_incorrect_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
onCloseClick = onCloseClick,
|
||||
),
|
||||
type = WalletNotificationType.Warning,
|
||||
)
|
||||
|
||||
data object TestnetCard : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "TestnetCardNotification",
|
||||
title = resourceReference(id = R.string.warning_testnet_card_title),
|
||||
subtitle = resourceReference(id = R.string.warning_testnet_card_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Warning,
|
||||
)
|
||||
|
||||
data class LowSignatures(val count: Int) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "LowSignaturesNotification",
|
||||
|
|
@ -177,11 +230,69 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
id = R.string.warning_low_signatures_message,
|
||||
formatArgs = wrappedList(count.toString()),
|
||||
),
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Critical,
|
||||
)
|
||||
|
||||
data class FinishWalletActivation(
|
||||
val messageEffect: TangemMessageEffect,
|
||||
val isBackupExists: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "FinishWalletActivationNotification",
|
||||
title = resourceReference(R.string.hw_activation_need_title),
|
||||
subtitle = if (isBackupExists) {
|
||||
resourceReference(R.string.hw_activation_need_warning_description)
|
||||
} else {
|
||||
resourceReference(R.string.hw_activation_need_description)
|
||||
},
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.img_knight_shield_32,
|
||||
tintReference = {
|
||||
when (messageEffect) {
|
||||
TangemMessageEffect.Warning -> TangemTheme.colors2.graphic.neutral.primary
|
||||
else -> TangemTheme.colors2.graphic.status.attention
|
||||
}
|
||||
},
|
||||
),
|
||||
messageEffect = messageEffect,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.hw_activation_need_finish),
|
||||
type = TangemButtonType.PrimaryInverse,
|
||||
onClick = onClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = when (messageEffect) {
|
||||
TangemMessageEffect.Warning -> WalletNotificationType.Critical
|
||||
else -> WalletNotificationType.Warning
|
||||
},
|
||||
)
|
||||
|
||||
data class NumberOfSignedHashesIncorrect(val onCloseClick: () -> Unit) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "NumberOfSignedHashesIncorrectNotification",
|
||||
title = resourceReference(id = R.string.warning_number_of_signed_hashes_incorrect_title),
|
||||
subtitle = resourceReference(id = R.string.warning_number_of_signed_hashes_incorrect_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.img_knight_shield_32,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
onCloseClick = onCloseClick,
|
||||
),
|
||||
type = WalletNotificationType.Critical,
|
||||
)
|
||||
// endregion
|
||||
|
||||
// region Warning
|
||||
data class MissingAddresses(
|
||||
@DrawableRes val tangemIcon: Int?,
|
||||
val missingAddressesCount: Int,
|
||||
|
|
@ -196,12 +307,11 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
formatArgs = wrappedList(missingAddressesCount),
|
||||
),
|
||||
isCentered = true,
|
||||
iconUM = tangemIcon?.let { TangemIconUM.Icon(it) },
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
messageEffect = TangemMessageEffect.Card,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(id = R.string.common_generate_addresses),
|
||||
type = TangemButtonType.PrimaryInverse,
|
||||
type = TangemButtonType.Primary,
|
||||
iconRes = tangemIcon,
|
||||
onClick = onGenerateClick,
|
||||
),
|
||||
|
|
@ -223,33 +333,6 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
type = WalletNotificationType.Warning,
|
||||
)
|
||||
|
||||
data object DemoCard : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "DemoCardNotification",
|
||||
title = resourceReference(id = R.string.warning_demo_mode_title),
|
||||
subtitle = resourceReference(id = R.string.warning_demo_mode_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Warning,
|
||||
)
|
||||
|
||||
data class NoteMigration(val onClick: () -> Unit) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "NoteMigrationNotification",
|
||||
title = resourceReference(R.string.wallet_promo_banner_title),
|
||||
subtitle = resourceReference(R.string.wallet_promo_banner_description),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.wallet_promo_banner_button_title),
|
||||
onClick = onClick,
|
||||
type = TangemButtonType.PrimaryInverse,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
data class UnlockWallets(val onClick: () -> Unit) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "UnlockWalletsNotification",
|
||||
|
|
@ -261,12 +344,76 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
),
|
||||
),
|
||||
onClick = onClick,
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
messageEffect = TangemMessageEffect.Card,
|
||||
isCentered = true,
|
||||
),
|
||||
type = WalletNotificationType.Warning,
|
||||
)
|
||||
// endregion
|
||||
|
||||
// region Promo
|
||||
data class NoteMigration(val onClick: () -> Unit) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "NoteMigrationNotification",
|
||||
title = resourceReference(R.string.wallet_promo_banner_title),
|
||||
subtitle = resourceReference(R.string.wallet_promo_banner_description),
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
isCentered = true,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.wallet_promo_banner_button_title),
|
||||
onClick = onClick,
|
||||
type = TangemButtonType.Primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
data class OnePlusOnePromo(
|
||||
val onCloseClick: () -> Unit,
|
||||
val onClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "OnePlusOnePromoNotification",
|
||||
title = resourceReference(R.string.notification_one_plus_one_title),
|
||||
subtitle = resourceReference(R.string.notification_one_plus_one_text),
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
onCloseClick = onCloseClick,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.notification_one_plus_one_button),
|
||||
type = TangemButtonType.Primary,
|
||||
onClick = onClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
data class YieldPromo(
|
||||
val onCloseClick: () -> Unit,
|
||||
val onTermsAndConditionsClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "YieldPromoNotification",
|
||||
title = resourceReference(R.string.notification_yield_promo_title),
|
||||
subtitle = resourceReference(R.string.notification_yield_promo_text),
|
||||
onCloseClick = onCloseClick,
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.notification_yield_promo_button),
|
||||
type = TangemButtonType.Primary,
|
||||
onClick = onTermsAndConditionsClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
// endregion
|
||||
|
||||
// region Survey
|
||||
data class RateApp(
|
||||
val onLikeClick: () -> Unit,
|
||||
val onDislikeClick: () -> Unit,
|
||||
|
|
@ -294,49 +441,9 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
),
|
||||
type = WalletNotificationType.Survey,
|
||||
)
|
||||
// endregion
|
||||
|
||||
data object UsedOutdatedData : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "UsedOutdatedDataNotification",
|
||||
title = stringReference("Missing some token balances"), // todo redesign main lokalise
|
||||
subtitle = stringReference("Will be updated as soon as possible"),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
),
|
||||
type = WalletNotificationType.Status,
|
||||
)
|
||||
|
||||
data class FinishWalletActivation(
|
||||
val messageEffect: TangemMessageEffect,
|
||||
val isBackupExists: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "FinishWalletActivationNotification",
|
||||
title = resourceReference(R.string.hw_activation_need_title),
|
||||
subtitle = if (isBackupExists) {
|
||||
resourceReference(R.string.hw_activation_need_warning_description)
|
||||
} else {
|
||||
resourceReference(R.string.hw_activation_need_description)
|
||||
},
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.img_knight_shield_32,
|
||||
tintReference = { TangemTheme.colors2.graphic.status.attention },
|
||||
),
|
||||
messageEffect = messageEffect,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.hw_activation_need_finish),
|
||||
type = TangemButtonType.PrimaryInverse,
|
||||
onClick = onClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = when (messageEffect) {
|
||||
TangemMessageEffect.Card -> WalletNotificationType.Critical
|
||||
else -> WalletNotificationType.Warning
|
||||
},
|
||||
)
|
||||
|
||||
// region Informational
|
||||
data class PushNotifications(
|
||||
val onCloseClick: () -> Unit,
|
||||
val onEnabledClick: () -> Unit,
|
||||
|
|
@ -346,7 +453,7 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
title = resourceReference(R.string.user_push_notification_banner_title),
|
||||
subtitle = resourceReference(R.string.user_push_notification_banner_subtitle),
|
||||
onCloseClick = onCloseClick,
|
||||
messageEffect = TangemMessageEffect.Card,
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.common_later),
|
||||
|
|
@ -385,45 +492,5 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t
|
|||
),
|
||||
type = WalletNotificationType.Informational,
|
||||
)
|
||||
|
||||
data class OnePlusOnePromo(
|
||||
val onCloseClick: () -> Unit,
|
||||
val onClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "OnePlusOnePromoNotification",
|
||||
title = resourceReference(R.string.notification_one_plus_one_title),
|
||||
subtitle = resourceReference(R.string.notification_one_plus_one_text),
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.notification_one_plus_one_button),
|
||||
type = TangemButtonType.PrimaryInverse,
|
||||
onClick = onCloseClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
|
||||
data class YieldPromo(
|
||||
val onCloseClick: () -> Unit,
|
||||
val onTermsAndConditionsClick: () -> Unit,
|
||||
) : WalletNotificationUM(
|
||||
messageUM = TangemMessageUM(
|
||||
id = "YieldPromoNotification",
|
||||
title = resourceReference(R.string.notification_yield_promo_title),
|
||||
subtitle = resourceReference(R.string.notification_yield_promo_text),
|
||||
onCloseClick = onCloseClick,
|
||||
messageEffect = TangemMessageEffect.Magic,
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(R.string.notification_yield_promo_button),
|
||||
type = TangemButtonType.Primary,
|
||||
onClick = onTermsAndConditionsClick,
|
||||
),
|
||||
),
|
||||
),
|
||||
type = WalletNotificationType.Promo,
|
||||
)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ internal sealed interface WalletUM {
|
|||
|
||||
val buttons: PersistentList<TangemButtonUM>
|
||||
val notifications: ImmutableList<WalletNotificationUM>
|
||||
val notificationsCarousel: ImmutableList<WalletNotificationUM>
|
||||
|
||||
val tokensListUM: WalletTokensListUM
|
||||
|
||||
|
|
@ -29,11 +30,11 @@ internal sealed interface WalletUM {
|
|||
override val walletsBalanceUM: WalletBalanceUM,
|
||||
override val buttons: PersistentList<TangemButtonUM>,
|
||||
override val notifications: ImmutableList<WalletNotificationUM>,
|
||||
override val notificationsCarousel: ImmutableList<WalletNotificationUM>,
|
||||
override val tokensListUM: WalletTokensListUM,
|
||||
override val nftState: WalletNFTItemUM,
|
||||
override val type: WalletType,
|
||||
override val tangemPayState: TangemPayState,
|
||||
val stackableNotifications: ImmutableList<WalletNotificationUM>,
|
||||
) : WalletUM
|
||||
|
||||
data class Locked(
|
||||
|
|
@ -42,6 +43,7 @@ internal sealed interface WalletUM {
|
|||
override val type: WalletType,
|
||||
override val notifications: ImmutableList<WalletNotificationUM> = persistentListOf(),
|
||||
) : WalletUM {
|
||||
override val notificationsCarousel: ImmutableList<WalletNotificationUM> = persistentListOf()
|
||||
override val pullToRefreshConfig = PullToRefreshConfig(false, {})
|
||||
override val tokensListUM: WalletTokensListUM = WalletTokensListUM.Empty // todo redesign main locked state
|
||||
override val nftState: WalletNFTItemUM = WalletNFTItemUM.Hidden
|
||||
|
|
|
|||
|
|
@ -2,14 +2,18 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import timber.log.Timber
|
||||
|
||||
internal class SetWarningsTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
private val warnings: ImmutableList<WalletNotification>,
|
||||
private val notifications: ImmutableList<WalletNotificationUM> = persistentListOf(),
|
||||
private val notificationsCarousel: ImmutableList<WalletNotificationUM> = persistentListOf(),
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
|
|
@ -26,6 +30,15 @@ internal class SetWarningsTransformer(
|
|||
}
|
||||
|
||||
override fun transform(walletUM: WalletUM): WalletUM {
|
||||
return walletUM // todo redesign main
|
||||
return when (walletUM) {
|
||||
is WalletUM.Content -> walletUM.copy(
|
||||
notifications = notifications,
|
||||
notificationsCarousel = notificationsCarousel,
|
||||
)
|
||||
is WalletUM.Locked -> {
|
||||
Timber.w("Impossible to update notifications for locked wallet")
|
||||
walletUM
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,12 +9,9 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWarningsTransformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
internal class MultiWalletWarningsSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
|
|
@ -37,7 +34,13 @@ internal class MultiWalletWarningsSubscriber(
|
|||
it.wallets.any { walletState -> walletState.walletCardState.id == userWallet.walletId }
|
||||
}
|
||||
|
||||
stateHolder.update(SetWarningsTransformer(userWallet.walletId, warnings))
|
||||
stateHolder.update(
|
||||
SetWarningsTransformer(
|
||||
userWalletId = userWallet.walletId,
|
||||
warnings = warnings,
|
||||
notifications = persistentListOf(),
|
||||
),
|
||||
)
|
||||
walletWarningsAnalyticsSender.send(displayedState, warnings)
|
||||
walletWarningsSingleEventSender.send(
|
||||
userWalletId = userWallet.walletId,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.GetWalletNotificationsCarouselFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.GetWalletWarningsFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWarningsTransformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class MultiWalletWarningsSubscriberV2(
|
||||
private val userWallet: UserWallet,
|
||||
private val stateHolder: WalletStateController,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
private val getWalletWarningsFactory: GetWalletWarningsFactory,
|
||||
private val getWalletNotificationsCarouselFactory: GetWalletNotificationsCarouselFactory,
|
||||
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
|
||||
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
|
||||
) : WalletSubscriber() {
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<ImmutableList<WalletNotificationUM>> {
|
||||
return combine(
|
||||
flow = getWalletWarningsFactory.create(userWallet, clickIntents).conflate().distinctUntilChanged(),
|
||||
flow2 = getWalletNotificationsCarouselFactory.create(userWallet, clickIntents).conflate()
|
||||
.distinctUntilChanged(),
|
||||
) { notifications, notificationsCarousel ->
|
||||
val displayedWalletUM = stateHolder.getWalletUM(userWallet.walletId)
|
||||
|
||||
// Wait until the wallet appears in the list
|
||||
stateHolder.uiState.first {
|
||||
it.wallets2.any { walletUM -> walletUM.walletsBalanceUM.id == userWallet.walletId }
|
||||
}
|
||||
|
||||
// If there are notifications, we need to filter out the RateApp notification from stackable notifications,
|
||||
// because it should not be shown together with other notifications.
|
||||
val alteredNotificationsCarousel = if (notifications.isNotEmpty()) {
|
||||
notificationsCarousel.filterNot { it is WalletNotificationUM.RateApp }
|
||||
} else {
|
||||
notificationsCarousel
|
||||
}.toPersistentList()
|
||||
|
||||
stateHolder.update(
|
||||
SetWarningsTransformer(
|
||||
userWalletId = userWallet.walletId,
|
||||
warnings = persistentListOf(),
|
||||
notifications = notifications,
|
||||
notificationsCarousel = alteredNotificationsCarousel,
|
||||
),
|
||||
)
|
||||
|
||||
val totalNotifications = (notifications + alteredNotificationsCarousel).toPersistentList()
|
||||
|
||||
walletWarningsAnalyticsSender.send(displayedWalletUM, totalNotifications)
|
||||
walletWarningsSingleEventSender.send(
|
||||
userWalletId = userWallet.walletId,
|
||||
displayedWalletUM = displayedWalletUM,
|
||||
newNotifications = totalNotifications,
|
||||
)
|
||||
|
||||
totalNotifications
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWarningsTransformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
|
|
@ -32,7 +33,7 @@ internal class SingleWalletNotificationsSubscriber(
|
|||
.onEach { warnings ->
|
||||
val displayedState = stateHolder.getWalletState(userWallet.walletId)
|
||||
|
||||
stateHolder.update(SetWarningsTransformer(userWallet.walletId, warnings))
|
||||
stateHolder.update(SetWarningsTransformer(userWallet.walletId, warnings, persistentListOf()))
|
||||
walletWarningsAnalyticsSender.send(displayedState, warnings)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue