Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-25 13:59:19 +04:00
parent d27a59ab75
commit a0ba5ab9d9
36 changed files with 327 additions and 1748 deletions

View file

@ -5,11 +5,8 @@
<ID>BooleanPropertyNaming:DefaultUserWalletsFetcher.kt$DefaultUserWalletsFetcher$@Assisted("onlyMultiCurrency") private val onlyMultiCurrency: Boolean</ID>
<ID>BooleanPropertyNaming:DraggableItem.kt$DraggableItem$abstract val showShadow: Boolean</ID>
<ID>BooleanPropertyNaming:DraggableItem.kt$DraggableItem.RoundingMode$abstract val showGap: Boolean</ID>
<ID>BooleanPropertyNaming:GetSingleWalletWarningsFactory.kt$GetSingleWalletWarningsFactory$private var readyForRateAppNotification = false</ID>
<ID>BooleanPropertyNaming:GetSingleWalletWarningsFactory.kt$GetSingleWalletWarningsFactory$val userHasWalletOrWallet2 = userWallets.filterIsInstance&lt;UserWallet.Cold&gt;().any { val typesResolver = it.scanResponse.cardTypesResolver typesResolver.isTangemWallet() || typesResolver.isWallet2() }</ID>
<ID>BooleanPropertyNaming:OrganizeTokensState.kt$OrganizeTokensState.ActionsConfig$val showApplyProgress: Boolean = false</ID>
<ID>BooleanPropertyNaming:ScrollToWalletTransformer.kt$ScrollToWalletTransformer$private val withScrollAnimation: Boolean = true</ID>
<ID>BooleanPropertyNaming:SetWalletCardDropDownItemsTransformer.kt$SetWalletCardDropDownItemsTransformer$private val dropdownEnabled: Boolean</ID>
<ID>BooleanPropertyNaming:TangemPayState.kt$TangemPayState.Progress$val showProgress: Boolean = false</ID>
<ID>BooleanPropertyNaming:TokenActionButtonConfig.kt$TokenActionButtonConfig$val enabled: Boolean = true</ID>
<ID>BooleanPropertyNaming:UpdateMultiWalletActionButtonBadgeTransformer.kt$UpdateMultiWalletActionButtonBadgeTransformer$private val showSwapBadge: Boolean</ID>
@ -18,127 +15,69 @@
<ID>BooleanPropertyNaming:WalletManageButton.kt$WalletManageButton$/** Is click enabled */ abstract val enabled: Boolean</ID>
<ID>BooleanPropertyNaming:WalletManageButton.kt$WalletManageButton$/** Whether to dim content */ abstract val dimContent: Boolean</ID>
<ID>BooleanPropertyNaming:WalletManageButton.kt$WalletManageButton.Swap$val showBadge: Boolean = false</ID>
<ID>BooleanPropertyNaming:WalletModel.kt$WalletModel$private var needToRefreshWallet = false</ID>
<ID>BooleanPropertyNaming:WalletNameMigrationUseCase.kt$WalletNameMigrationUseCase$private val useNewListRepository: Boolean</ID>
<ID>BooleanPropertyNaming:WalletScreen.kt$val portfolioContent = state is WalletState.MultiCurrency.Content &amp;&amp; state.tokensListState is WalletTokensListState.ContentState.PortfolioContent</ID>
<ID>BooleanPropertyNaming:WalletScreen.kt$val showMarketsHint by remember { derivedStateOf { // Show hint only when there are items in the list // and when there a no items to scroll listState.layoutInfo.totalItemsCount &gt; 0 &amp;&amp; !listState.canScrollBackward &amp;&amp; !listState.canScrollForward || listState.canScrollBackward &amp;&amp; !listState.canScrollForward } }</ID>
<ID>BooleanPropertyNaming:WalletScreen.kt$var visible by remember { mutableStateOf(value = false) }</ID>
<ID>BooleanPropertyNaming:WalletScreenState.kt$WalletScreenState$val showMarketsOnboarding: Boolean</ID>
<ID>BooleanPropertyNaming:WalletWithFundsChecker.kt$WalletWithFundsChecker$val prevStatus = statusByWalletId.get(userWalletId)</ID>
<ID>IgnoredReturnValue:MultiWalletTokenListStore.kt$MultiWalletTokenListStore$remove(userWalletId)</ID>
<ID>MaxChainedCallsOnSameLine:HasSingleWalletSignedHashesUseCase.kt$HasSingleWalletSignedHashesUseCase$userWallet.scanResponse.card.wallets.firstOrNull()?.totalSignedHashes</ID>
<ID>MultilineLambdaItParameter:BasicTokenListSubscriber.kt$BasicTokenListSubscriber${ it.getOrElse { e -&gt; Timber.e("Failed to load app currency: $e") AppCurrency.Default } }</ID>
<ID>MultilineLambdaItParameter:DefaultPromoDeeplinkHandler.kt$DefaultPromoDeeplinkHandler${ Timber.tag(LOG_TAG).e("Error on getting user wallet: $it") showAlert(Failed) }</ID>
<ID>MultilineLambdaItParameter:DefaultUserWalletImageFetcher.kt$DefaultUserWalletImageFetcher${ it.fold( ifLeft = { emit(UserWalletItemUM.ImageState.Loading) }, ifRight = { wallet -&gt; emitAll(walletImage(wallet, size)) }, ) }</ID>
<ID>MultilineLambdaItParameter:GetSingleWalletWarningsFactory.kt$GetSingleWalletWarningsFactory${ hasSingleWalletSignedHashesUseCase(userWallet = selectedWallet, network = it) .conflate() .distinctUntilChanged() .firstOrNull() }</ID>
<ID>MultilineLambdaItParameter:GetSingleWalletWarningsFactory.kt$GetSingleWalletWarningsFactory${ val typesResolver = it.scanResponse.cardTypesResolver typesResolver.isTangemWallet() || typesResolver.isWallet2() }</ID>
<ID>MultilineLambdaItParameter:NetworkGroupToDraggableItemsConverterV2.kt$NetworkGroupToDraggableItemsConverterV2${ AccountCryptoCurrencyStatus( account = account, status = it, ) }</ID>
<ID>MultilineLambdaItParameter:OrganizeTokensModel.kt$OrganizeTokensModel${ isBalanceHidden = it.isBalanceHidden stateHolder.updateHiddenState(isBalanceHidden) }</ID>
<ID>MultilineLambdaItParameter:OrganizeTokensModel.kt$OrganizeTokensModel${ stateHolder.updateStateAfterTokenListSorting(it) cachedTokenList = it }</ID>
<ID>MultilineLambdaItParameter:OrganizeTokensModel.kt$OrganizeTokensModel${ stateHolder.updateStateAfterTokenListSortingV2(it, isAccountsModeEnabled) cachedAccountStatusList = it }</ID>
<ID>MultilineLambdaItParameter:OrganizedTokenListConverter.kt$OrganizedTokenListConverter${ AccountCryptoCurrencyStatus( account = cryptoAccount, status = it, ) }</ID>
<ID>MultilineLambdaItParameter:PrimaryCurrencySubscriber.kt$PrimaryCurrencySubscriber${ // do not send tokens count for single currency wallet analyticsEventHandler.send( event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded( balance = it, tokensCount = null, ), ) }</ID>
<ID>MultilineLambdaItParameter:PrimaryCurrencySubscriber.kt$PrimaryCurrencySubscriber${ Timber.e("Unable to get primary currency status: $it") return@onEach }</ID>
<ID>MultilineLambdaItParameter:PrimaryCurrencySubscriberV2.kt$PrimaryCurrencySubscriberV2${ // do not send tokens count for single currency wallet analyticsEventHandler.send( event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded( balance = it, tokensCount = null, ), ) }</ID>
<ID>MultilineLambdaItParameter:ReviewManagerRequester.kt$ReviewManagerRequester${ handleOnCompleteRequestTask( reviewManager = reviewManager, activity = context.findActivity(), task = it, onDismissClick = onDismissClick, ) }</ID>
<ID>MultilineLambdaItParameter:SetRefreshStateTransformer.kt$SetRefreshStateTransformer${ it.mapNotNull { button -&gt; when (button) { is WalletManageButton.Buy -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Send -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Sell -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Receive -&gt; button is WalletManageButton.Stake -&gt; null is WalletManageButton.Swap -&gt; null } } }</ID>
<ID>MultilineLambdaItParameter:SetVisaInfoTransformer.kt$SetVisaInfoTransformer${ if (it is RefreshTokenExpiredException) { return getRefreshTokenExpiredState(prevState) } return prevState.copy( buttons = createVisaButtonsDimmed(), walletCardState = getErrorWalletCardState(prevState.walletCardState), balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error, ) }</ID>
<ID>MultilineLambdaItParameter:SingleWalletExpressStatusesSubscriber.kt$SingleWalletExpressStatusesSubscriber${ Timber.e("Unable to get primary currency status: $it") return@onEach }</ID>
<ID>MultilineLambdaItParameter:TokenListAnalyticsSender.kt$TokenListAnalyticsSender${ val status = it.value if (status is CryptoCurrencyStatus.Loaded) { sendTokenBalancesForSpecificBlockchains(it, status) } }</ID>
<ID>MultilineLambdaItParameter:TokenListStateConverter.kt$TokenListStateConverter${ if (isExtend) { clickIntents.onAccountCollapseClick(it) } else { clickIntents.onAccountExpandClick(it) } }</ID>
<ID>MultilineLambdaItParameter:TxHistorySubscriber.kt$TxHistorySubscriber${ SetTxHistoryItemsErrorTransformer( userWalletId = userWallet.walletId, error = it, clickIntents = clickIntents, ) }</ID>
<ID>MultilineLambdaItParameter:TxHistorySubscriberV2.kt$TxHistorySubscriberV2${ SetTxHistoryItemsErrorTransformer( userWalletId = userWallet.walletId, error = it, clickIntents = clickIntents, ) }</ID>
<ID>MultilineLambdaItParameter:UpdateMultiWalletActionsTransformer.kt$UpdateMultiWalletActionsTransformer${ when (it) { is WalletManageButton.Buy -&gt; { it.copy( enabled = buyStatus.isContent(), dimContent = !buyStatus.isContent(), ) } is WalletManageButton.Sell -&gt; { it.copy( enabled = sellStatus.isContent(), dimContent = !sellStatus.isContent(), ) } is WalletManageButton.Swap -&gt; { it.copy( enabled = swapStatus.isContent(), dimContent = !swapStatus.isContent(), ) } else -&gt; it } }</ID>
<ID>MultilineLambdaItParameter:UseCaseExt.kt${ Timber.e("Impossible to get primary currency status $it") null }</ID>
<ID>MultilineLambdaItParameter:UseCaseExt.kt${ Timber.e("Impossible to get selected wallet $it") null }</ID>
<ID>MultilineLambdaItParameter:VisaWalletIntents.kt$VisaWalletIntentsImplementor${ Timber.e("Unable to get balances and limits: $it") return@launch }</ID>
<ID>MultilineLambdaItParameter:VisaWalletIntents.kt$VisaWalletIntentsImplementor${ Timber.e(it, "Failed to get transaction details") return@launch }</ID>
<ID>MultilineLambdaItParameter:VisaWalletIntents.kt$VisaWalletIntentsImplementor${ Timber.e(it, "Failed to get visa currency") return@launch }</ID>
<ID>MultilineLambdaItParameter:VisaWalletSubscriber.kt$VisaWalletSubscriber${ Timber.e(it, "Failed to load VISA currency") setFailedTxHistoryState(it) return@flow }</ID>
<ID>MultilineLambdaItParameter:VisaWalletSubscriber.kt$VisaWalletSubscriber${ Timber.e(it, "Failed to load tx history for wallet ${userWallet.walletId}") throw it }</ID>
<ID>MultilineLambdaItParameter:WalletCard.kt${ haptic.performHapticFeedback(HapticFeedbackType.LongPress) isMenuVisible = true pressOffset = DpOffset(x = it.x.toDp(), y = it.y.toDp()) }</ID>
<ID>MultilineLambdaItParameter:WalletCard.kt${ val press = PressInteraction.Press(it) interactionSource.emit(press) tryAwaitRelease() interactionSource.emit(PressInteraction.Release(press)) }</ID>
<ID>MultilineLambdaItParameter:WalletCardClickIntents.kt$WalletCardClickIntentsImplementor${ Timber.e("Unable to delete user wallet: $it") return@launch }</ID>
<ID>MultilineLambdaItParameter:WalletClickIntents.kt$WalletClickIntents${ if (!it.isLocked) { launch { walletContentFetcher(userWalletId = it.walletId) } } walletScreenContentLoader.load( userWallet = it, clickIntents = this@WalletClickIntents, coroutineScope = modelScope, ) }</ID>
<ID>MultilineLambdaItParameter:WalletContentClickIntents.kt$WalletContentClickIntentsImplementor${ Timber.e( """ Unable to get user wallet |- ID: $userWalletId |- Exception: $it """.trimIndent(), ) return@launch }</ID>
<ID>MultilineLambdaItParameter:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor${ analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonCopyAddress(currency.symbol)) clipboardManager.setText(text = it, isSensitive = true) }</ID>
<ID>MultilineLambdaItParameter:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor${ analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonShareAddress(currency.symbol)) shareManager.shareText(text = it) }</ID>
<ID>MultilineLambdaItParameter:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor${ onAddressTypeSelected( userWalletId = userWalletId, currency = currency, addressModel = it, ) }</ID>
<ID>MultilineLambdaItParameter:WalletLoaderStorage.kt$WalletLoaderStorage${ it.forEach(Job::cancel) loaders.remove(id) }</ID>
<ID>MultilineLambdaItParameter:WalletModel.kt$WalletModel${ walletScreenContentLoader.load( userWallet = it, clickIntents = clickIntents, coroutineScope = modelScope, isRefresh = true, ) }</ID>
<ID>MultilineLambdaItParameter:WalletModel.kt$WalletModel${ walletsUpdateActionResolver.resolve( wallets = it, currentState = stateHolder.value, ) }</ID>
<ID>MultilineLambdaItParameter:WalletNFTListSubscriber.kt$WalletNFTListSubscriber${ stateHolder.update( SetNFTCollectionsTransformer( userWalletId = userWallet.walletId, nftCollections = it, onItemClick = { clickIntents.onNFTClick(userWallet) }, ), ) }</ID>
<ID>MultilineLambdaItParameter:WalletNameMigrationUseCase.kt$WalletNameMigrationUseCase${ val defaultName = it.name val suggestedWalletName = suggestedWalletName(defaultName, existingNames) if (defaultName != suggestedWalletName) { userWalletsListRepository.saveWithoutLock(it.copy(name = suggestedWalletName), canOverride = true) } Timber.tag("Migrated names").e(it.walletId.toString() + " " + suggestedWalletName) }</ID>
<ID>MultilineLambdaItParameter:WalletScreen.kt${ PaddingValues( bottom = it.calculateBottomPadding() + marketHintAproxHeight + 52.dp, ) }</ID>
<ID>MultilineLambdaItParameter:WalletScreen.kt${ WalletSnackbarHost( snackbarHostState = it, event = state.event, modifier = Modifier .padding(bottom = TangemTheme.dimens.spacing4) .navigationBarsPadding(), ) }</ID>
<ID>MultilineLambdaItParameter:WalletScreen.kt${ balancesAndLimitsBlock( modifier = itemModifier, state = it.balancesAndLimitBlockState, ) }</ID>
<ID>MultilineLambdaItParameter:WalletScreen.kt${ findPortfolioVisibleState( portfolio = it, expandedState = expandedState, collapsedState = collapsedState, ) }</ID>
<ID>MultilineLambdaItParameter:WalletScreen.kt${ it.organizeTokensButtonConfig?.let { config -&gt; organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
<ID>MultilineLambdaItParameter:WalletScreen.kt${ nftCollections( modifier = itemModifier, state = it.nftState, ) }</ID>
<ID>MultilineLambdaItParameter:WalletWarningsClickIntents.kt$WalletWarningsClickIntentsImplementor${ Timber.e( """ Unable to get user wallet |- ID: $userWalletId |- Exception: $it """.trimIndent(), ) null }</ID>
<ID>MultilineLambdaItParameter:WalletWarningsClickIntents.kt$WalletWarningsClickIntentsImplementor${ router.openOnboardingScreen( scanResponse = it.scanResponse, continueBackup = true, ) }</ID>
<ID>MultilineLambdaItParameter:WalletWithFundsChecker.kt$WalletWithFundsChecker${ val amount = it.value.amount ?: return@any false !amount.isZero() }</ID>
<ID>NamedArguments:GetMultiWalletWarningsFactory.kt$GetMultiWalletWarningsFactory$addInformationalNotifications(userWallet, cardTypesResolver, flattenCurrencies, clickIntents)</ID>
<ID>NamedArguments:GetMultiWalletWarningsFactory.kt$GetMultiWalletWarningsFactory$addWarningNotifications(cardTypesResolver, flattenCurrencies, isNeedToBackup, clickIntents)</ID>
<ID>NamedArguments:TangemSnapFlingBehavior.kt$HighVelocityApproachAnimation$animateDecay(offset, animationState, decayAnimationSpec, onAnimationStep)</ID>
<ID>NamedArguments:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$animateSnap( closestOffset, closestOffset, animationState, snapAnimationSpec, ) { delta -&gt; remainingScrollOffset -= delta onRemainingScrollOffsetUpdate(remainingScrollOffset) }</ID>
<ID>NamedArguments:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$animateSnap( remainingOffset, remainingOffset, animationState.copy(value = 0f), snapAnimationSpec, ) { delta -&gt; remainingScrollOffset -= delta onAnimationStep(remainingScrollOffset) }</ID>
<ID>NamedArguments:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$approach( initialTargetOffset, initialVelocity, animation, snapLayoutInfoProvider, density, onAnimationStep, )</ID>
<ID>NamedArguments:TangemSnapFlingBehavior.kt$approachAnimation( this, initialTargetOffset, initialVelocity, onAnimationStep, )</ID>
<ID>NamedArguments:WalletContent.kt$tokensListItems(state.tokensListState, modifier, isBalanceHidden, portfolioVisibleState)</ID>
<ID>NamedArguments:WalletContent.kt$txHistoryItems(state.txHistoryState, txHistoryItems, isBalanceHidden, modifier)</ID>
<ID>NamedArguments:WalletScreenContentLoader.kt$WalletScreenContentLoader$loadInternal(userWallet, clickIntents, coroutineScope, isRefresh = true)</ID>
<ID>NamedArguments:WalletScreenContentLoader.kt$WalletScreenContentLoader$loadInternal(userWallet, clickIntents, coroutineScope, isRefresh)</ID>
<ID>NestedScopeFunctions:WalletScreen.kt$let { config -&gt; organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) }</ID>
<ID>NestedScopeFunctions:WalletScreen.kt$let { it.organizeTokensButtonConfig?.let { config -&gt; organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
<ID>NestedScopeFunctions:WalletScreen.kt$let { marketPriceBlockState -&gt; marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier) }</ID>
<ID>NoNameShadowing:DefaultUserWalletsFetcher.kt$DefaultUserWalletsFetcher${ it.isMultiCurrency }</ID>
<ID>NoNameShadowing:MultiCurrencyAccountContent.kt$modifier</ID>
<ID>NoNameShadowing:TxHistorySubscriber.kt$TxHistorySubscriber${ it.cachedIn(coroutineScope) }</ID>
<ID>NoNameShadowing:TxHistorySubscriberV2.kt$TxHistorySubscriberV2${ it.cachedIn(coroutineScope) }</ID>
<ID>NoNameShadowing:WalletComponent.kt$WalletComponent$dialog</ID>
<ID>NoNameShadowing:WalletCurrencyActionsClickIntents.kt$WalletCurrencyActionsClickIntentsImplementor${ it is TokensListItemUM.Token }</ID>
<ID>NoNameShadowing:WalletNFTItem.kt$modifier</ID>
<ID>NoNameShadowing:WalletScreen.kt${ it.organizeTokensButtonConfig?.let { config -&gt; organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
<ID>NullableToStringCall:DefaultPromoDeeplinkHandler.kt$DefaultPromoDeeplinkHandler$$bitcoinCurrency</ID>
<ID>NullableToStringCall:DefaultPromoDeeplinkHandler.kt$DefaultPromoDeeplinkHandler$$bitcoinStatus</ID>
<ID>NullableToStringCall:DefaultPromoDeeplinkHandler.kt$DefaultPromoDeeplinkHandler$${cryptoCurrencies?.size}</ID>
<ID>NullableToStringCall:DefaultPromoDeeplinkHandler.kt$DefaultPromoDeeplinkHandler$${networkStatuses?.size}</ID>
<ID>NullableToStringCall:WalletStateController.kt$WalletStateController$${transformer::class.simpleName}</ID>
<ID>NullableToStringCall:WalletSubscriber.kt$WalletSubscriber$${this::class.simpleName}</ID>
<ID>PropertyUsedBeforeDeclaration:BaseWalletClickIntents.kt$BaseWalletClickIntents$_modelScope</ID>
<ID>PropertyUsedBeforeDeclaration:BaseWalletClickIntents.kt$BaseWalletClickIntents$_router</ID>
<ID>PropertyUsedBeforeDeclaration:OrganizeTokensModel.kt$OrganizeTokensModel$uiState</ID>
<ID>PropertyUsedBeforeDeclaration:WalletScreenPreviewData.kt$WalletScreenPreviewData$buyButton</ID>
<ID>PropertyUsedBeforeDeclaration:WalletStateController.kt$WalletStateController$mutableUiState</ID>
<ID>ReusedModifierInstance:DefaultWalletEntryComponent.kt$DefaultWalletEntryComponent$Content(modifier)</ID>
<ID>ReusedModifierInstance:VisaTxDetailsBottomSheet.kt$LazyColumn( modifier = modifier.background(TangemTheme.colors.background.secondary), contentPadding = PaddingValues( bottom = TangemTheme.dimens.spacing16, ), verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing12), horizontalAlignment = Alignment.CenterHorizontally, ) { item { TransactionBlock(config.transaction) } items(config.requests) { item -&gt; BlockchainRequestBlock(item) } item { DisputeButton(config.onDisputeClick) } }</ID>
<ID>ReusedModifierInstance:WalletNFTItem.kt$Image( modifier = modifier .background(TangemTheme.colors.stroke.primary), painter = painterResource(R.drawable.ic_nft_preview_more_16), contentDescription = null, )</ID>
<ID>ReusedModifierInstance:WalletNFTItem.kt$SubcomposeAsyncImage( modifier = modifier, model = s.url, loading = { RectangleShimmer(radius = 0.dp) }, error = { Box( modifier = Modifier.background(TangemTheme.colors.field.primary), ) }, contentDescription = null, )</ID>
<ID>ReusedModifierInstance:WalletNFTItem.kt$take(modifiers.size)</ID>
<ID>SuspendFunSwallowedCancellation:WalletModel.kt$WalletModel$runCatching</ID>
<ID>UnnecessaryLet:BalancesAndLimitsBottomSheetConverter.kt$BalancesAndLimitsBottomSheetConverter$let(::formatAmount)</ID>
<ID>UnnecessaryLet:MultiWalletContentLoader.kt$MultiWalletContentLoader$let(::add)</ID>
<ID>UnnecessaryLet:SingleWalletWithTokenContentLoader.kt$SingleWalletWithTokenContentLoader$let(::add)</ID>
<ID>UnnecessaryLet:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$let { abs(it) * sign(initialVelocity) // ensure offset sign is correct }</ID>
<ID>UnnecessaryLet:WalletClickIntents.kt$WalletClickIntents$let(::add)</ID>
<ID>UnnecessaryLet:WalletScreen.kt$let { (state.tokensListState as? WalletTokensListState.ContentState)?.let { it.organizeTokensButtonConfig?.let { config -&gt; organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } } }</ID>
<ID>UnnecessaryLet:WalletScreen.kt$let { it.organizeTokensButtonConfig?.let { config -&gt; organizeTokensButton( modifier = itemModifier, isEnabled = config.isEnabled, onClick = config.onClick, ) } }</ID>
<ID>UnnecessarySafeCall:SetVisaInfoTransformer.kt$SetVisaInfoTransformer$visaCurrency.fiatRate?.let { visaCurrency.balances.available.multiply(it) }</ID>
<ID>UseEmptyCounterpart:DefaultUserWalletImageFetcher.kt$DefaultUserWalletImageFetcher$mapOf&lt;String, ArtworkUM&gt;()</ID>
<ID>UseEmptyCounterpart:ExpandedAccountsHolder.kt$ExpandedAccountsHolder$mapOf()</ID>
<ID>UseEmptyCounterpart:ExpandedAccountsHolder.kt$ExpandedAccountsHolder$setOf()</ID>
<ID>UseEmptyCounterpart:PortfolioOrganizeTokensAnalyticsEvent.kt$PortfolioOrganizeTokensAnalyticsEvent$mapOf()</ID>
<ID>UseEmptyCounterpart:PromoActivationAnalytics.kt$PromoActivationAnalytics$mapOf()</ID>
<ID>UseEmptyCounterpart:SingleWalletExpressStatusesSubscriber.kt$SingleWalletExpressStatusesSubscriber$listOf()</ID>
<ID>UseEmptyCounterpart:SingleWalletExpressStatusesSubscriberV2.kt$SingleWalletExpressStatusesSubscriberV2$listOf()</ID>
<ID>UseEmptyCounterpart:TokenListStateConverter.kt$TokenListStateConverter$listOf()</ID>
<ID>UseEmptyCounterpart:WalletScreenAnalyticsEvent.kt$WalletScreenAnalyticsEvent.Basic$mapOf()</ID>
<ID>UseEmptyCounterpart:WalletScreenAnalyticsEvent.kt$WalletScreenAnalyticsEvent.MainScreen$mapOf()</ID>
<ID>UseEmptyCounterpart:WalletScreenAnalyticsEvent.kt$WalletScreenAnalyticsEvent.PushBannerPromo$mapOf()</ID>
<ID>UseOrEmpty:CryptoCurrenciesIdsResolver.kt$CryptoCurrenciesIdsResolver$accountStatusList?.accountStatuses ?.filter { it.getCryptoTokenList() != TokenList.Empty } ?.associate { accountStatus -&gt; val currencies = accountStatus.flattenCurrencies() accountStatus.account as Account.CryptoPortfolio to draggableTokens .asSequence() .filter { it.accountId == accountStatus.account.accountId.value } .mapNotNull { sortedToken -&gt; currencies.firstOrNull { it.currency.id.value == sortedToken.id }?.currency } .toList() } ?: emptyMap()</ID>
<ID>UseSumOfInsteadOfFlatMapSize:TokenListStateConverter.kt$TokenListStateConverter$flatMap(NetworkGroup::currencies)</ID>
<ID>VarCouldBeVal:TangemSnapFlingBehavior.kt$TangemSnapFlingBehavior$private var motionScaleDuration = DefaultScrollMotionDurationScale</ID>
<ID>VarCouldBeVal:WalletModel.kt$WalletModel$private var expressTxStatusTaskScheduler = SingleTaskScheduler&lt;Unit&gt;()</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -11,7 +11,6 @@ import com.tangem.core.analytics.utils.TrackingContextProxy
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
@ -31,7 +30,10 @@ import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.SelectedWalletAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.*
import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletContentFetcher
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
@ -78,7 +80,6 @@ internal class WalletModel @Inject constructor(
private val walletNameMigrationUseCase: WalletNameMigrationUseCase,
private val refreshMultiCurrencyWalletQuotesUseCase: RefreshMultiCurrencyWalletQuotesUseCase,
private val walletImageResolver: WalletImageResolver,
private val tokenListStore: MultiWalletTokenListStore,
private val onrampStatusFactory: OnrampStatusFactory,
private val analyticsEventsHandler: AnalyticsEventHandler,
private val walletContentFetcher: WalletContentFetcher,
@ -90,7 +91,6 @@ internal class WalletModel @Inject constructor(
private val userWalletsListRepository: UserWalletsListRepository,
private val yieldSupplyApyUpdateUseCase: YieldSupplyApyUpdateUseCase,
private val tangemPayOnboardingRepository: OnboardingRepository,
private val accountsFeatureToggles: AccountsFeatureToggles,
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
private val getAppThemeModeUseCase: GetAppThemeModeUseCase,
private val trackingContextProxy: TrackingContextProxy,
@ -112,8 +112,8 @@ internal class WalletModel @Inject constructor(
private val refreshWalletJobHolder = JobHolder()
private val updateTangemPayJobHolder = JobHolder()
private var needToRefreshWallet = false
private var expressTxStatusTaskScheduler = SingleTaskScheduler<Unit>()
private var shouldRefreshWallet = false
private val expressTxStatusTaskScheduler = SingleTaskScheduler<Unit>()
init {
trackScreenOpened()
@ -182,7 +182,6 @@ internal class WalletModel @Inject constructor(
override fun onDestroy() {
super.onDestroy()
tokenListStore.clear()
stateHolder.clear()
walletScreenContentLoader.cancelAll()
}
@ -261,9 +260,9 @@ internal class WalletModel @Inject constructor(
getWalletsUseCase()
.conflate()
.distinctUntilChanged()
.map {
.map { userWallets ->
walletsUpdateActionResolver.resolve(
wallets = it,
wallets = userWallets,
currentState = stateHolder.value,
)
}
@ -355,7 +354,7 @@ internal class WalletModel @Inject constructor(
refreshWalletJobHolder.cancel()
when {
isBackground -> needToRefreshTimer()
needToRefreshWallet && !isBackground -> {
shouldRefreshWallet && !isBackground -> {
triggerRefreshWalletQuotes()
}
}
@ -426,12 +425,12 @@ internal class WalletModel @Inject constructor(
private fun needToRefreshTimer() {
modelScope.launch {
delay(REFRESH_WALLET_BACKGROUND_TIMER_MILLIS)
needToRefreshWallet = true
shouldRefreshWallet = true
}.saveIn(refreshWalletJobHolder)
}
private fun triggerRefreshWalletQuotes() {
needToRefreshWallet = false
shouldRefreshWallet = false
val state = stateHolder.uiState.value
val wallet = state.wallets.getOrNull(state.selectedWalletIndex) ?: return
modelScope.launch {
@ -462,7 +461,6 @@ internal class WalletModel @Inject constructor(
// refresh loader to use actual user wallet
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
isRefresh = true,
coroutineScope = modelScope,
)
@ -510,10 +508,9 @@ internal class WalletModel @Inject constructor(
}
private fun reloadWarnings(action: WalletsUpdateActionResolver.Action.ReloadWallets) {
action.wallets.forEach {
action.wallets.forEach { userWallet ->
walletScreenContentLoader.load(
userWallet = it,
clickIntents = clickIntents,
userWallet = userWallet,
coroutineScope = modelScope,
isRefresh = true,
)
@ -532,7 +529,6 @@ internal class WalletModel @Inject constructor(
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)
@ -559,11 +555,9 @@ internal class WalletModel @Inject constructor(
private fun reinitializeNewWallet(action: WalletsUpdateActionResolver.Action.ReinitializeNewWallet) {
walletScreenContentLoader.cancel(action.prevWalletId)
tokenListStore.remove(action.prevWalletId)
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)
@ -582,11 +576,9 @@ internal class WalletModel @Inject constructor(
private fun reinitializeWallets(action: WalletsUpdateActionResolver.Action.ReinitializeWallets) {
action.wallets.forEach { userWallet ->
walletScreenContentLoader.cancel(userWallet.walletId)
tokenListStore.remove(userWallet.walletId)
walletScreenContentLoader.load(
userWallet = userWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)
@ -603,39 +595,20 @@ internal class WalletModel @Inject constructor(
}
private fun addWallet(action: WalletsUpdateActionResolver.Action.AddWallet) {
if (accountsFeatureToggles.isFeatureEnabled) {
fetchWalletContent(userWallet = action.selectedWallet)
fetchWalletContent(userWallet = action.selectedWallet)
stateHolder.update(
AddWalletTransformer(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
walletImageResolver = walletImageResolver,
),
)
walletScreenContentLoader.load(
stateHolder.update(
AddWalletTransformer(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)
} else {
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)
walletImageResolver = walletImageResolver,
),
)
fetchWalletContent(userWallet = action.selectedWallet)
stateHolder.update(
AddWalletTransformer(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
walletImageResolver = walletImageResolver,
),
)
}
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
coroutineScope = modelScope,
)
scrollToWallet(prevIndex = action.prevWalletIndex, newIndex = action.selectedWalletIndex) {
stateHolder.update {
@ -648,11 +621,9 @@ internal class WalletModel @Inject constructor(
private fun deleteWallet(action: WalletsUpdateActionResolver.Action.DeleteWallet) {
walletScreenContentLoader.cancel(action.deletedWalletId)
tokenListStore.remove(action.deletedWalletId)
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)
@ -696,7 +667,6 @@ internal class WalletModel @Inject constructor(
walletScreenContentLoader.load(
userWallet = action.selectedWallet,
clickIntents = clickIntents,
coroutineScope = modelScope,
)

View file

@ -30,7 +30,7 @@ internal class WalletClickIntents @Inject constructor(
private val currencyActionsClickIntentsImplementor: WalletCurrencyActionsClickIntentsImplementor,
private val contentClickIntentsImplementor: WalletContentClickIntentsImplementor,
private val pushPermissionClickIntentsImplementor: WalletPushPermissionClickIntentsImplementor,
private val stateHolder: WalletStateController,
private val stateController: WalletStateController,
private val walletScreenContentLoader: WalletScreenContentLoader,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val selectWalletUseCase: SelectWalletUseCase,
@ -62,7 +62,7 @@ internal class WalletClickIntents @Inject constructor(
fun onWalletChange(index: Int, onlyState: Boolean) {
if (onlyState) {
stateHolder.update { it.copy(selectedWalletIndex = index) }
stateController.update { it.copy(selectedWalletIndex = index) }
return
}
@ -70,27 +70,23 @@ internal class WalletClickIntents @Inject constructor(
launch { neverToShowWalletsScrollPreview() }
val maybeUserWallet = selectWalletUseCase(
userWalletId = stateHolder.value.wallets[index].walletCardState.id,
userWalletId = stateController.value.wallets[index].walletCardState.id,
)
stateHolder.update { it.copy(selectedWalletIndex = index) }
stateController.update { it.copy(selectedWalletIndex = index) }
maybeUserWallet.onRight {
if (!it.isLocked) {
launch { walletContentFetcher(userWalletId = it.walletId) }
maybeUserWallet.onRight { userWallet ->
if (!userWallet.isLocked) {
launch { walletContentFetcher(userWalletId = userWallet.walletId) }
}
walletScreenContentLoader.load(
userWallet = it,
clickIntents = this@WalletClickIntents,
coroutineScope = modelScope,
)
walletScreenContentLoader.load(userWallet = userWallet, coroutineScope = modelScope)
}
}
}
fun onRefreshSwipe(showRefreshState: Boolean) {
when (stateHolder.getSelectedWallet()) {
when (stateController.getSelectedWallet()) {
is WalletState.MultiCurrency.Content -> {
refreshMultiCurrencyContent(showRefreshState)
}
@ -111,7 +107,7 @@ internal class WalletClickIntents @Inject constructor(
private fun refreshMultiCurrencyContent(showRefreshState: Boolean) {
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
stateHolder.update(
stateController.update(
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = showRefreshState),
)
@ -126,7 +122,7 @@ internal class WalletClickIntents @Inject constructor(
}
.awaitAll()
stateHolder.update(
stateController.update(
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = false),
)
}
@ -137,7 +133,7 @@ internal class WalletClickIntents @Inject constructor(
private fun refreshSingleCurrencyContent(showRefreshState: Boolean) {
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
stateHolder.update(
stateController.update(
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = showRefreshState),
)
@ -147,12 +143,11 @@ internal class WalletClickIntents @Inject constructor(
onrampStatusFactory.updateOnrmapTransactionStatuses(userWallet)
walletScreenContentLoader.load(
userWallet = userWallet,
clickIntents = this@WalletClickIntents,
isRefresh = true,
coroutineScope = modelScope,
)
stateHolder.update(
stateController.update(
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = false),
)
}

View file

@ -22,7 +22,6 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.haptic.VibratorHapticManager
import com.tangem.core.ui.message.DialogMessage
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@ -147,8 +146,6 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val needShowYieldSupplyDepositedWarningUseCase: NeedShowYieldSupplyDepositedWarningUseCase,
private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase,
private val isCryptoCurrencyCoinCouldHide: IsCryptoCurrencyCoinCouldHideUseCase,
private val removeCurrencyUseCase: RemoveCurrencyUseCase,
private val accountsFeatureToggles: AccountsFeatureToggles,
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
private val uiMessageSender: UiMessageSender,
@ -289,23 +286,19 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
override fun onPerformHideToken(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) {
modelScope.launch(dispatchers.io) {
if (accountsFeatureToggles.isFeatureEnabled) {
val accountId = getAccountCurrencyStatusUseCase.invokeSync(
userWalletId = userWalletId,
currency = cryptoCurrencyStatus.currency,
)
.map { it.account.accountId }
.getOrNull()
val accountId = getAccountCurrencyStatusUseCase.invokeSync(
userWalletId = userWalletId,
currency = cryptoCurrencyStatus.currency,
)
.map { it.account.accountId }
.getOrNull()
if (accountId == null) {
Timber.e("Account ID is null, cannot hide currency ${cryptoCurrencyStatus.currency.id}")
return@launch
}
manageCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrencyStatus.currency)
} else {
removeCurrencyUseCase(userWalletId, cryptoCurrencyStatus.currency)
if (accountId == null) {
Timber.e("Account ID is null, cannot hide currency ${cryptoCurrencyStatus.currency.id}")
return@launch
}
manageCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrencyStatus.currency)
.fold(
ifLeft = {
walletEventSender.send(

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.account
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.supplier.SingleAccountStatusSupplier
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
@ -9,7 +8,6 @@ import javax.inject.Inject
@ModelScoped
internal class AccountDependencies @Inject constructor(
val accountsFeatureToggles: AccountsFeatureToggles,
val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
val expandedAccountsHolder: ExpandedAccountsHolder,
val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,

View file

@ -11,7 +11,6 @@ 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.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.hotwallet.CheckHotWalletUpgradeBannerUseCase
import com.tangem.domain.hotwallet.GetAccessCodeSkippedUseCase
@ -52,7 +51,6 @@ import javax.inject.Inject
@Suppress("LongParameterList", "LargeClass")
@ModelScoped
internal class GetMultiWalletWarningsFactory @Inject constructor(
private val tokenListStore: MultiWalletTokenListStore,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
@ -71,30 +69,15 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotification>> {
val cardTypesResolver = (userWallet as? UserWallet.Cold)?.scanResponse?.cardTypesResolver
val accountStatusList by lazy {
val accountStatusListFlow by lazy {
val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
accountDependencies.singleAccountStatusListSupplier(params)
.map { it.totalFiatBalance to it.flattenCurrencies() }
.map { Lce.Content(it) }
}
fun tokenListFlow(): LceFlow<TokenListError, Pair<TotalFiatBalance, List<CryptoCurrencyStatus>>> {
return if (accountDependencies.accountsFeatureToggles.isFeatureEnabled) {
accountStatusList
} else {
runCatching { tokenListStore.getOrThrow(userWallet.walletId) }
.map { result -> result.map { lce -> lce.map { it.totalFiatBalance to it.flattenCurrencies() } } }
.getOrNull()
// in case of runtime change ft in tester menu
?: accountStatusList
}
}
// val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
// val accountStatusListFlow = accountDependencies.singleAccountStatusListSupplier(params)
return combine(
// todo account just use it, after delete accountsFeatureToggles
// accountStatusListFlow,
accountStatusListFlow,
isReadyToShowRateAppUseCase().distinctUntilChanged(),
isNeedToBackupUseCase(userWallet.walletId).distinctUntilChanged(),
seedPhraseNotificationUseCase(userWalletId = userWallet.walletId).distinctUntilChanged(),
@ -110,7 +93,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
getUpgradeBannerClosureTimestampUseCase(userWallet.walletId)
.distinctUntilChanged(),
) { array -> array }
.combine(tokenListFlow()) { array, any: Any? -> arrayOf(any).plus(elements = array) }
.map { array ->
val lceTokens = array[0] as Lce<TokenListError, Pair<TotalFiatBalance, List<CryptoCurrencyStatus>>>
val totalFiatBalance = lceTokens.map { it.first }
@ -149,9 +131,19 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
addYieldPromoNotification(clickIntents, shouldShowYieldPromo)
addInformationalNotifications(userWallet, cardTypesResolver, flattenCurrencies, clickIntents)
addInformationalNotifications(
userWallet = userWallet,
cardTypesResolver = cardTypesResolver,
flattenCurrencies = flattenCurrencies,
clickIntents = clickIntents,
)
addWarningNotifications(cardTypesResolver, flattenCurrencies, isNeedToBackup, clickIntents)
addWarningNotifications(
cardTypesResolver = cardTypesResolver,
flattenCurrencies = flattenCurrencies,
isNeedToBackup = isNeedToBackup,
clickIntents = clickIntents,
)
addPushReminderNotification(
clickIntents = clickIntents,

View file

@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.domain
import arrow.core.Either
import arrow.core.right
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.producer.SingleAccountStatusProducer
import com.tangem.domain.account.status.supplier.SingleAccountStatusSupplier
import com.tangem.domain.card.CardTypesResolver
@ -15,7 +14,6 @@ import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
@ -30,8 +28,6 @@ import javax.inject.Inject
@ModelScoped
@Suppress("LongParameterList")
internal class GetSingleWalletWarningsFactory @Inject constructor(
private val accountsFeatureToggles: AccountsFeatureToggles,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val singleAccountStatusSupplier: SingleAccountStatusSupplier,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
@ -40,7 +36,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
private val getWalletsUseCase: GetWalletsUseCase,
) {
private var readyForRateAppNotification = false
private var isReadyForRateAppNotification = false
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): Flow<ImmutableList<WalletNotification>> {
if (userWallet !is UserWallet.Cold) {
@ -54,7 +50,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
flow4 = getWalletsUseCase().conflate(),
) { maybePrimaryCurrencyStatus, isReadyToShowRating, isNeedToBackup, userWallets ->
readyForRateAppNotification = true
isReadyForRateAppNotification = true
buildList {
addUsedOutdatedDataNotification(maybePrimaryCurrencyStatus)
@ -120,8 +116,8 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
cardTypesResolver: CardTypesResolver,
clickIntents: WalletClickIntents,
) {
val userHasWalletOrWallet2 = userWallets.filterIsInstance<UserWallet.Cold>().any {
val typesResolver = it.scanResponse.cardTypesResolver
val hasWalletOrWallet2 = userWallets.filterIsInstance<UserWallet.Cold>().any { coldWallet ->
val typesResolver = coldWallet.scanResponse.cardTypesResolver
typesResolver.isTangemWallet() || typesResolver.isWallet2()
}
@ -129,7 +125,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
element = WalletNotification.NoteMigration(
onClick = { clickIntents.onNoteMigrationButtonClick(NOTE_MIGRATION_URL) },
),
condition = cardTypesResolver.isTangemNote() && !userHasWalletOrWallet2,
condition = cardTypesResolver.isTangemNote() && !hasWalletOrWallet2,
)
addIf(
@ -191,8 +187,8 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
selectedWallet: UserWallet.Cold,
cryptoCurrencyStatus: CryptoCurrencyStatus?,
): Boolean {
return cryptoCurrencyStatus?.currency?.network?.let {
hasSingleWalletSignedHashesUseCase(userWallet = selectedWallet, network = it)
return cryptoCurrencyStatus?.currency?.network?.let { network ->
hasSingleWalletSignedHashesUseCase(userWallet = selectedWallet, network = network)
.conflate()
.distinctUntilChanged()
.firstOrNull()
@ -209,7 +205,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
onDislikeClick = clickIntents::onDislikeAppClick,
onCloseClick = clickIntents::onCloseRateAppWarningClick,
),
condition = isReadyToShowRating && readyForRateAppNotification,
condition = isReadyToShowRating && isReadyForRateAppNotification,
)
}
@ -219,7 +215,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
element is WalletNotification.Warning ||
element is WalletNotification.NoteMigration
) {
readyForRateAppNotification = false
isReadyForRateAppNotification = false
}
element
@ -229,16 +225,12 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
private fun getPrimaryCurrencyStatusFlow(
userWallet: UserWallet,
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
return if (accountsFeatureToggles.isFeatureEnabled) {
getAccountStatusFlow(userWallet).mapNotNull { accountStatus ->
accountStatus.flattenCurrencies().firstOrNull()
}
.distinctUntilChanged()
.conflate()
.map { it.right() }
} else {
getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWallet.walletId)
return getAccountStatusFlow(userWallet).mapNotNull { accountStatus ->
accountStatus.flattenCurrencies().firstOrNull()
}
.distinctUntilChanged()
.conflate()
.map { it.right() }
}
private fun getAccountStatusFlow(userWallet: UserWallet): Flow<AccountStatus.CryptoPortfolio> {

View file

@ -1,62 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.domain
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.error.TokenListError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.shareIn
import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@ModelScoped
internal class MultiWalletTokenListStore @Inject constructor(
private val getTokenListUseCase: GetTokenListUseCase,
) {
private val flows: ConcurrentHashMap<UserWalletId, LceFlow<TokenListError, TokenList>> by lazy {
ConcurrentHashMap()
}
fun addIfNot(userWalletId: UserWalletId, coroutineScope: CoroutineScope) {
if (flows[userWalletId] != null) {
Timber.d("Flow with token list for $userWalletId already exists")
return
}
coroutineScope.ensureActive()
flows[userWalletId] = getTokenListUseCase
.launch(userWalletId)
.shareIn(
scope = coroutineScope,
started = SharingStarted.WhileSubscribed(),
replay = 1,
)
Timber.d("Flow with token list for $userWalletId created")
}
fun getOrThrow(userWalletId: UserWalletId): LceFlow<TokenListError, TokenList> {
return requireNotNull(flows[userWalletId]) {
"Flow with token list for $userWalletId doesn't exist"
}
}
fun remove(userWalletId: UserWalletId) {
flows.remove(userWalletId)
Timber.d("Flow with token list for $userWalletId removed")
}
fun clear() {
flows.clear()
Timber.d("All flows with token list cleared")
}
}

View file

@ -1,52 +1,33 @@
package com.tangem.feature.wallet.presentation.wallet.loaders
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.*
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.MultiWalletContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.SingleWalletContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.SingleWalletWithTokenContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.WalletContentLoader
import javax.inject.Inject
@Suppress("LongParameterList")
@ModelScoped
internal class WalletContentLoaderFactory @Inject constructor(
private val multiWalletContentLoaderFactory: MultiWalletContentLoaderFactory,
private val multiWalletContentLoaderV2Factory: MultiWalletContentLoaderV2.Factory,
private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoaderFactory,
private val singleWalletWithTokenContentLoaderV2Factory: SingleWalletWithTokenContentLoaderV2.Factory,
private val accountsFeatureToggles: AccountsFeatureToggles,
private val singleWalletContentLoaderFactory: SingleWalletContentLoaderFactory,
private val singleWalletContentLoaderV2Factory: SingleWalletContentLoaderV2.Factory,
private val multiWalletContentLoaderFactory: MultiWalletContentLoader.Factory,
private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoader.Factory,
private val singleWalletContentLoaderFactory: SingleWalletContentLoader.Factory,
) {
fun create(
userWallet: UserWallet,
clickIntents: WalletClickIntents,
isRefresh: Boolean = false,
): WalletContentLoader? {
fun create(userWallet: UserWallet, isRefresh: Boolean = false): WalletContentLoader? {
return when {
userWallet.isMultiCurrency -> {
if (accountsFeatureToggles.isFeatureEnabled) {
multiWalletContentLoaderV2Factory.create(userWallet)
} else {
multiWalletContentLoaderFactory.create(userWallet, clickIntents)
}
multiWalletContentLoaderFactory.create(userWallet)
}
userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken() -> {
if (accountsFeatureToggles.isFeatureEnabled) {
singleWalletWithTokenContentLoaderV2Factory.create(userWallet)
} else {
singleWalletWithTokenContentLoaderFactory.create(userWallet, clickIntents)
}
singleWalletWithTokenContentLoaderFactory.create(userWallet)
}
userWallet is UserWallet.Cold && !userWallet.isMultiCurrency -> {
if (accountsFeatureToggles.isFeatureEnabled) {
singleWalletContentLoaderV2Factory.create(userWallet, isRefresh)
} else {
singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
}
singleWalletContentLoaderFactory.create(userWallet, isRefresh)
}
else -> null
}

View file

@ -18,8 +18,8 @@ internal class WalletLoaderStorage @Inject constructor() {
}
fun remove(id: UserWalletId) {
loaders[id]?.let {
it.forEach(Job::cancel)
loaders[id]?.let { jobs ->
jobs.forEach(Job::cancel)
loaders.remove(id)
}
}

View file

@ -4,7 +4,6 @@ import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.isLocked
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import kotlinx.coroutines.CloseableCoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.newSingleThreadContext
@ -14,9 +13,8 @@ import javax.inject.Inject
/**
* Base wallet screen content loader. Use it to load content by [UserWallet].
*
* @property factory factory that creates loader
* @property storage storage that save loader's jobs
* @property dispatchers coroutine dispatchers provider
* @property factory factory that creates loader
* @property storage storage that save loader's jobs
*
[REDACTED_AUTHOR]
*/
@ -33,25 +31,19 @@ internal class WalletScreenContentLoader @Inject constructor(
* Load content by [UserWallet]
*
* @param userWallet user wallet
* @param clickIntents click intents
* @param isRefresh flag that determinate if content must load again
* @param coroutineScope coroutine scope
*/
fun load(
userWallet: UserWallet,
clickIntents: WalletClickIntents,
isRefresh: Boolean = false,
coroutineScope: CoroutineScope,
) {
fun load(userWallet: UserWallet, isRefresh: Boolean = false, coroutineScope: CoroutineScope) {
if (userWallet.isLocked) return
val id = userWallet.walletId
if (!storage.contains(id)) {
loadInternal(userWallet, clickIntents, coroutineScope, isRefresh)
loadInternal(userWallet, coroutineScope, isRefresh)
} else {
if (isRefresh) {
storage.remove(id)
loadInternal(userWallet, clickIntents, coroutineScope, isRefresh = true)
loadInternal(userWallet, coroutineScope, isRefresh = true)
} else {
Timber.d("$id content loading has already started")
}
@ -70,15 +62,9 @@ internal class WalletScreenContentLoader @Inject constructor(
singleBackgroundDispatcher.close()
}
private fun loadInternal(
userWallet: UserWallet,
clickIntents: WalletClickIntents,
coroutineScope: CoroutineScope,
isRefresh: Boolean,
) {
private fun loadInternal(userWallet: UserWallet, coroutineScope: CoroutineScope, isRefresh: Boolean) {
val loader = factory.create(
userWallet = userWallet,
clickIntents = clickIntents,
isRefresh = isRefresh,
)

View file

@ -1,92 +1,33 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
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.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
@Deprecated("Use MultiWalletContentLoaderV2 instead")
@ModelScoped
internal class MultiWalletContentLoader(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val tokenListStore: MultiWalletTokenListStore,
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val walletsRepository: WalletsRepository,
private val currenciesRepository: CurrenciesRepository,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
internal class MultiWalletContentLoader @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val accountListSubscriberFactory: AccountListSubscriber.Factory,
private val walletNFTListSubscriberFactory: WalletNFTListSubscriberV2.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
private val multiWalletWarningsSubscriberFactory: MultiWalletWarningsSubscriber.Factory,
private val multiWalletActionButtonsSubscriberFactory: MultiWalletActionButtonsSubscriber.Factory,
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
return buildList {
MultiWalletTokenListSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase = stakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
).let(::add)
override fun create(): List<WalletSubscriber> = listOf(
accountListSubscriberFactory.create(userWallet),
walletNFTListSubscriberFactory.create(userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet),
multiWalletWarningsSubscriberFactory.create(userWallet),
multiWalletActionButtonsSubscriberFactory.create(userWallet),
tangemPayMainSubscriberFactory.create(userWallet),
)
WalletNFTListSubscriber(
userWallet = userWallet,
getNFTCollectionsUseCase = getNFTCollectionsUseCase,
stateHolder = stateHolder,
walletsRepository = walletsRepository,
clickIntents = clickIntents,
currenciesRepository = currenciesRepository,
).let(::add)
MultiWalletWarningsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
).let(::add)
MultiWalletActionButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
getStoryContentUseCase = getStoryContentUseCase,
).let(::add)
add(tangemPayMainSubscriberFactory.create(userWallet))
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): MultiWalletContentLoader
}
}

View file

@ -1,71 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
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.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.TangemPayMainSubscriber
import javax.inject.Inject
@Suppress("LongParameterList")
@Deprecated("Use MultiWalletContentLoaderV2.Factory instead")
@ModelScoped
internal class MultiWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val tokenListStore: MultiWalletTokenListStore,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val walletsRepository: WalletsRepository,
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
private val currenciesRepository: CurrenciesRepository,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): WalletContentLoader {
return MultiWalletContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,
stateHolder = stateHolder,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
getStoryContentUseCase = getStoryContentUseCase,
walletsRepository = walletsRepository,
getNFTCollectionsUseCase = getNFTCollectionsUseCase,
currenciesRepository = currenciesRepository,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase = stakingAvailabilityListUseCase,
tangemPayMainSubscriberFactory = tangemPayMainSubscriberFactory,
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
)
}
}

View file

@ -1,54 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
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.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
internal class MultiWalletContentLoaderV2 @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val accountListSubscriberFactory: AccountListSubscriber.Factory,
private val walletNFTListSubscriberV2Factory: WalletNFTListSubscriberV2.Factory,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
accountListSubscriberFactory.create(userWallet = userWallet),
walletNFTListSubscriberV2Factory.create(userWallet = userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet = userWallet),
MultiWalletWarningsSubscriber(
userWallet = userWallet,
stateHolder = stateController,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
),
MultiWalletActionButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateController,
getStoryContentUseCase = getStoryContentUseCase,
),
tangemPayMainSubscriberFactory.create(userWallet),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): MultiWalletContentLoaderV2
}
}

View file

@ -1,83 +1,34 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
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.domain.GetSingleWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
internal class SingleWalletContentLoader(
private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents,
private val isRefresh: Boolean,
private val stateHolder: WalletStateController,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
internal class SingleWalletContentLoader @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
@Assisted private val isRefresh: Boolean,
private val primaryCurrencySubscriberFactory: PrimaryCurrencySubscriber.Factory,
private val singleWalletButtonsSubscriberFactory: SingleWalletButtonsSubscriber.Factory,
private val singleWalletNotificationsSubscriberFactory: SingleWalletNotificationsSubscriber.Factory,
private val singleWalletExpressStatusesSubscriberFactory: SingleWalletExpressStatusesSubscriber.Factory,
private val txHistorySubscriberFactory: TxHistorySubscriber.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
return listOf(
PrimaryCurrencySubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase,
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
analyticsEventHandler = analyticsEventHandler,
),
SingleWalletButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase,
getCryptoCurrencyActionsUseCase = getCryptoCurrencyActionsUseCase,
),
SingleWalletNotificationsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
getSingleWalletWarningsFactory = getSingleWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
),
SingleWalletExpressStatusesSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
analyticsEventHandler = analyticsEventHandler,
getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase,
getOnrampTransactionsUseCase = getOnrampTransactionsUseCase,
onrampRemoveTransactionUseCase = onrampRemoveTransactionUseCase,
),
TxHistorySubscriber(
userWallet = userWallet,
isRefresh = isRefresh,
stateHolder = stateHolder,
clickIntents = clickIntents,
getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
),
)
override fun create(): List<WalletSubscriber> = listOf(
primaryCurrencySubscriberFactory.create(userWallet),
singleWalletButtonsSubscriberFactory.create(userWallet),
singleWalletNotificationsSubscriberFactory.create(userWallet),
singleWalletExpressStatusesSubscriberFactory.create(userWallet),
txHistorySubscriberFactory.create(userWallet, isRefresh),
checkWalletWithFundsSubscriberFactory.create(userWallet),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): SingleWalletContentLoader
}
}

View file

@ -1,57 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
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.domain.GetSingleWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import javax.inject.Inject
@ModelScoped
@Suppress("LongParameterList")
@Deprecated("Use SingleWalletContentLoaderV2.Factory instead")
internal class SingleWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateController,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) {
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
return SingleWalletContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,
isRefresh = isRefresh,
stateHolder = stateHolder,
getSingleCryptoCurrencyStatusUseCase = getSingleCryptoCurrencyStatusUseCase,
getCryptoCurrencyActionsUseCase = getCryptoCurrencyActionsUseCase,
getSingleWalletWarningsFactory = getSingleWalletWarningsFactory,
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
analyticsEventHandler = analyticsEventHandler,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
getOnrampTransactionsUseCase = getOnrampTransactionsUseCase,
onrampRemoveTransactionUseCase = onrampRemoveTransactionUseCase,
)
}
}

View file

@ -1,96 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
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.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
internal class SingleWalletContentLoaderV2 @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
@Assisted private val isRefresh: Boolean,
private val clickIntents: WalletClickIntents,
private val stateHolder: WalletStateController,
private val getCryptoCurrencyActionsUseCaseV2: GetCryptoCurrencyActionsUseCaseV2,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val accountDependencies: AccountDependencies,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val dispatchers: CoroutineDispatcherProvider,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
PrimaryCurrencySubscriberV2(
userWallet = userWallet,
singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
stateController = stateHolder,
analyticsEventHandler = analyticsEventHandler,
),
SingleWalletButtonsSubscriberV2(
userWallet = userWallet,
singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier,
stateController = stateHolder,
clickIntents = clickIntents,
getCryptoCurrencyActionsUseCaseV2 = getCryptoCurrencyActionsUseCaseV2,
),
SingleWalletNotificationsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
getSingleWalletWarningsFactory = getSingleWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
),
SingleWalletExpressStatusesSubscriberV2(
userWallet = userWallet,
singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier,
getOnrampTransactionsUseCase = getOnrampTransactionsUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
onrampRemoveTransactionUseCase = onrampRemoveTransactionUseCase,
stateController = stateHolder,
clickIntents = clickIntents,
analyticsEventHandler = analyticsEventHandler,
),
TxHistorySubscriberV2(
userWallet = userWallet,
singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
isRefresh = isRefresh,
stateController = stateHolder,
clickIntents = clickIntents,
),
CheckWalletWithFundsSubscriber(
userWallet = userWallet,
singleAccountStatusListSupplier = accountDependencies.singleAccountStatusListSupplier,
walletWithFundsChecker = walletWithFundsChecker,
dispatchers = dispatchers,
),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): SingleWalletContentLoaderV2
}
}

View file

@ -1,70 +1,29 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
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.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionButtonsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.CheckWalletWithFundsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenListSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Deprecated("Use SingleWalletWithTokenContentLoaderV2 instead")
@Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoader(
private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents,
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val tokenListStore: MultiWalletTokenListStore,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
internal class SingleWalletWithTokenContentLoader @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
private val singleWalletWithTokenSubscriberFactory: SingleWalletWithTokenSubscriber.Factory,
private val multiWalletWarningsSubscriberFactory: MultiWalletWarningsSubscriber.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
return buildList {
SingleWalletWithTokenListSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase = stakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
).let(::add)
MultiWalletWarningsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
).let(::add)
MultiWalletActionButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
getStoryContentUseCase = getStoryContentUseCase,
).let(::add)
}
override fun create(): List<WalletSubscriber> = listOf(
singleWalletWithTokenSubscriberFactory.create(userWallet),
multiWalletWarningsSubscriberFactory.create(userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold): SingleWalletWithTokenContentLoader
}
}

View file

@ -1,57 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
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.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import javax.inject.Inject
// TODO: Refactor
@Suppress("LongParameterList")
@Deprecated("Use SingleWalletWithTokenContentLoaderV2.Factory instead")
@ModelScoped
internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val tokenListStore: MultiWalletTokenListStore,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
) {
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
return SingleWalletWithTokenContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,
stateHolder = stateHolder,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
getStoryContentUseCase = getStoryContentUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase = stakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
)
}
}

View file

@ -1,46 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
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.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.CheckWalletWithFundsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoaderV2 @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
private val singleWalletWithTokenSubscriberFactory: SingleWalletWithTokenSubscriber.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
private val clickIntents: WalletClickIntents,
private val stateController: WalletStateController,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
singleWalletWithTokenSubscriberFactory.create(userWallet),
MultiWalletWarningsSubscriber(
userWallet = userWallet,
stateHolder = stateController,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
),
checkWalletWithFundsSubscriberFactory.create(userWallet),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold): SingleWalletWithTokenContentLoaderV2
}
}

View file

@ -1,165 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.getOrElse
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.utils.getOrElse
import com.tangem.domain.models.PortfolioId
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.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
import java.math.BigDecimal
@Deprecated("Use AccountListSubscriber instead")
@Suppress("LongParameterList")
internal abstract class BasicTokenListSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
) : WalletSubscriber() {
private val sendAnalyticsJobHolder = JobHolder()
private val onTokenListReceivedJobHolder = JobHolder()
protected abstract fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList>
protected abstract suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>)
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return combine(
flow = tokenListFlow(coroutineScope)
.onEach { maybeTokenList ->
coroutineScope.launch {
sendTokenListAnalytics(
flattenCurrencies = maybeTokenList.getOrNull()?.flattenCurrencies(),
totalFiatBalance = maybeTokenList.getOrNull()?.totalFiatBalance,
)
}.saveIn(sendAnalyticsJobHolder)
}
.distinctUntilChanged()
.onEach { maybeTokenList ->
coroutineScope.launch {
onTokenListReceived(maybeTokenList)
}.saveIn(onTokenListReceivedJobHolder)
},
flow2 = appCurrencyFlow(),
flow3 = yieldSupplyApyFlow(),
flow4 = yieldSupplyGetShouldShowMainPromoFlow(),
transform = { maybeTokenList, appCurrency, yieldSupplyApyMap, shouldShowMainPromo ->
val tokenList = maybeTokenList.getOrElse(
ifLoading = { maybeContent ->
val isRefreshing = stateHolder.getWalletState(userWallet.walletId)
?.pullToRefreshConfig
?.isRefreshing == true
maybeContent
?.takeIf { !isRefreshing }
?: return@combine
},
ifError = { e ->
Timber.e("Failed to load token list: $e")
stateHolder.update(
SetTokenListErrorTransformer(
selectedWallet = userWallet,
error = e,
appCurrency = appCurrency,
),
)
return@combine
},
)
updateContent(
params = TokenConverterParams.Wallet(PortfolioId(userWallet.walletId), tokenList),
appCurrency = appCurrency,
yieldSupplyApyMap = yieldSupplyApyMap,
stakingAvailabilityMap = stakingAvailabilityListUseCase.invokeSync(
userWalletId = userWallet.walletId,
cryptoCurrencyList = tokenList.flattenCurrencies().map(CryptoCurrencyStatus::currency),
),
shouldShowMainPromo = shouldShowMainPromo,
)
walletWithFundsChecker.check(tokenList)
},
)
}
private suspend fun sendTokenListAnalytics(
flattenCurrencies: List<CryptoCurrencyStatus>?,
totalFiatBalance: TotalFiatBalance?,
) {
val displayedState = stateHolder.getWalletStateIfSelected(userWallet.walletId)
tokenListAnalyticsSender.send(
displayedUiState = displayedState,
userWallet = userWallet,
flattenCurrencies = flattenCurrencies ?: return,
totalFiatBalance = totalFiatBalance ?: return,
)
}
private fun updateContent(
params: TokenConverterParams,
appCurrency: AppCurrency,
yieldSupplyApyMap: Map<String, BigDecimal>,
stakingAvailabilityMap: Map<CryptoCurrency, StakingAvailability>,
shouldShowMainPromo: Boolean,
) {
stateHolder.update(
SetTokenListTransformer(
params = params,
userWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
yieldSupplyApyMap = yieldSupplyApyMap,
stakingAvailabilityMap = stakingAvailabilityMap,
shouldShowMainPromo = shouldShowMainPromo,
isAccountsModeEnabled = false,
),
)
}
private fun appCurrencyFlow(): Flow<AppCurrency> = getSelectedAppCurrencyUseCase()
.map {
it.getOrElse { e ->
Timber.e("Failed to load app currency: $e")
AppCurrency.Default
}
}
.distinctUntilChanged()
private fun yieldSupplyApyFlow(): Flow<Map<String, BigDecimal>> = yieldSupplyApyFlowUseCase()
.distinctUntilChanged()
private fun yieldSupplyGetShouldShowMainPromoFlow(): Flow<Boolean> = yieldSupplyGetShouldShowMainPromoUseCase()
.distinctUntilChanged()
}

View file

@ -1,28 +1,37 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.promo.models.StoryContentIds
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.UpdateMultiWalletActionButtonBadgeTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
internal class MultiWalletActionButtonsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
internal class MultiWalletActionButtonsSubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateController: WalletStateController,
private val getStoryContentUseCase: GetStoryContentUseCase,
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> = getStoryContentUseCase(
id = StoryContentIds.STORY_FIRST_TIME_SWAP.id,
).map { maybeSwapStories ->
val isSwapStoriesNotNull = maybeSwapStories.getOrNull() != null
stateHolder.update(
stateController.update(
UpdateMultiWalletActionButtonBadgeTransformer(
userWalletId = userWallet.walletId,
showSwapBadge = isSwapStoriesNotNull,
),
)
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): MultiWalletActionButtonsSubscriber
}
}

View file

@ -1,83 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.models.TokensSortType
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import kotlinx.coroutines.CoroutineScope
@Deprecated("Use AccountListSubscriber instead")
@Suppress("LongParameterList")
internal class MultiWalletTokenListSubscriber(
private val userWallet: UserWallet,
private val tokenListStore: MultiWalletTokenListStore,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
stateHolder: WalletStateController,
clickIntents: WalletClickIntents,
tokenListAnalyticsSender: TokenListAnalyticsSender,
walletWithFundsChecker: WalletWithFundsChecker,
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
) : BasicTokenListSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase = stakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
) {
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
tokenListStore.addIfNot(userWallet.walletId, coroutineScope)
return tokenListStore.getOrThrow(userWallet.walletId)
}
override suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>) {
updateSortingIfNeeded(maybeTokenList)
}
private suspend fun updateSortingIfNeeded(maybeTokenList: Lce<*, TokenList>) {
val tokenList = getTokenList(maybeTokenList) ?: return
applyTokenListSortingUseCase(
userWalletId = userWallet.walletId,
sortedTokensIds = getCurrenciesIds(tokenList),
isGroupedByNetwork = tokenList is TokenList.GroupedByNetwork,
isSortedByBalance = tokenList.sortedBy == TokensSortType.BALANCE,
)
}
private fun getTokenList(lce: Lce<*, TokenList>): TokenList? {
val tokenList = lce.getOrNull(isPartialContentAccepted = false)
?: return null
return tokenList.takeIf {
tokenList.totalFiatBalance is TotalFiatBalance.Loaded &&
tokenList.sortedBy == TokensSortType.BALANCE
}
}
private fun getCurrenciesIds(tokenList: TokenList): List<CryptoCurrency.ID> {
return tokenList.flattenCurrencies().map { it.currency.id }
}
}

View file

@ -8,14 +8,17 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin
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 dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
internal class MultiWalletWarningsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
internal class MultiWalletWarningsSubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
@ -27,14 +30,14 @@ internal class MultiWalletWarningsSubscriber(
.conflate()
.distinctUntilChanged()
.onEach { warnings ->
val displayedState = stateHolder.getWalletState(userWallet.walletId)
val displayedState = stateController.getWalletState(userWallet.walletId)
// Wait until the wallet appears in the list
stateHolder.uiState.first {
stateController.uiState.first {
it.wallets.any { walletState -> walletState.walletCardState.id == userWallet.walletId }
}
stateHolder.update(
stateController.update(
SetWarningsTransformer(
userWalletId = userWallet.walletId,
warnings = warnings,
@ -49,4 +52,9 @@ internal class MultiWalletWarningsSubscriber(
)
}
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): MultiWalletWarningsSubscriber
}
}

View file

@ -1,62 +1,47 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetPrimaryCurrencyTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import timber.log.Timber
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import java.math.BigDecimal
@Deprecated("Use PrimaryCurrencySubscriberV2 instead")
internal class PrimaryCurrencySubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
internal class PrimaryCurrencySubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val stateController: WalletStateController,
private val analyticsEventHandler: AnalyticsEventHandler,
) : WalletSubscriber() {
) : BasicSingleWalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
): Flow<Pair<Either<CurrencyStatusError, CryptoCurrencyStatus>, AppCurrency>> {
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return combine(
flow = getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWallet.walletId)
.conflate()
.distinctUntilChanged(),
flow2 = getSelectedAppCurrencyUseCase()
.conflate()
.distinctUntilChanged()
.map { maybeAppCurrency -> maybeAppCurrency.getOrElse { AppCurrency.Default } },
transform = { maybeCurrencyStatus, appCurrency -> maybeCurrencyStatus to appCurrency },
flow = getPrimaryCurrencyStatusFlow(),
flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
transform = ::Pair,
)
.onEach { maybeCurrencyStatusAndAppCurrency ->
val status = maybeCurrencyStatusAndAppCurrency.first.getOrElse {
Timber.e("Unable to get primary currency status: $it")
return@onEach
}
updateContent(status, maybeCurrencyStatusAndAppCurrency.second)
.onEach { (status, appCurrency) ->
updateContent(status, appCurrency)
sendAnalyticsEvent(status)
checkWalletWithFunds(status)
}
}
private fun updateContent(status: CryptoCurrencyStatus, appCurrency: AppCurrency) {
stateHolder.update(
stateController.update(
SetPrimaryCurrencyTransformer(
status = status,
userWallet = userWallet,
@ -81,11 +66,11 @@ internal class PrimaryCurrencySubscriber(
-> null
}
cardBalanceState?.let {
cardBalanceState?.let { balanceState ->
// do not send tokens count for single currency wallet
analyticsEventHandler.send(
event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded(
balance = it,
balance = balanceState,
tokensCount = null,
),
)
@ -100,7 +85,8 @@ internal class PrimaryCurrencySubscriber(
}
}
private suspend fun checkWalletWithFunds(status: CryptoCurrencyStatus) {
if (status.value.amount?.isZero() == false) setWalletWithFundsFoundUseCase()
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): PrimaryCurrencySubscriber
}
}

View file

@ -1,84 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetPrimaryCurrencyTransformer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import java.math.BigDecimal
internal class PrimaryCurrencySubscriberV2(
override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val stateController: WalletStateController,
private val analyticsEventHandler: AnalyticsEventHandler,
) : BasicSingleWalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return combine(
flow = getPrimaryCurrencyStatusFlow(),
flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
transform = ::Pair,
)
.onEach { (status, appCurrency) ->
updateContent(status, appCurrency)
sendAnalyticsEvent(status)
}
}
private fun updateContent(status: CryptoCurrencyStatus, appCurrency: AppCurrency) {
stateController.update(
SetPrimaryCurrencyTransformer(
status = status,
userWallet = userWallet,
appCurrency = appCurrency,
),
)
}
private fun sendAnalyticsEvent(status: CryptoCurrencyStatus) {
val fiatAmount = status.value.fiatAmount
val cardBalanceState = when (status.value) {
is CryptoCurrencyStatus.Loaded,
is CryptoCurrencyStatus.NoAccount,
is CryptoCurrencyStatus.NoAmount,
-> createCardBalanceState(fiatAmount)
is CryptoCurrencyStatus.NoQuote -> AnalyticsParam.CardBalanceState.NoRate
is CryptoCurrencyStatus.Unreachable,
-> AnalyticsParam.CardBalanceState.BlockchainError
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Loading,
is CryptoCurrencyStatus.Custom,
-> null
}
cardBalanceState?.let {
// do not send tokens count for single currency wallet
analyticsEventHandler.send(
event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded(
balance = it,
tokensCount = null,
),
)
}
}
private fun createCardBalanceState(fiatAmount: BigDecimal?): AnalyticsParam.CardBalanceState? {
return when {
fiatAmount == null -> null
fiatAmount.isZero() -> AnalyticsParam.CardBalanceState.Empty
else -> AnalyticsParam.CardBalanceState.Full
}
}
}

View file

@ -1,44 +1,43 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetCryptoCurrencyActionsTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.onEach
@Deprecated("Use SingleWalletButtonsSubscriberV2 instead")
internal class SingleWalletButtonsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
internal class SingleWalletButtonsSubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
) : WalletSubscriber() {
private val getCryptoCurrencyActionsUseCaseV2: GetCryptoCurrencyActionsUseCaseV2,
) : BasicSingleWalletSubscriber() {
@OptIn(ExperimentalCoroutinesApi::class)
override fun create(coroutineScope: CoroutineScope): Flow<TokenActionsState> {
return channelFlow {
getSingleCryptoCurrencyStatusUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
getCryptoCurrencyActionsUseCase(userWallet = userWallet, status = status)
?.let { send(it) }
return getPrimaryCurrencyStatusFlow()
.flatMapLatest {
getCryptoCurrencyActionsUseCaseV2(accountId = accountId, currency = it.currency)
}
}
.onEach { actions ->
updateContent(
tokenActionsState = actions,
portfolioId = PortfolioId(userWallet.walletId),
)
.onEach {
updateContent(tokenActionsState = it, portfolioId = PortfolioId(userWallet.walletId))
}
}
private fun updateContent(tokenActionsState: TokenActionsState, portfolioId: PortfolioId) {
stateHolder.update(
stateController.update(
SetCryptoCurrencyActionsTransformer(
tokenActionsState = tokenActionsState,
userWallet = userWallet,
@ -48,9 +47,8 @@ internal class SingleWalletButtonsSubscriber(
)
}
private suspend fun getCryptoCurrencyActionsUseCase(userWallet: UserWallet, status: CryptoCurrencyStatus) =
this.getCryptoCurrencyActionsUseCase(userWallet = userWallet, cryptoCurrencyStatus = status)
.conflate()
.distinctUntilChanged()
.firstOrNull()
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): SingleWalletButtonsSubscriber
}
}

View file

@ -1,46 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetCryptoCurrencyActionsTransformer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.onEach
internal class SingleWalletButtonsSubscriberV2(
override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val getCryptoCurrencyActionsUseCaseV2: GetCryptoCurrencyActionsUseCaseV2,
) : BasicSingleWalletSubscriber() {
@OptIn(ExperimentalCoroutinesApi::class)
override fun create(coroutineScope: CoroutineScope): Flow<TokenActionsState> {
return getPrimaryCurrencyStatusFlow()
.flatMapLatest {
getCryptoCurrencyActionsUseCaseV2(accountId = accountId, currency = it.currency)
}
.onEach {
updateContent(tokenActionsState = it, portfolioId = PortfolioId(userWallet.walletId))
}
}
private fun updateContent(tokenActionsState: TokenActionsState, portfolioId: PortfolioId) {
stateController.update(
SetCryptoCurrencyActionsTransformer(
tokenActionsState = tokenActionsState,
userWallet = userWallet,
clickIntents = clickIntents,
portfolioId = portfolioId,
),
)
}
}

View file

@ -1,93 +1,92 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
import com.tangem.domain.onramp.model.cache.OnrampTransaction
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetExpressStatusesTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import timber.log.Timber
@Suppress("LongParameterList")
@Deprecated("Use SingleWalletExpressStatusesSubscriberV2 instead")
internal class SingleWalletExpressStatusesSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
internal class SingleWalletExpressStatusesSubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val analyticsEventHandler: AnalyticsEventHandler,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
): Flow<Pair<Either<CurrencyStatusError, CryptoCurrencyStatus>, AppCurrency>> {
return combine(
flow = getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWalletId = userWallet.walletId)
.conflate()
.distinctUntilChanged(),
flow2 = getSelectedAppCurrencyUseCase()
.conflate()
.distinctUntilChanged()
.map { maybeAppCurrency -> maybeAppCurrency.getOrElse { AppCurrency.Default } },
transform = { maybeCurrencyStatus, appCurrency -> maybeCurrencyStatus to appCurrency },
).onEach { maybeCurrencyStatusAndAppCurrency ->
val status = maybeCurrencyStatusAndAppCurrency.first.getOrElse {
Timber.e("Unable to get primary currency status: $it")
return@onEach
}
) : BasicSingleWalletSubscriber() {
@OptIn(ExperimentalCoroutinesApi::class)
override fun create(coroutineScope: CoroutineScope): Flow<*> {
val getOnrampTransactionsFlow = getPrimaryCurrencyStatusFlow().flatMapLatest { currencyStatus ->
getOnrampTransactionsUseCase(
userWalletId = userWallet.walletId,
cryptoCurrencyId = status.currency.id,
).onEach { maybeTransaction ->
cryptoCurrencyId = currencyStatus.currency.id,
)
.map { currencyStatus to it }
}
return combine(
flow = getOnrampTransactionsFlow,
flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
transform = ::toTriple,
)
.onEach { (status, maybeTransaction, appCurrency) ->
maybeTransaction.fold(
ifRight = { onrampTxs ->
onrampTxs.clearHiddenTerminal()
stateHolder.update(
stateController.update(
SetExpressStatusesTransformer(
userWalletId = userWallet.walletId,
onrampTxs = onrampTxs,
clickIntents = clickIntents,
cryptoCurrencyStatus = status,
appCurrency = maybeCurrencyStatusAndAppCurrency.second,
appCurrency = appCurrency,
analyticsEventHandler = analyticsEventHandler,
),
)
},
ifLeft = {
stateHolder.update(
stateController.update(
SetExpressStatusesTransformer(
userWalletId = userWallet.walletId,
onrampTxs = listOf(),
onrampTxs = emptyList(),
clickIntents = clickIntents,
cryptoCurrencyStatus = status,
appCurrency = maybeCurrencyStatusAndAppCurrency.second,
appCurrency = appCurrency,
analyticsEventHandler = analyticsEventHandler,
),
)
},
)
}
.launchIn(coroutineScope)
}
}
private fun <A, B, C> toTriple(firstPair: Pair<A, B>, second: C): Triple<A, B, C> {
return Triple(firstPair.first, firstPair.second, second)
}
private suspend fun List<OnrampTransaction>.clearHiddenTerminal() {
this.filter { it.status.isHidden && it.status.isTerminal }
this
.filter { it.status.isHidden && it.status.isTerminal }
.forEach { onrampRemoveTransactionUseCase(txId = it.txId) }
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): SingleWalletExpressStatusesSubscriber
}
}

View file

@ -1,84 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
import com.tangem.domain.onramp.model.cache.OnrampTransaction
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetExpressStatusesTransformer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
@Suppress("LongParameterList")
internal class SingleWalletExpressStatusesSubscriberV2(
override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val analyticsEventHandler: AnalyticsEventHandler,
) : BasicSingleWalletSubscriber() {
@OptIn(ExperimentalCoroutinesApi::class)
override fun create(coroutineScope: CoroutineScope): Flow<*> {
val getOnrampTransactionsFlow = getPrimaryCurrencyStatusFlow().flatMapLatest { currencyStatus ->
getOnrampTransactionsUseCase(
userWalletId = userWallet.walletId,
cryptoCurrencyId = currencyStatus.currency.id,
)
.map { currencyStatus to it }
}
return combine(
flow = getOnrampTransactionsFlow,
flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
transform = ::toTriple,
)
.onEach { (status, maybeTransaction, appCurrency) ->
maybeTransaction.fold(
ifRight = { onrampTxs ->
onrampTxs.clearHiddenTerminal()
stateController.update(
SetExpressStatusesTransformer(
userWalletId = userWallet.walletId,
onrampTxs = onrampTxs,
clickIntents = clickIntents,
cryptoCurrencyStatus = status,
appCurrency = appCurrency,
analyticsEventHandler = analyticsEventHandler,
),
)
},
ifLeft = {
stateController.update(
SetExpressStatusesTransformer(
userWalletId = userWallet.walletId,
onrampTxs = listOf(),
clickIntents = clickIntents,
cryptoCurrencyStatus = status,
appCurrency = appCurrency,
analyticsEventHandler = analyticsEventHandler,
),
)
},
)
}
}
private fun <A, B, C> toTriple(firstPair: Pair<A, B>, second: C): Triple<A, B, C> {
return Triple(firstPair.first, firstPair.second, second)
}
private suspend fun List<OnrampTransaction>.clearHiddenTerminal() {
this
.filter { it.status.isHidden && it.status.isTerminal }
.forEach { onrampRemoveTransactionUseCase(txId = it.txId) }
}
}

View file

@ -7,6 +7,9 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarni
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 dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
@ -18,9 +21,9 @@ import kotlinx.coroutines.flow.onEach
/**
[REDACTED_AUTHOR]
*/
internal class SingleWalletNotificationsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
internal class SingleWalletNotificationsSubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateController: WalletStateController,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val clickIntents: WalletClickIntents,
@ -31,10 +34,15 @@ internal class SingleWalletNotificationsSubscriber(
.conflate()
.distinctUntilChanged()
.onEach { warnings ->
val displayedState = stateHolder.getWalletState(userWallet.walletId)
val displayedState = stateController.getWalletState(userWallet.walletId)
stateHolder.update(SetWarningsTransformer(userWallet.walletId, warnings, persistentListOf()))
stateController.update(SetWarningsTransformer(userWallet.walletId, warnings, persistentListOf()))
walletWarningsAnalyticsSender.send(displayedState, warnings)
}
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): SingleWalletNotificationsSubscriber
}
}

View file

@ -1,51 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import kotlinx.coroutines.CoroutineScope
@Deprecated("Use SingleWalletWithTokenSubscriber instead")
@Suppress("LongParameterList")
internal class SingleWalletWithTokenListSubscriber(
private val userWallet: UserWallet.Cold,
private val tokenListStore: MultiWalletTokenListStore,
stateHolder: WalletStateController,
clickIntents: WalletClickIntents,
tokenListAnalyticsSender: TokenListAnalyticsSender,
walletWithFundsChecker: WalletWithFundsChecker,
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase: StakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
) : BasicTokenListSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingAvailabilityListUseCase = stakingAvailabilityListUseCase,
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
) {
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
tokenListStore.addIfNot(userWallet.walletId, coroutineScope)
return tokenListStore.getOrThrow(userWallet.walletId)
}
override suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>) = Unit
}

View file

@ -4,47 +4,46 @@ import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map
import arrow.core.Either
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TxHistoryItemStateConverter
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
typealias MaybeTxHistoryCount = Either<TxHistoryStateError, Int>
typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxInfo>>>
@Suppress("LongParameterList")
@Deprecated("Use TxHistorySubscriberV2 instead")
internal class TxHistorySubscriber(
private val userWallet: UserWallet.Cold,
private val isRefresh: Boolean,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
internal class TxHistorySubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet.Cold,
@Assisted private val isRefresh: Boolean,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
) : WalletSubscriber() {
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
) : BasicSingleWalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<PagingData<TxInfo>> {
return flow {
getSingleCryptoCurrencyStatusUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
getPrimaryCurrencyStatusFlow().collectLatest { status ->
val maybeTxHistoryItemCount = txHistoryItemsCountUseCase(
userWalletId = userWallet.walletId,
currency = status.currency,
@ -52,29 +51,32 @@ internal class TxHistorySubscriber(
setLoadingTxHistoryState(maybeTxHistoryItemCount, status)
maybeTxHistoryItemCount.onRight {
maybeTxHistoryItemCount.onRight { _ ->
val maybeTxHistoryItems = txHistoryItemsUseCase(
userWalletId = userWallet.walletId,
currency = status.currency,
refresh = isRefresh,
).map { it.cachedIn(coroutineScope) }
setLoadedTxHistoryState(maybeTxHistoryItems, status.currency)
setLoadedTxHistoryState(maybeTxHistoryItems, currency = status.currency)
}
}
}
}
private fun setLoadingTxHistoryState(maybeTxHistoryItemCount: MaybeTxHistoryCount, status: CryptoCurrencyStatus) {
stateHolder.update(
private fun setLoadingTxHistoryState(
maybeTxHistoryItemCount: Either<TxHistoryStateError, Int>,
status: CryptoCurrencyStatus,
) {
stateController.update(
maybeTxHistoryItemCount.fold(
ifLeft = { error ->
SetTxHistoryCountErrorTransformer(
userWallet = userWallet,
error = error,
pendingTransactions = status.value.pendingTransactions,
currency = status.currency,
clickIntents = clickIntents,
currency = status.currency,
)
},
ifRight = { txCount ->
@ -88,23 +90,26 @@ internal class TxHistorySubscriber(
)
}
private fun setLoadedTxHistoryState(maybeTxHistoryItems: MaybeTxHistoryItems, currency: CryptoCurrency) {
stateHolder.update(
private fun setLoadedTxHistoryState(
maybeTxHistoryItems: Either<TxHistoryListError, Flow<PagingData<TxInfo>>>,
currency: CryptoCurrency,
) {
stateController.update(
maybeTxHistoryItems.fold(
ifLeft = {
ifLeft = { error ->
SetTxHistoryItemsErrorTransformer(
userWalletId = userWallet.walletId,
error = it,
error = error,
clickIntents = clickIntents,
)
},
ifRight = { itemsFlow ->
val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
val itemConverter = TxHistoryItemStateConverter(
currency = currency,
symbol = blockchain.currency,
decimals = blockchain.decimals(),
clickIntents = clickIntents,
currency = currency,
)
SetTxHistoryItemsTransformer(
@ -118,4 +123,9 @@ internal class TxHistorySubscriber(
),
)
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): TxHistorySubscriber
}
}

View file

@ -1,114 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TxHistoryItemStateConverter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
@Suppress("LongParameterList")
internal class TxHistorySubscriberV2(
override val userWallet: UserWallet.Cold,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val isRefresh: Boolean,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
) : BasicSingleWalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<PagingData<TxInfo>> {
return flow {
getPrimaryCurrencyStatusFlow().collectLatest { status ->
val maybeTxHistoryItemCount = txHistoryItemsCountUseCase(
userWalletId = userWallet.walletId,
currency = status.currency,
)
setLoadingTxHistoryState(maybeTxHistoryItemCount, status)
maybeTxHistoryItemCount.onRight {
val maybeTxHistoryItems = txHistoryItemsUseCase(
userWalletId = userWallet.walletId,
currency = status.currency,
refresh = isRefresh,
).map { it.cachedIn(coroutineScope) }
setLoadedTxHistoryState(maybeTxHistoryItems, currency = status.currency)
}
}
}
}
private fun setLoadingTxHistoryState(maybeTxHistoryItemCount: MaybeTxHistoryCount, status: CryptoCurrencyStatus) {
stateController.update(
maybeTxHistoryItemCount.fold(
ifLeft = { error ->
SetTxHistoryCountErrorTransformer(
userWallet = userWallet,
error = error,
pendingTransactions = status.value.pendingTransactions,
clickIntents = clickIntents,
currency = status.currency,
)
},
ifRight = { txCount ->
SetTxHistoryCountTransformer(
userWalletId = userWallet.walletId,
transactionsCount = txCount,
clickIntents = clickIntents,
)
},
),
)
}
private fun setLoadedTxHistoryState(maybeTxHistoryItems: MaybeTxHistoryItems, currency: CryptoCurrency) {
stateController.update(
maybeTxHistoryItems.fold(
ifLeft = {
SetTxHistoryItemsErrorTransformer(
userWalletId = userWallet.walletId,
error = it,
clickIntents = clickIntents,
)
},
ifRight = { itemsFlow ->
val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
val itemConverter = TxHistoryItemStateConverter(
currency = currency,
symbol = blockchain.currency,
decimals = blockchain.decimals(),
clickIntents = clickIntents,
)
SetTxHistoryItemsTransformer(
userWallet = userWallet,
flow = itemsFlow.map { items ->
items.map(itemConverter::convert)
},
clickIntents = clickIntents,
)
},
),
)
}
}

View file

@ -1,58 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.RemoveNFTCollectionsTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetNFTCollectionsTransformer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
@Deprecated("Use WalletNFTListSubscriberV2 instead")
internal class WalletNFTListSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val walletsRepository: WalletsRepository,
private val currenciesRepository: CurrenciesRepository,
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
private val clickIntents: WalletClickIntents,
) : WalletSubscriber() {
@OptIn(ExperimentalCoroutinesApi::class)
override fun create(coroutineScope: CoroutineScope): Flow<*> = combine(
walletsRepository.nftEnabledStatus(userWallet.walletId),
currenciesRepository.getWalletCurrenciesUpdates(userWallet.walletId),
) { nftEnabled, currencies -> nftEnabled to currencies }
.distinctUntilChanged()
.flatMapLatest { (nftEnabled, currencies) ->
// if NFT is enabled for this wallet and there are currencies,
// then start observing changes from store and apply transformer if need
if (nftEnabled && currencies.isNotEmpty()) {
getNFTCollectionsUseCase(userWallet.walletId)
.shareIn(
scope = coroutineScope,
started = SharingStarted.WhileSubscribed(),
replay = 1,
)
.onEach {
stateHolder.update(
SetNFTCollectionsTransformer(
userWalletId = userWallet.walletId,
nftCollections = it,
onItemClick = { clickIntents.onNFTClick(userWallet) },
),
)
}
} else {
// otherwise, hide NFT from wallet
stateHolder.update(
RemoveNFTCollectionsTransformer(userWallet.walletId),
)
emptyFlow()
}
}
}

View file

@ -6,7 +6,6 @@ import com.tangem.common.ui.userwallet.state.UserWalletItemUM
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.usecase.GetWalletTotalBalanceUseCaseV2
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError
@ -20,7 +19,6 @@ import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.feature.wallet.impl.R
@ -39,8 +37,6 @@ import kotlinx.coroutines.flow.*
@Suppress("LongParameterList")
internal class DefaultUserWalletsFetcher @AssistedInject constructor(
getWalletsUseCase: GetWalletsUseCase,
private val accountsFeatureToggles: AccountsFeatureToggles,
private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase,
private val getWalletTotalBalanceUseCaseV2: GetWalletTotalBalanceUseCaseV2,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
@ -103,11 +99,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
// We should not load balances in auth mode
flowOf(Lce.Loading(walletIds.associateWith { TotalFiatBalance.Loading }))
} else {
if (accountsFeatureToggles.isFeatureEnabled) {
getWalletTotalBalanceUseCaseV2(userWalletIds = walletIds)
} else {
getWalletTotalBalanceUseCase(walletIds).distinctUntilChanged()
}
getWalletTotalBalanceUseCaseV2(userWalletIds = walletIds)
}
}