Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-10 15:21:55 +05:00
parent 4570bc334c
commit 602e20a1d2
53 changed files with 489 additions and 368 deletions

View file

@ -38,7 +38,7 @@ import com.tangem.domain.settings.*
import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase
import com.tangem.domain.walletconnect.WcPairService
import com.tangem.domain.walletconnect.model.WcPairRequest
import com.tangem.domain.tokensync.usecase.StartTokenSyncUseCase
import com.tangem.domain.assetsdiscovery.usecase.StartAssetsDiscoveryUseCase
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import com.tangem.domain.wallets.usecase.*
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyUpdateUseCase
@ -126,7 +126,7 @@ internal class WalletModel @Inject constructor(
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
private val uiMessageSender: UiMessageSender,
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
private val startTokenSyncUseCase: StartTokenSyncUseCase,
private val startAssetsDiscoveryUseCase: StartAssetsDiscoveryUseCase,
val screenLifecycleProvider: ScreenLifecycleProvider,
val innerWalletRouter: InnerWalletRouter,
) : Model() {
@ -159,7 +159,7 @@ internal class WalletModel @Inject constructor(
subscribeTangemPayOnWalletState()
subscribeToMainScreenQrScanning()
enableNotificationsIfNeeded()
applyPendingTokenSyncs()
applyPendingAssetsDiscovery()
clickIntents.initialize(innerWalletRouter, modelScope)
@ -840,9 +840,9 @@ internal class WalletModel @Inject constructor(
}
}
private fun applyPendingTokenSyncs() {
if (hotWalletFeatureToggles.isTokenSyncEnabled) {
startTokenSyncUseCase.applyPendingSyncs()
private fun applyPendingAssetsDiscovery() {
if (hotWalletFeatureToggles.isAssetsDiscoveryEnabled) {
startAssetsDiscoveryUseCase.applyPendingAssetsDiscovery()
}
}

View file

@ -40,7 +40,7 @@ import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.Program
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.PromotionBannerClicked
import com.tangem.domain.tokens.model.details.NavigationAction
import com.tangem.domain.tokensync.usecase.AcknowledgeTokenSyncCompletionUseCase
import com.tangem.domain.assetsdiscovery.usecase.AcknowledgeAssetsDiscoveryCompletionUseCase
import com.tangem.domain.wallets.usecase.*
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic
@ -97,9 +97,9 @@ internal interface WalletWarningsClickIntents {
fun onCloseUpgradeBannerClick(userWalletId: UserWalletId)
fun onDismissTokenSyncNotification(userWalletId: UserWalletId)
fun onDismissAssetsDiscoveryNotification(userWalletId: UserWalletId)
fun onTokenSyncManageClick(userWalletId: UserWalletId)
fun onAssetsDiscoveryManageClick(userWalletId: UserWalletId)
}
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
@ -132,7 +132,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
private val uiMessageSender: UiMessageSender,
private val reviewManager: ReviewManager,
private val closeHotWalletUpgradeBannerUseCase: CloseHotWalletUpgradeBannerUseCase,
private val acknowledgeTokenSyncCompletionUseCase: AcknowledgeTokenSyncCompletionUseCase,
private val acknowledgeAssetsDiscoveryCompletionUseCase: AcknowledgeAssetsDiscoveryCompletionUseCase,
) : BaseWalletClickIntents(), WalletWarningsClickIntents {
override fun onAddBackupCardClick() {
@ -508,12 +508,12 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
}
}
override fun onDismissTokenSyncNotification(userWalletId: UserWalletId) {
acknowledgeTokenSyncCompletionUseCase(userWalletId)
override fun onDismissAssetsDiscoveryNotification(userWalletId: UserWalletId) {
acknowledgeAssetsDiscoveryCompletionUseCase(userWalletId)
}
override fun onTokenSyncManageClick(userWalletId: UserWalletId) {
acknowledgeTokenSyncCompletionUseCase(userWalletId)
override fun onAssetsDiscoveryManageClick(userWalletId: UserWalletId) {
acknowledgeAssetsDiscoveryCompletionUseCase(userWalletId)
router.openManageTokensScreen(
AccountId.forMainCryptoPortfolio(userWalletId),
)

View file

@ -120,7 +120,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
is WalletNotification.Warning.TangemPayRefreshNeeded -> null
is WalletNotification.Warning.TangemPayUnreachable -> null
is WalletNotification.UpgradeHotWalletPromo -> null
is WalletNotification.TokenSyncCompleted -> null
is WalletNotification.AssetsDiscoveryCompleted -> null
is WalletNotification.CreateTangemPayAccount -> null
}
}

View file

@ -27,8 +27,8 @@ 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.tokensync.model.TokenSyncProgress
import com.tangem.domain.tokensync.usecase.ObserveTokenSyncUseCase
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
import com.tangem.domain.assetsdiscovery.usecase.ObserveAssetsDiscoveryUseCase
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
import com.tangem.feature.wallet.child.wallet.model.WalletActivationBannerType
@ -65,7 +65,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
private val shouldShowUpgradeHotWalletBannerUseCase: ShouldShowUpgradeHotWalletBannerUseCase,
private val getUpgradeBannerClosureTimestampUseCase: GetUpgradeBannerClosureTimestampUseCase,
private val checkHotWalletUpgradeBannerUseCase: CheckHotWalletUpgradeBannerUseCase,
private val observeTokenSyncUseCase: ObserveTokenSyncUseCase,
private val observeAssetsDiscoveryUseCase: ObserveAssetsDiscoveryUseCase,
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
) {
@ -75,11 +75,12 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
val accountStatusListFlow = accountDependencies.singleAccountStatusListSupplier(params)
val tokenSyncProgressFlow = if (hotWalletFeatureToggles.isTokenSyncEnabled && userWallet is UserWallet.Hot) {
observeTokenSyncUseCase(userWallet.walletId).distinctUntilChanged()
} else {
flowOf(TokenSyncProgress.Idle)
}
val assetsDiscoveryProgressFlow =
if (hotWalletFeatureToggles.isAssetsDiscoveryEnabled && userWallet is UserWallet.Hot) {
observeAssetsDiscoveryUseCase(userWallet.walletId).distinctUntilChanged()
} else {
flowOf(AssetsDiscoveryProgress.Idle)
}
return combine(
accountStatusListFlow,
@ -96,7 +97,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
.distinctUntilChanged(),
getUpgradeBannerClosureTimestampUseCase(userWallet.walletId)
.distinctUntilChanged(),
tokenSyncProgressFlow,
assetsDiscoveryProgressFlow,
) { array -> array }
.map { array ->
val accountStatusList = array[0] as AccountStatusList
@ -108,7 +109,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
val shouldShowYieldPromo = array[6] as Boolean
val shouldShowUpgradeBanner = array[7] as Boolean
val closureTimestamp = array[8] as? Long
val tokenSyncProgress = array[9] as TokenSyncProgress
val assetsDiscoveryProgress = array[9] as AssetsDiscoveryProgress
val flattenCurrencies = accountStatusList.flattenCurrencies()
val paymentAccountStatus = accountStatusList.accountStatuses
@ -153,9 +154,9 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
clickIntents = clickIntents,
)
addTokenSyncCompletedNotification(
addAssetsDiscoveryCompletedNotification(
userWallet = userWallet,
tokenSyncProgress = tokenSyncProgress,
assetsDiscoveryProgress = assetsDiscoveryProgress,
clickIntents = clickIntents,
)
@ -404,17 +405,17 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
// }
// }
private fun MutableList<WalletNotification>.addTokenSyncCompletedNotification(
private fun MutableList<WalletNotification>.addAssetsDiscoveryCompletedNotification(
userWallet: UserWallet,
tokenSyncProgress: TokenSyncProgress,
assetsDiscoveryProgress: AssetsDiscoveryProgress,
clickIntents: WalletClickIntents,
) {
addIf(
element = WalletNotification.TokenSyncCompleted(
onCloseClick = { clickIntents.onDismissTokenSyncNotification(userWallet.walletId) },
onManageTokensClick = { clickIntents.onTokenSyncManageClick(userWallet.walletId) },
element = WalletNotification.AssetsDiscoveryCompleted(
onCloseClick = { clickIntents.onDismissAssetsDiscoveryNotification(userWallet.walletId) },
onManageTokensClick = { clickIntents.onAssetsDiscoveryManageClick(userWallet.walletId) },
),
condition = tokenSyncProgress is TokenSyncProgress.Completed,
condition = assetsDiscoveryProgress is AssetsDiscoveryProgress.Completed,
)
}

View file

@ -10,7 +10,7 @@ import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.card.common.util.getCardsCount
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
import java.math.BigDecimal
@ -32,7 +32,7 @@ internal object WalletAdditionalInfoFactory {
fun resolve(
wallet: UserWallet,
currencyAmount: BigDecimal? = null,
syncProgress: TokenSyncProgressUM = TokenSyncProgressUM.Idle,
syncProgress: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
): WalletAdditionalInfo {
return when (wallet) {
is UserWallet.Cold -> {
@ -46,8 +46,8 @@ internal object WalletAdditionalInfoFactory {
}
}
private fun UserWallet.Hot.resolveAdditionalInfo(syncProgress: TokenSyncProgressUM): WalletAdditionalInfo {
val content = if (syncProgress is TokenSyncProgressUM.InProgress) {
private fun UserWallet.Hot.resolveAdditionalInfo(syncProgress: AssetsDiscoveryProgressUM): WalletAdditionalInfo {
val content = if (syncProgress is AssetsDiscoveryProgressUM.InProgress) {
WalletAdditionalInfo.Content.SyncProgress(syncProgress.progressPercent)
} else {
WalletAdditionalInfo.Content.Text(

View file

@ -18,7 +18,7 @@ internal class MultiWalletContentLoader @AssistedInject constructor(
private val walletNotificationsSubscriberFactory: WalletNotificationsSubscriber.Factory,
private val multiWalletActionButtonsSubscriberFactory: MultiWalletActionButtonsSubscriber.Factory,
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
private val tokenSyncSubscriberFactory: TokenSyncSubscriber.Factory,
private val assetsDiscoverySubscriberFactory: AssetsDiscoverySubscriber.Factory,
private val tokenListAnalyticsSubscriberFactory: TokenListAnalyticsSubscriber.Factory,
private val designFeatureToggles: DesignFeatureToggles,
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
@ -36,8 +36,8 @@ internal class MultiWalletContentLoader @AssistedInject constructor(
multiWalletActionButtonsSubscriberFactory.create(userWallet),
tangemPayMainSubscriberFactory.create(userWallet),
tokenListAnalyticsSubscriberFactory.create(userWallet),
if (hotWalletFeatureToggles.isTokenSyncEnabled && userWallet is UserWallet.Hot) {
tokenSyncSubscriberFactory.create(userWallet)
if (hotWalletFeatureToggles.isAssetsDiscoveryEnabled && userWallet is UserWallet.Hot) {
assetsDiscoverySubscriberFactory.create(userWallet)
} else {
null
},

View file

@ -0,0 +1,13 @@
package com.tangem.feature.wallet.presentation.wallet.state.model
import androidx.compose.runtime.Immutable
@Immutable
internal sealed class AssetsDiscoveryProgressUM {
data object Idle : AssetsDiscoveryProgressUM()
data class InProgress(val progressPercent: Int) : AssetsDiscoveryProgressUM()
data object Completed : AssetsDiscoveryProgressUM()
}

View file

@ -1,13 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.state.model
import androidx.compose.runtime.Immutable
@Immutable
internal sealed class TokenSyncProgressUM {
data object Idle : TokenSyncProgressUM()
data class InProgress(val progressPercent: Int) : TokenSyncProgressUM()
data object Completed : TokenSyncProgressUM()
}

View file

@ -435,7 +435,7 @@ sealed class WalletNotification(val config: NotificationConfig) {
),
)
data class TokenSyncCompleted(
data class AssetsDiscoveryCompleted(
val onCloseClick: () -> Unit,
val onManageTokensClick: () -> Unit,
) : WalletNotification(

View file

@ -27,7 +27,7 @@ internal sealed interface WalletState : WalletStateHolder {
abstract val tangemPayState: TangemPayState
abstract val tangemPayMainUM: TangemPayMainUM
abstract val isTangemPayRefactorEnabled: Boolean // TANGEM_PAY_ACCOUNTS_REFACTOR_ENABLED
abstract val tokenSyncProgressUM: TokenSyncProgressUM
abstract val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM
data class Content(
override val pullToRefreshConfig: PullToRefreshConfig,
@ -41,7 +41,7 @@ internal sealed interface WalletState : WalletStateHolder {
override val tangemPayState: TangemPayState,
override val tangemPayMainUM: TangemPayMainUM,
override val isTangemPayRefactorEnabled: Boolean,
override val tokenSyncProgressUM: TokenSyncProgressUM = TokenSyncProgressUM.Idle,
override val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
) : MultiCurrency()
data class Locked(
@ -63,7 +63,7 @@ internal sealed interface WalletState : WalletStateHolder {
override val tangemPayState: TangemPayState = TangemPayState.Empty
override val tangemPayMainUM: TangemPayMainUM = TangemPayMainUM.Empty
override val isTangemPayRefactorEnabled: Boolean = false
override val tokenSyncProgressUM: TokenSyncProgressUM = TokenSyncProgressUM.Idle
override val assetsDiscoveryProgressUM: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle
}
}

View file

@ -2,21 +2,21 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
internal class SetTokenSyncProgressTransformer(
internal class SetAssetsDiscoveryProgressTransformer(
private val userWallet: UserWallet,
private val progress: TokenSyncProgressUM,
private val progress: AssetsDiscoveryProgressUM,
) : WalletStateTransformer(userWallet.walletId) {
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.MultiCurrency.Content -> prevState.copy(
walletCardState = updateCardState(prevState.walletCardState),
tokenSyncProgressUM = progress,
assetsDiscoveryProgressUM = progress,
)
else -> prevState
}

View file

@ -61,7 +61,7 @@ internal class SetTokenListErrorTransformer(
walletsBalanceUM = walletUM.walletsBalanceUM.toLoadedState(),
tokensListUM = WalletTokensListUM.Empty(
onEmptyClick = {
clickIntents.onTokenSyncManageClick(walletUM.walletsBalanceUM.id)
clickIntents.onAssetsDiscoveryManageClick(walletUM.walletsBalanceUM.id)
},
),
buttons = walletUM.disableButtons(),

View file

@ -123,7 +123,7 @@ internal class SetTokenListTransformer(
if (params !is TokenConverterParams.Account) {
return WalletTokensListUM.Empty(
onEmptyClick = {
clickIntents.onTokenSyncManageClick(userWallet.walletId)
clickIntents.onAssetsDiscoveryManageClick(userWallet.walletId)
},
)
}

View file

@ -4,7 +4,7 @@ import com.tangem.domain.card.common.util.getCardsCount
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
@ -19,7 +19,7 @@ internal class UpdateWalletCardsCountTransformer(
return when (prevState) {
is WalletState.MultiCurrency.Content -> {
prevState.copy(
walletCardState = prevState.walletCardState.toUpdatedState(prevState.tokenSyncProgressUM),
walletCardState = prevState.walletCardState.toUpdatedState(prevState.assetsDiscoveryProgressUM),
)
}
is WalletState.SingleCurrency.Content -> {
@ -39,7 +39,7 @@ internal class UpdateWalletCardsCountTransformer(
}
private fun WalletCardState.toUpdatedState(
syncProgress: TokenSyncProgressUM = TokenSyncProgressUM.Idle,
syncProgress: AssetsDiscoveryProgressUM = AssetsDiscoveryProgressUM.Idle,
): WalletCardState {
return when (this) {
is WalletCardState.Content -> copy(

View file

@ -1,11 +1,11 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokensync.model.TokenSyncProgress
import com.tangem.domain.tokensync.usecase.ObserveTokenSyncUseCase
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
import com.tangem.domain.assetsdiscovery.usecase.ObserveAssetsDiscoveryUseCase
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenSyncProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenSyncProgressTransformer
import com.tangem.feature.wallet.presentation.wallet.state.model.AssetsDiscoveryProgressUM
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetAssetsDiscoveryProgressTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -13,25 +13,25 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach
internal class TokenSyncSubscriber @AssistedInject constructor(
internal class AssetsDiscoverySubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateController: WalletStateController,
private val observeTokenSyncUseCase: ObserveTokenSyncUseCase,
private val observeAssetsDiscoveryUseCase: ObserveAssetsDiscoveryUseCase,
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return observeTokenSyncUseCase(userWallet.walletId)
return observeAssetsDiscoveryUseCase(userWallet.walletId)
.onEach { current -> handleProgress(userWallet, current) }
}
private fun handleProgress(userWallet: UserWallet, current: TokenSyncProgress) {
private fun handleProgress(userWallet: UserWallet, current: AssetsDiscoveryProgress) {
val progressUM = when (current) {
is TokenSyncProgress.InProgress -> TokenSyncProgressUM.InProgress(current.progressPercent)
is TokenSyncProgress.Completed -> TokenSyncProgressUM.Completed
is TokenSyncProgress.Idle -> TokenSyncProgressUM.Idle
is AssetsDiscoveryProgress.InProgress -> AssetsDiscoveryProgressUM.InProgress(current.progressPercent)
is AssetsDiscoveryProgress.Completed -> AssetsDiscoveryProgressUM.Completed
is AssetsDiscoveryProgress.Idle -> AssetsDiscoveryProgressUM.Idle
}
stateController.update(
SetTokenSyncProgressTransformer(
SetAssetsDiscoveryProgressTransformer(
userWallet = userWallet,
progress = progressUM,
),
@ -40,6 +40,6 @@ internal class TokenSyncSubscriber @AssistedInject constructor(
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): TokenSyncSubscriber
fun create(userWallet: UserWallet): AssetsDiscoverySubscriber
}
}