From 299117f8c493042ae3653fb6e320e5cfb3ef7f99 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Feb 2026 16:24:37 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../local/preferences/PreferencesKeys.kt | 12 +++ .../drawable-hdpi/img_tangem_wallet_72.webp | Bin 0 -> 1850 bytes .../drawable-mdpi/img_tangem_wallet_72.webp | Bin 0 -> 1196 bytes .../drawable-xhdpi/img_tangem_wallet_72.webp | Bin 0 -> 2494 bytes .../drawable-xxhdpi/img_tangem_wallet_72.webp | Bin 0 -> 3978 bytes .../img_tangem_wallet_72.webp | Bin 0 -> 5266 bytes .../hotwallet/DefaultHotWalletRepository.kt | 76 ++++++++++++++++++ .../repository/HotWalletRepository.kt | 20 +++++ .../intents/WalletWarningsClickIntents.kt | 34 ++++++++ .../utils/WalletWarningsAnalyticsSender.kt | 34 ++++---- .../domain/GetMultiWalletWarningsFactory.kt | 65 +++++++++++++++ .../wallet/state/model/WalletNotification.kt | 18 +++++ .../components/common/WalletNotifications.kt | 9 +++ 13 files changed, 252 insertions(+), 16 deletions(-) create mode 100644 core/ui/src/main/res/drawable-hdpi/img_tangem_wallet_72.webp create mode 100644 core/ui/src/main/res/drawable-mdpi/img_tangem_wallet_72.webp create mode 100644 core/ui/src/main/res/drawable-xhdpi/img_tangem_wallet_72.webp create mode 100644 core/ui/src/main/res/drawable-xxhdpi/img_tangem_wallet_72.webp create mode 100644 core/ui/src/main/res/drawable-xxxhdpi/img_tangem_wallet_72.webp diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 544a55357f..eae141d861 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -132,6 +132,18 @@ object PreferencesKeys { val ACCESS_CODE_SKIPPED_STATES_KEY by lazy { stringPreferencesKey(name = "accessCodeSkippedStates") } + val SHOULD_SHOW_UPGRADE_BANNER_KEY by lazy { stringPreferencesKey(name = "shouldShowUpgradeBanner") } + + val SHOULD_SHOW_NEXT_TIME_UPGRADE_BANNER_KEY by lazy { + stringPreferencesKey(name = "shouldShowNextTimeUpgradeBanner") + } + + val UPGRADE_BANNER_CLOSURE_TIMESTAMP_KEY by lazy { stringPreferencesKey(name = "upgradeBannerClosureTimestamp") } + + val WALLET_CREATION_TIMESTAMP_KEY by lazy { stringPreferencesKey(name = "walletCreationTimestamp") } + + val HAS_HAD_FIRST_TOP_UP_KEY by lazy { stringPreferencesKey(name = "hasHadFirstTopUp") } + // region Notifications val NOTIFICATIONS_APPLICATION_ID_KEY by lazy { stringPreferencesKey(name = "notificationsApplicationId") } diff --git a/core/ui/src/main/res/drawable-hdpi/img_tangem_wallet_72.webp b/core/ui/src/main/res/drawable-hdpi/img_tangem_wallet_72.webp new file mode 100644 index 0000000000000000000000000000000000000000..a82e95d6ad26c873a357ff44c33fd8e3cbba1525 GIT binary patch literal 1850 zcmV-A2gUeONk&F82LJ$9MM6+kP&il$0000G0000`002+`06|PpNGSsV00E$NZIdAh z`XaI-YdmY)wsB|Mwr$(CZQ}>nw!LH9(-jw8nNvNP%d3c(0Q~QfI1x*6AWp=JA)0rM zBX8Os6cTYFRt%$hwPT+6ZYb08*AotbI1wv`xpD2&pZQ@ZQ~xvVtRgm&O2Rbn+6UeL z^*~7r9WgvR$Vh4vM%8jhJn&_INh`Xhtq>WpR+#Em+v&ECdZu+YzAi-(Ct`((7TN6j z_d2I^HrJV%5GOVjCbPhfSHIaZt^w|E{kWRbg*Q6=gaxMYDy9A#b1Q*me$a=<C~g?4xneb;KnLMB;7hVxEXY)@U5C_ryW>v@V%160PE59*=`AEDqQ^BXPZl%oB+b zVF&YA9CQtFz+M}P*R4zDjznhI!Db{5x^3!!y*Lt0;*y$3=zNKTOKn@CO`mNJfw%}CYl?0XTXw!rU z{*-itr0=3g*)NEe$6w9S?F!*pG1TGLcUBeN%sZ_Jl9tL$e0%*S4LDGJM{a8bwkqYF zUIb*%qNbak+I1d)rAkgv-w)RUfaf*;x?-q+!8cD_M!=Fv%ngN&pJ5%L%RMcsXepnS2P)VWC^Fm%7 zIetlt0l@QEu%y-y3fw+(b#08?)k^Ao1jUmfLcw!Pt8;h<-Gn={9!>UkkTZ0vCKEs65QKU2@w5#)MPjzdts z-?V!Eu}Bz4X#RJ#W#><-=foZe^F+sC09JcIz0X6S$K~}B<~X58y>FsW_Q<<;iRXIN z{{f3o>9?FFo#|~B;a;0F)2Ra)0WZ>2K2Jh#lk9VTrTZD@HR^x*-r*n0Kdt}K^_}(~`&I0v`w(DQ zLA}n?@NJ^K)aIG`ndda&DQr06Bz`E*siG=c0vs>nfTfg9Y?kZFEKLts z0092}pH${M2PGQ4V;^J-AM~E{jLY=YY3!3$O^Wm}8$aYaPAVx6fdR$rbtso4ljp?u zlcLr7xs+lXHs?kfDFEGndkCe=#EQu*YfQ{gRgGX~MSSmZMf_L&T}NlX-C6vfCKA8H z|D<0aD&3pRgc=9R*f(&)8~$hf*#)ug`7JzDq7k*4N$MD+@jywQP9e^m|1FIfT5ItT zJwA`bCk_&$o|oQ+!*?hAoe7|@XfFi?tm7$u9=H$Rg2KP{qr1<=@WDVN&t1Fa56g7RBOv$mcWa;W zS<7iNn@Fm?8lrh`n4$Bf3QAJ`c>6e1nuGiE6cLxVskBcq8xOGi(%OdIUA$dr!C_y( zmcaP*8XARn>Xm#|w4Y!AnaW!wC%(V}ot1y3F~;1z{Nw~ionde7F0o_#LP1_|%m*_L z%)b?=1a%In@=L>nANz5*cgo!#NT#y9XB5q&>9TF??7x8sRbC_~`IBNf{vJnlsx;|O zZ^^Dzvk&Q&6yiR(ULyv_@*f#R4aqLvNZ8J~GH}BF_>^O2o2F~Hl7(WTR4!7Xod5Rku`mH5>3pX+?OGH-pj?PJZYynYs+1#q!h` zoJ`s))I4gnZ(y`j6oHVe(gAp$+oynG=!V#I!nQ_zYgB2*Cp z_%R+@_zNX-Jdt<)w|ck)V<_6^D{_>77`(Tw$HayHhV`f-!7ST-;&b3otT^d*wdt3n zh-|b;FhJvD^R_>=qaa)Ft=GHUDCIg?DQui-|L&S}4BC>0$x@J?x(*%B*}-I$<@&8( oMcbsjz}2WEQO+mP6G`8Vf|oM%t9iLTKP2(T>ap|zOaK4?0FpVGzyJUM literal 0 HcmV?d00001 diff --git a/core/ui/src/main/res/drawable-mdpi/img_tangem_wallet_72.webp b/core/ui/src/main/res/drawable-mdpi/img_tangem_wallet_72.webp new file mode 100644 index 0000000000000000000000000000000000000000..bdfc895e3c0dd86d8f6220848226f17decf3dbc0 GIT binary patch literal 1196 zcmV;d1XKG`Nk&Gb1ONb6MM6+kP&il$0000G0000r001=r06|PpNb>;z00EE#0FWU` z)iu*S_qJ`@w*4RbL;q)1X4|%{*tTt+eLEF&&7xjuL`(qu&nwiPaZrg-=z7M%+~o(a zxRvPB35=CO*Ju~9{E(Hm6MYIE>P1VTYmAFnZpiZM@ga)%r;bcH+Gtc|`!BlkGel7@ z=>#c9dm2^A?sG4E$);Fujtg*{Mq>`Y%^;yUP5>m5=uVoONU|Rqu7fbjqZpJn&ST7d zVF`xOZG}-8v=mC)9cO{LFD%DlbQ@vROg@Ddv`| zAWU6UK*p9;L_{qhYz##u@#3hKuepp>h2f?(Iy|#Jf{a_!YPo=>>T6=3HU((!TYbZG z^8|!GZs?XDPEYvTZ52H77Wax}(O z5OxEf*`WboSUfW?3Q>Gc_SHN9P%%Vya&ZB@$$ni104lyBb`}WS#S8|3ey@qWg%TcF z2LNEaPwcmfAn~Ks0P3G2KB)nSd_hDH>u-)H{(DD|xr&GqDfo3m5Lzgn!hKK<#E#Am zN?lt31P}Vo_$M2H?2?mDT)8-ok z8(z%@H^cY{(?RkruK574zq=#;`ao%Cn$SwU6$Z_S4C_I7Z;YcIDNEC2xh z{>;8SlbmhH|HL3Heu^u)MZQlJ6w6s6xtULqA?UwmYQaAEyc_eFMT!{Qb<0iu8Hf0e z8CYvQk4QV}E-#_;=ED2sQ(wF1_{4s4vo#5guKyivGNzbza7uY!l-G@-k(iG<@fXKv z_o7Ki-o4$aSiP;*{-=gNsx*Re>UDbKzjxAlNMmB>v1LYC zPG~JOW^RwL_#m=hRx;U>?R=ZYm>7j8-F>WA7T0VXG%4@MYa3n}yB<)?_AF zp(U)_K}~&0dfXGP^>$QX*1`el${wtEO;?)kutIWP{lYs=11 zO{YfLituqqh0F@a{!au@PbaQmEnr$)l>_t@oH=vk64ro^WIw9&E2vcBzU?1^vgE`#ZA?$ Kp=k?7zyJX1g(`Ib literal 0 HcmV?d00001 diff --git a/core/ui/src/main/res/drawable-xhdpi/img_tangem_wallet_72.webp b/core/ui/src/main/res/drawable-xhdpi/img_tangem_wallet_72.webp new file mode 100644 index 0000000000000000000000000000000000000000..31d50c1c29889531c6626ded6c2e1effc1ea3cd3 GIT binary patch literal 2494 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 I^Nauh01<-EQvd(} literal 0 HcmV?d00001 diff --git a/core/ui/src/main/res/drawable-xxhdpi/img_tangem_wallet_72.webp b/core/ui/src/main/res/drawable-xxhdpi/img_tangem_wallet_72.webp new file mode 100644 index 0000000000000000000000000000000000000000..0fcc24fc07f71fdfaf51b03f350e8eec1761278e GIT binary patch literal 3978 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 = appPreferencesStore + .getObjectMap(PreferencesKeys.SHOULD_SHOW_UPGRADE_BANNER_KEY) + .map { it[userWalletId.stringValue] == true } + + override suspend fun setShouldShowUpgradeBanner(userWalletId: UserWalletId, shouldShow: Boolean) { + appPreferencesStore.editData { mutablePreferences -> + mutablePreferences.setObjectMap( + key = PreferencesKeys.SHOULD_SHOW_UPGRADE_BANNER_KEY, + value = mutablePreferences.getObjectMap(PreferencesKeys.SHOULD_SHOW_UPGRADE_BANNER_KEY) + .plus(userWalletId.stringValue to shouldShow), + ) + } + } + + override fun shouldShowNextTimeUpgradeBanner(userWalletId: UserWalletId): Flow = appPreferencesStore + .getObjectMap(PreferencesKeys.SHOULD_SHOW_NEXT_TIME_UPGRADE_BANNER_KEY) + .map { it[userWalletId.stringValue] == true } + + override suspend fun setShouldShowNextTimeUpgradeBanner(userWalletId: UserWalletId, shouldShow: Boolean) { + appPreferencesStore.editData { mutablePreferences -> + mutablePreferences.setObjectMap( + key = PreferencesKeys.SHOULD_SHOW_NEXT_TIME_UPGRADE_BANNER_KEY, + value = mutablePreferences.getObjectMap( + PreferencesKeys.SHOULD_SHOW_NEXT_TIME_UPGRADE_BANNER_KEY, + ) + .plus(userWalletId.stringValue to shouldShow), + ) + } + } + + override suspend fun getUpgradeBannerClosureTimestamp(userWalletId: UserWalletId): Long? { + return appPreferencesStore + .getObjectMapSync(PreferencesKeys.UPGRADE_BANNER_CLOSURE_TIMESTAMP_KEY)[userWalletId.stringValue] + } + + override suspend fun setUpgradeBannerClosureTimestamp(userWalletId: UserWalletId, timestamp: Long) { + appPreferencesStore.editData { mutablePreferences -> + mutablePreferences.setObjectMap( + key = PreferencesKeys.UPGRADE_BANNER_CLOSURE_TIMESTAMP_KEY, + value = mutablePreferences.getObjectMap(PreferencesKeys.UPGRADE_BANNER_CLOSURE_TIMESTAMP_KEY) + .plus(userWalletId.stringValue to timestamp), + ) + } + } + + override suspend fun getWalletCreationTimestamp(userWalletId: UserWalletId): Long? { + return appPreferencesStore + .getObjectMapSync(PreferencesKeys.WALLET_CREATION_TIMESTAMP_KEY)[userWalletId.stringValue] + } + + override suspend fun setWalletCreationTimestamp(userWalletId: UserWalletId, timestamp: Long) { + appPreferencesStore.editData { mutablePreferences -> + mutablePreferences.setObjectMap( + key = PreferencesKeys.WALLET_CREATION_TIMESTAMP_KEY, + value = mutablePreferences.getObjectMap(PreferencesKeys.WALLET_CREATION_TIMESTAMP_KEY) + .plus(userWalletId.stringValue to timestamp), + ) + } + } + + override suspend fun hasHadFirstTopUp(userWalletId: UserWalletId): Boolean { + return appPreferencesStore + .getObjectMapSync(PreferencesKeys.HAS_HAD_FIRST_TOP_UP_KEY)[userWalletId.stringValue] == true + } + + override suspend fun setHasHadFirstTopUp(userWalletId: UserWalletId, hasTopUp: Boolean) { + appPreferencesStore.editData { mutablePreferences -> + mutablePreferences.setObjectMap( + key = PreferencesKeys.HAS_HAD_FIRST_TOP_UP_KEY, + value = mutablePreferences.getObjectMap(PreferencesKeys.HAS_HAD_FIRST_TOP_UP_KEY) + .plus(userWalletId.stringValue to hasTopUp), + ) + } + } } \ No newline at end of file diff --git a/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt b/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt index e228cd4419..2432bc3dc9 100644 --- a/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt +++ b/domain/hot-wallet/src/main/kotlin/com/tangem/domain/hotwallet/repository/HotWalletRepository.kt @@ -12,4 +12,24 @@ interface HotWalletRepository { fun accessCodeSkipped(userWalletId: UserWalletId): Flow suspend fun setAccessCodeSkipped(userWalletId: UserWalletId, skipped: Boolean) + + fun shouldShowUpgradeBanner(userWalletId: UserWalletId): Flow + + suspend fun setShouldShowUpgradeBanner(userWalletId: UserWalletId, shouldShow: Boolean) + + fun shouldShowNextTimeUpgradeBanner(userWalletId: UserWalletId): Flow + + suspend fun setShouldShowNextTimeUpgradeBanner(userWalletId: UserWalletId, shouldShow: Boolean) + + suspend fun getUpgradeBannerClosureTimestamp(userWalletId: UserWalletId): Long? + + suspend fun setUpgradeBannerClosureTimestamp(userWalletId: UserWalletId, timestamp: Long) + + suspend fun getWalletCreationTimestamp(userWalletId: UserWalletId): Long? + + suspend fun setWalletCreationTimestamp(userWalletId: UserWalletId, timestamp: Long) + + suspend fun hasHadFirstTopUp(userWalletId: UserWalletId): Boolean + + suspend fun setHasHadFirstTopUp(userWalletId: UserWalletId, hasTopUp: Boolean) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 0dd7d1af6f..ca5a2d4caa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -17,6 +17,7 @@ import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType +import com.tangem.domain.hotwallet.repository.HotWalletRepository import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet @@ -98,6 +99,10 @@ internal interface WalletWarningsClickIntents { fun onFinishWalletActivationClick(isBackupExists: Boolean) fun onYieldPromoTermsAndConditionsClick() + + fun onUpgradeHotWalletClick(userWalletId: UserWalletId) + + fun onCloseUpgradeBannerClick(userWalletId: UserWalletId) } @Suppress("LargeClass", "LongParameterList", "TooManyFunctions") @@ -130,6 +135,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( private val getWalletsListForEnablingUseCase: GetWalletsForAutomaticallyPushEnablingUseCase, private val uiMessageSender: UiMessageSender, private val reviewManager: ReviewManager, + private val hotWalletRepository: HotWalletRepository, ) : BaseWalletClickIntents(), WalletWarningsClickIntents { override fun onAddBackupCardClick() { @@ -544,6 +550,34 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( urlOpener.openUrl(YIELD_PROMO_TERMS_LINK) } + override fun onUpgradeHotWalletClick(userWalletId: UserWalletId) { + modelScope.launch(dispatchers.main) { + val userWallet = getUserWalletUseCase(userWalletId).getOrNull() + if (userWallet is UserWallet.Hot) { + hotWalletRepository.setShouldShowUpgradeBanner(userWalletId, false) + hotWalletRepository.setShouldShowNextTimeUpgradeBanner(userWalletId, false) + appRouter.push(UpgradeWallet(userWalletId)) + } + } + } + + override fun onCloseUpgradeBannerClick(userWalletId: UserWalletId) { + modelScope.launch(dispatchers.main) { + val userWallet = getUserWalletUseCase(userWalletId).getOrNull() + if (userWallet is UserWallet.Hot) { + val hasHadFirstTopUp = hotWalletRepository.hasHadFirstTopUp(userWalletId) + val currentTime = System.currentTimeMillis() + + if (hasHadFirstTopUp) { + hotWalletRepository.setShouldShowUpgradeBanner(userWalletId, false) + hotWalletRepository.setUpgradeBannerClosureTimestamp(userWalletId, currentTime) + } else { + hotWalletRepository.setShouldShowUpgradeBanner(userWalletId, true) + } + } + } + } + private companion object { const val VISA_PROMO_LINK = "https://tangem.com/en/cardwaitlist/?utm_source=tangem-app-banner" + "&utm_medium=banner" + diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index 3852ada00e..341c2c6726 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -6,8 +6,9 @@ import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.decompose.di.ModelScoped 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 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.utils.ScreenLifecycleProvider @@ -40,16 +41,16 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( @Suppress("CyclomaticComplexMethod") private fun getEvent(warning: WalletNotification): AnalyticsEvent? { return when (warning) { - is WalletNotification.Critical.DevCard -> MainScreen.DevelopmentCard() - is WalletNotification.Critical.FailedCardValidation -> MainScreen.ProductSampleCard() - is WalletNotification.Warning.MissingBackup -> MainScreen.BackupYourWallet() - is WalletNotification.Warning.NumberOfSignedHashesIncorrect -> MainScreen.CardSignedTransactions() - is WalletNotification.Warning.TestNetCard -> MainScreen.TestnetCard() - is WalletNotification.Informational.DemoCard -> MainScreen.DemoCard() - is WalletNotification.Informational.MissingAddresses -> MainScreen.MissingAddresses() - is WalletNotification.RateApp -> MainScreen.HowDoYouLikeTangem() - is WalletNotification.Critical.BackupError -> MainScreen.BackupError() - is WalletNotification.NoteMigration -> MainScreen.NotePromo() + is WalletNotification.Critical.DevCard -> DevelopmentCard() + is WalletNotification.Critical.FailedCardValidation -> ProductSampleCard() + is WalletNotification.Warning.MissingBackup -> BackupYourWallet() + is WalletNotification.Warning.NumberOfSignedHashesIncorrect -> CardSignedTransactions() + is WalletNotification.Warning.TestNetCard -> TestnetCard() + is WalletNotification.Informational.DemoCard -> DemoCard() + is WalletNotification.Informational.MissingAddresses -> MissingAddresses() + is WalletNotification.RateApp -> HowDoYouLikeTangem() + is WalletNotification.Critical.BackupError -> BackupError() + is WalletNotification.NoteMigration -> NotePromo() is WalletNotification.SwapPromo -> NoticePromotionBanner( source = AnalyticsParam.ScreensSources.Main, program = Program.Empty, // Use it on new promo action @@ -92,16 +93,17 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( WalletActivationBannerType.Attention -> AnalyticsParam.EmptyFull.Empty WalletActivationBannerType.Warning -> AnalyticsParam.EmptyFull.Full } - MainScreen.NoticeFinishActivation( + NoticeFinishActivation( activationState = activationState, balanceState = balanceState, ) } - is WalletNotification.Critical.SeedPhraseNotification -> MainScreen.NoticeSeedPhraseSupport() - is WalletNotification.Critical.SeedPhraseSecondNotification -> MainScreen.NoticeSeedPhraseSupportSecond() - is WalletNotification.PushNotifications -> WalletScreenAnalyticsEvent.PushBannerPromo.PushBanner() + is WalletNotification.Critical.SeedPhraseNotification -> NoticeSeedPhraseSupport() + is WalletNotification.Critical.SeedPhraseSecondNotification -> NoticeSeedPhraseSupportSecond() + is WalletNotification.PushNotifications -> PushBanner() is WalletNotification.Warning.TangemPayRefreshNeeded -> null - WalletNotification.Warning.TangemPayUnreachable -> null + is WalletNotification.Warning.TangemPayUnreachable -> null + is WalletNotification.UpgradeHotWalletPromo -> null } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt index 6381c3f6a4..6f8e6b1be6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt @@ -14,6 +14,7 @@ import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.hotwallet.GetAccessCodeSkippedUseCase +import com.tangem.domain.hotwallet.repository.HotWalletRepository import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.currency.CryptoCurrency @@ -43,6 +44,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map +import java.util.concurrent.TimeUnit import javax.inject.Inject @Suppress("LongParameterList", "LargeClass") @@ -58,6 +60,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( private val notificationsRepository: NotificationsRepository, private val accountDependencies: AccountDependencies, private val getAccessCodeSkippedUseCase: GetAccessCodeSkippedUseCase, + private val hotWalletRepository: HotWalletRepository, ) { @Suppress("UNCHECKED_CAST", "MagicNumber", "LongMethod") @@ -98,6 +101,8 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( getAccessCodeSkippedUseCase(userWallet.walletId).distinctUntilChanged(), shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.YieldPromo) .distinctUntilChanged(), + hotWalletRepository.shouldShowUpgradeBanner(userWallet.walletId).distinctUntilChanged(), + hotWalletRepository.shouldShowNextTimeUpgradeBanner(userWallet.walletId).distinctUntilChanged(), ) { array -> array } .combine(tokenListFlow()) { array, any: Any -> arrayOf(any).plus(elements = array) } .map { array -> @@ -111,12 +116,22 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( val shouldShowEnablePushesReminderNotification = array[5] as Boolean val shouldAccessCodeSkipped = array[6] as Boolean val shouldShowYieldPromo = array[7] as Boolean + val shouldShowUpgradeBanner = array[8] as Boolean + val shouldShowNextTimeUpgradeBanner = array[9] as Boolean buildList { addUsedOutdatedDataNotification(totalFiatBalance) addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents) + addUpgradeHotWalletPromoNotification( + userWallet = userWallet, + flattenCurrencies = flattenCurrencies, + clickIntents = clickIntents, + shouldShowUpgradeBanner = shouldShowUpgradeBanner, + shouldShowNextTimeUpgradeBanner = shouldShowNextTimeUpgradeBanner, + ) + addFinishWalletActivationNotification( userWallet = userWallet, flattenCurrencies = flattenCurrencies, @@ -449,7 +464,57 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( ) } + @Suppress("CyclomaticComplexMethod") + private suspend fun MutableList.addUpgradeHotWalletPromoNotification( + userWallet: UserWallet, + flattenCurrencies: Lce>, + clickIntents: WalletClickIntents, + shouldShowUpgradeBanner: Boolean, + shouldShowNextTimeUpgradeBanner: Boolean, + ) { + if (userWallet !is UserWallet.Hot) return + + val currentTime = System.currentTimeMillis() + val creationTimestamp = hotWalletRepository.getWalletCreationTimestamp(userWallet.walletId) + val closureTimestamp = hotWalletRepository.getUpgradeBannerClosureTimestamp(userWallet.walletId) + val hasHadFirstTopUp = hotWalletRepository.hasHadFirstTopUp(userWallet.walletId) + + if (creationTimestamp == null) { + hotWalletRepository.setWalletCreationTimestamp(userWallet.walletId, currentTime) + return + } + + val daysSinceCreation = TimeUnit.MILLISECONDS.toDays(currentTime - creationTimestamp) + val daysSinceClosure = closureTimestamp?.let { TimeUnit.MILLISECONDS.toDays(currentTime - it) } + + val currencies = flattenCurrencies.getOrNull(isPartialContentAccepted = true).orEmpty() + val hasBalance = currencies.any { it.value.amount.orZero().isPositive() } + + if (hasBalance && !hasHadFirstTopUp) { + hotWalletRepository.setHasHadFirstTopUp(userWallet.walletId, true) + } + + val shouldShow = when { + shouldShowUpgradeBanner && hasBalance -> true + shouldShowNextTimeUpgradeBanner && daysSinceClosure != null && daysSinceClosure >= UPGRADE_BANNER_RESHOW_DAYS -> true + !shouldShowUpgradeBanner && !shouldShowNextTimeUpgradeBanner && hasHadFirstTopUp && daysSinceCreation >= UPGRADE_BANNER_RESHOW_DAYS -> { + hotWalletRepository.setShouldShowNextTimeUpgradeBanner(userWallet.walletId, true) + true + } + else -> false + } + + addIf( + element = WalletNotification.UpgradeHotWalletPromo( + onLaterClick = { clickIntents.onCloseUpgradeBannerClick(userWallet.walletId) }, + onUpgradeClick = { clickIntents.onUpgradeHotWalletClick(userWallet.walletId) }, + ), + condition = shouldShow, + ) + } + private companion object { const val MAX_REMAINING_SIGNATURES_COUNT = 10 + const val UPGRADE_BANNER_RESHOW_DAYS = 30 } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt index 9abf719a45..ed1601ae6a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt @@ -445,4 +445,22 @@ sealed class WalletNotification(val config: NotificationConfig) { ), ), ) + + data class UpgradeHotWalletPromo( + val onLaterClick: () -> Unit, + val onUpgradeClick: () -> Unit, + ) : WalletNotification( + config = NotificationConfig( + title = resourceReference(R.string.hw_upgrade_to_cold_banner_title), + subtitle = resourceReference(R.string.hw_upgrade_to_cold_banner_description), + iconResId = R.drawable.img_tangem_wallet_72, + buttonsState = ButtonsState.PairButtonsConfig( + primaryText = resourceReference(R.string.hw_upgrade), + onPrimaryClick = onUpgradeClick, + secondaryText = resourceReference(R.string.common_later), + onSecondaryClick = onLaterClick, + ), + iconSize = 72.dp, + ), + ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt index d8b52ad1ad..90fc34c41f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.items import androidx.compose.ui.Modifier import com.tangem.core.ui.components.notifications.NoteMigrationNotification import com.tangem.core.ui.components.notifications.Notification +import com.tangem.core.ui.res.ForceDarkTheme import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import kotlinx.collections.immutable.ImmutableList @@ -40,6 +41,14 @@ internal fun LazyListScope.notifications(configs: ImmutableList { + ForceDarkTheme { + Notification( + config = item.config, + modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null), + ) + } + } else -> { Notification( config = item.config,