diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt index c55ac9cb0c..947cf63839 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusFetcher.kt @@ -46,7 +46,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor( override suspend fun invoke(params: PaymentAccountStatusFetcher.Params): Either = Either.catchOn(dispatchers.default) { val account = Account.Payment(userWalletId = params.userWalletId) - logger.i("fetch: ${params.userWalletId.stringValue}") + logger.i("invoke() start: ${params.userWalletId.stringValue}") if (deviceSecurity.isSecurityExposed()) { logger.i("fetch security info: rooted: ${deviceSecurity.isRooted}") @@ -80,11 +80,14 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor( userWalletId = params.userWalletId, status = AccountStatus.Payment(account = account, value = status), ) - }.onLeft { + }.onLeft { throwable -> + logger.e("invoke() ${params.userWalletId} threw, falling back to ONLY_CACHE", throwable) paymentAccountStatusesStore.updateStatusSource( userWalletId = params.userWalletId, source = StatusSource.ONLY_CACHE, ) + }.also { result -> + logger.i("invoke() end ${params.userWalletId}: isRight=${result.isRight()}") } private suspend fun proceedHasTangemPayResult( @@ -101,7 +104,12 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor( private suspend fun fetchTangemPayAccountStatus(account: Account.Payment): PaymentAccountStatusValue { val prevResult = paymentAccountStatusesStore.getSyncOrNull(account.userWalletId) + logger.i( + "fetchTangemPayAccountStatus ${account.userWalletId}: " + + "prevResultType=${prevResult?.value?.let { it::class.simpleName } ?: "null"}", + ) if (prevResult == null || prevResult.value is PaymentAccountStatusValue.Error.Unavailable) { + logger.i("fetchTangemPayAccountStatus ${account.userWalletId}: writing Loading placeholder to store") paymentAccountStatusesStore.store( userWalletId = account.userWalletId, status = AccountStatus.Payment(account = account, value = PaymentAccountStatusValue.Loading), @@ -112,10 +120,13 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor( } private suspend fun proceedWithOrderId(account: Account.Payment): PaymentAccountStatusValue { - return if (!onboardingRepository.isTangemPayInitialDataProduced(account.userWalletId)) { + val isInitial = onboardingRepository.isTangemPayInitialDataProduced(account.userWalletId) + logger.i("proceedWithOrderId ${account.userWalletId}: isTangemPayInitialDataProduced=$isInitial") + return if (!isInitial) { PaymentAccountStatusValue.Error.NotSynced } else { val orderId = onboardingRepository.getOrderId(account.userWalletId) + logger.i("proceedWithOrderId ${account.userWalletId}: orderIdPresent=${orderId != null}") if (orderId != null) { proceedWithOrderId(account = account, orderId = orderId) } else { diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusProducer.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusProducer.kt index c2c53ae7cd..153f0d327d 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusProducer.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/flow/DefaultPaymentAccountStatusProducer.kt @@ -9,12 +9,17 @@ import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.pay.flow.PaymentAccountStatusProducer import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.logging.TangemLogger import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEmpty +import kotlinx.coroutines.flow.onStart + +private const val TAG = "PaymentAccountStatusProducer" internal class DefaultPaymentAccountStatusProducer @AssistedInject constructor( @Assisted private val params: PaymentAccountStatusProducer.Params, @@ -24,13 +29,20 @@ internal class DefaultPaymentAccountStatusProducer @AssistedInject constructor( ) : PaymentAccountStatusProducer { private val account = Account.Payment(userWalletId = params.userWalletId) + private val logger = TangemLogger.withTag(TAG) override val fallback: Option get() = AccountStatus.Payment(account = account, value = PaymentAccountStatusValue.Error.Unavailable).some() override fun produce(): Flow { + logger.i("[${params.userWalletId}] produce() called") return paymentAccountStatusesStore.get(userWalletId = params.userWalletId) - .onEmpty { emit(value = AccountStatus.Payment(account, PaymentAccountStatusValue.NotCreated)) } + .onStart { logger.i("[${params.userWalletId}] flow subscribed to store") } + .onEach { logger.i("[${params.userWalletId}] flow emits statusType=${it.value::class.simpleName}") } + .onEmpty { + logger.i("[${params.userWalletId}] onEmpty triggered: emitting NotCreated fallback") + emit(value = AccountStatus.Payment(account, PaymentAccountStatusValue.NotCreated)) + } .flowOn(dispatchers.default) } diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt index ec8a48d880..cb96162ce4 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/store/PaymentAccountStatusesStore.kt @@ -15,11 +15,15 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch internal typealias WalletIdWithPaymentStatus = Map internal typealias WalletIdWithPaymentStatusDM = Map +private const val TAG = "PaymentAccountStatusesStore" + /** * Store for payment account statuses with dual storage (runtime + persistence). * @@ -32,10 +36,18 @@ internal class PaymentAccountStatusesStore( scope: AppCoroutineScope, ) { + private val logger = TangemLogger.withTag(TAG) + init { scope.launch { + logger.i("init: loading cached payment statuses from persistence") try { - val cachedStatuses = persistenceDataStore.data.firstOrNull() ?: return@launch + val cachedStatuses = persistenceDataStore.data.firstOrNull() + if (cachedStatuses == null) { + logger.i("init: persistence empty (firstOrNull == null), runtimeStore stays empty") + return@launch + } + logger.i("init: loaded ${cachedStatuses.size} cached entries; populating runtimeStore") runtimeStore.store( value = cachedStatuses.mapValues { (rawUserWalletId, statusDM) -> val account = Account.Payment(userWalletId = UserWalletId(rawUserWalletId)) @@ -43,18 +55,32 @@ internal class PaymentAccountStatusesStore( AccountStatus.Payment(account = account, value = statusValue) }, ) + logger.i("init: runtimeStore populated with ${cachedStatuses.size} entries") } catch (e: Exception) { - TangemLogger.e("Error while loading cached payment account statuses", e) + logger.e("Error while loading cached payment account statuses", e) } } } fun get(userWalletId: UserWalletId): Flow { - return runtimeStore.get().mapNotNull { it[userWalletId.stringValue] } + return runtimeStore.get() + .onStart { logger.i("get($userWalletId): subscribed to runtimeStore") } + .onEach { map -> + logger.i( + "get($userWalletId): runtimeStore emitted map size=${map.size}, " + + "hasEntry=${map.containsKey(userWalletId.stringValue)}", + ) + } + .mapNotNull { it[userWalletId.stringValue] } + .onEach { status -> + logger.i("get($userWalletId): emitting statusType=${status.value::class.simpleName}") + } } suspend fun getSyncOrNull(userWalletId: UserWalletId): AccountStatus.Payment? { - return runtimeStore.getSyncOrNull()?.get(userWalletId.stringValue) + val result = runtimeStore.getSyncOrNull()?.get(userWalletId.stringValue) + logger.i("getSyncOrNull($userWalletId) valueType=${result?.value?.let { it::class.simpleName } ?: "null"}") + return result } suspend fun updateStatusSource(userWalletId: UserWalletId, source: StatusSource) { @@ -68,6 +94,7 @@ internal class PaymentAccountStatusesStore( } suspend fun store(userWalletId: UserWalletId, status: AccountStatus.Payment) { + logger.i("store($userWalletId): valueType=${status.value::class.simpleName}") coroutineScope { launch { storeInRuntime(userWalletId = userWalletId, status = status) } launch { storeInPersistence(userWalletId = userWalletId, status = status.value) } diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/producer/DefaultSingleAccountStatusListProducer.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/producer/DefaultSingleAccountStatusListProducer.kt index a2bf732b26..1da0c170d6 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/producer/DefaultSingleAccountStatusListProducer.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/producer/DefaultSingleAccountStatusListProducer.kt @@ -46,6 +46,7 @@ import com.tangem.domain.tokens.operations.TokenListFactory import com.tangem.domain.tokens.operations.TotalFiatBalanceCalculator import com.tangem.hot.sdk.model.HotWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.logging.TangemLogger import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -73,7 +74,7 @@ import java.math.BigDecimal [REDACTED_AUTHOR] */ // TODO: Move to :data:account:status [REDACTED_JIRA] -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LargeClass") @OptIn(ExperimentalCoroutinesApi::class) internal class DefaultSingleAccountStatusListProducer @AssistedInject constructor( @Assisted private val params: SingleAccountStatusListProducer.Params, @@ -90,17 +91,29 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo private val analyticsExceptionHandler: AnalyticsExceptionHandler, ) : SingleAccountStatusListProducer { + private val logger = TangemLogger.withTag(TAG) + override val fallback: Option = none() override fun produce(): Flow { + logger.i("produce() called for ${params.userWalletId}") return flattenFlow() + .onEach { list -> + logger.i( + "produce()[${params.userWalletId}] emit: accounts=${list.accountStatuses.size}, " + + "currencies=${list.flattenCurrencies().size}, " + + "totalFiatType=${list.totalFiatBalance::class.simpleName}", + ) + } .flowOn(dispatchers.default) } @Suppress("LongMethod") private fun flattenFlow(): Flow = channelFlow { val walletId = params.userWalletId + logger.i("flattenFlow[$walletId]: start") val userWallet = userWalletsListRepository.getSyncStrict(id = params.userWalletId) + logger.i("flattenFlow[$walletId]: userWallet resolved (type=${userWallet::class.simpleName})") val flattenCurrency: MutableSharedFlow> = MutableSharedFlow( replay = 1, @@ -108,11 +121,20 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo ) val accountListFlow: StateFlow = singleAccountListSupplier(walletId) - .onEach { accountList -> flattenCurrency.tryEmit(accountList.flattenMapCurrencies()) } + .onEach { accountList -> + logger.i( + "flattenFlow[$walletId]: accountList emitted accounts=${accountList.accounts.size}, " + + "currencies=${accountList.flattenMapCurrencies().size}", + ) + flattenCurrency.tryEmit(accountList.flattenMapCurrencies()) + } .stateIn(this) val hasCachedNetworks = networksRepository.hasCachedStatuses(walletId) + logger.i("flattenFlow[$walletId]: hasCachedNetworks=$hasCachedNetworks") if (!hasCachedNetworks) { + val initialAccounts = accountListFlow.value.accounts.size + logger.i("flattenFlow[$walletId]: sending Loading placeholder (accounts=$initialAccounts)") send(createLoadingAccountStatusList(accountListFlow.value)) } @@ -121,11 +143,19 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo flattenCurrency = flattenCurrency, ) - if (userWallet.isPaymentAccountSupported()) { + val isPaymentSupported = userWallet.isPaymentAccountSupported() + logger.i("flattenFlow[$walletId]: isPaymentAccountSupported=$isPaymentSupported") + if (isPaymentSupported) { combineWithPaymentAccount( accountListFlow = accountListFlow, cryptoCurrencyStatusFlow = cryptoCurrencyStatusFlow, - paymentAccountStatusFlow = paymentAccountStatusSupplier.invoke(userWalletId = params.userWalletId), + paymentAccountStatusFlow = paymentAccountStatusSupplier.invoke(userWalletId = params.userWalletId) + .onEach { paymentStatus -> + logger.i( + "flattenFlow[$walletId]: paymentAccountStatus emitted " + + "valueType=${paymentStatus.value::class.simpleName}", + ) + }, ) } else { combineWithoutPaymentAccount( @@ -146,6 +176,12 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo flow2 = cryptoCurrencyStatusFlow, flow3 = paymentAccountStatusFlow, transform = { accountList, currencyStatusMap, paymentAccountStatus -> + logger.i( + "combineWithPayment[${params.userWalletId}] transform: " + + "accounts=${accountList.accounts.size}, " + + "currencyStatusMap=${currencyStatusMap.size}, " + + "paymentType=${paymentAccountStatus.value::class.simpleName}", + ) val accountStatuses = accountList.accounts.map { account -> when (account) { is Account.Payment -> paymentAccountStatus @@ -192,6 +228,11 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo flow = accountListFlow, flow2 = cryptoCurrencyStatusFlow, transform = { accountList, currencyStatusMap -> + logger.i( + "combineWithoutPayment[${params.userWalletId}] transform: " + + "accounts=${accountList.accounts.size}, " + + "currencyStatusMap=${currencyStatusMap.size}", + ) val accountStatuses = accountList.accounts .filterIsInstance() .map { account -> @@ -242,14 +283,18 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo ): Flow> { val walletId = userWallet.walletId val networkStatusFlow: SharedFlow> = networkStatusFlow(walletId) + .onEach { logger.i("flattenCurrencyStatusFlow[$walletId]: networkStatuses emitted size=${it.size}") } .shareIn(this, started = SharingStarted.Eagerly, replay = 1) val stakingBalanceFlow: SharedFlow>> = stakingFlow(userWallet) + .onEach { logger.i("flattenCurrencyStatusFlow[$walletId]: stakingBalances emitted stakingIds=${it.size}") } .shareIn(this, started = SharingStarted.Eagerly, replay = 1) val quoteStatusFlow: SharedFlow> = quoteStatusFlow() + .onEach { logger.i("flattenCurrencyStatusFlow[$walletId]: quoteStatuses emitted size=${it.size}") } .shareIn(this, started = SharingStarted.Eagerly, replay = 1) return flattenCurrency .distinctUntilChanged() + .onEach { logger.i("flattenCurrencyStatusFlow[$walletId]: flattenCurrency emitted size=${it.size}") } .flatMapLatest { a -> combine( flow = networkStatusFlow, @@ -264,6 +309,15 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo ) } .distinctUntilChanged() + .onEach { box -> + logger.i( + "flattenCurrencyStatusFlow[$walletId]: box emitted " + + "currencies=${box.flattenCurrencyMap.size}, " + + "networks=${box.networkStatusMap.size}, " + + "stakings=${box.stakingBalanceMap.size}, " + + "quotes=${box.quoteStatusMap.size}", + ) + } .map { box -> val flattenCurrencyMap: Map = box.flattenCurrencyMap val networkStatusMap: Map = box.networkStatusMap @@ -402,4 +456,8 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo interface Factory : SingleAccountStatusListProducer.Factory { override fun create(params: SingleAccountStatusListProducer.Params): DefaultSingleAccountStatusListProducer } + + private companion object { + const val TAG = "SingleAccountStatusListProducer" + } } \ No newline at end of file diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt index 6d858dc872..a335565ea1 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/IsAccountsModeEnabledUseCase.kt @@ -6,6 +6,7 @@ import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.pay.flow.PaymentAccountStatusProducer import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier +import com.tangem.utils.logging.TangemLogger import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.* @@ -27,27 +28,51 @@ class IsAccountsModeEnabledUseCase( @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke(): Flow { + TangemLogger.i("$TAG: invoke() started") + val cryptoMode = multiAccountListSupplier.invoke() - .map { lists -> lists.any { it.hasMultipleCryptoPortfolios() } } + .onEach { lists -> + TangemLogger.i("$TAG: multiAccountListSupplier emitted ${lists.size} lists (cryptoMode branch)") + } + .map { lists -> + val isCryptoMode = lists.any { it.hasMultipleCryptoPortfolios() } + TangemLogger.i("$TAG: cryptoMode=$isCryptoMode") + isCryptoMode + } val paymentMode = multiAccountListSupplier.invoke().flatMapLatest { lists -> val walletIdsWithPayment = lists.mapNotNull { list -> if (list.accounts.any { it is Account.Payment }) list.userWalletId else null } + TangemLogger.i("$TAG: walletIdsWithPayment=${walletIdsWithPayment.size}") if (walletIdsWithPayment.isEmpty()) { flowOf(false) } else { val flows = walletIdsWithPayment.map { walletId -> paymentAccountStatusSupplier.invoke(walletId) + .onEach { status -> + TangemLogger.i("$TAG: paymentStatus for $walletId = ${status.value::class.simpleName}") + } .map { it.value.isActivePayment() } - .onStart { emit(false) } + .onStart { + TangemLogger.i("$TAG: paymentAccountStatusSupplier onStart for $walletId") + emit(false) + } + } + combine(flows) { results -> + val isPaymentMode = results.any { it } + TangemLogger.i("$TAG: paymentMode combine result=$isPaymentMode (${results.toList()})") + isPaymentMode } - combine(flows) { results -> results.any { it } } } } - return combine(cryptoMode, paymentMode) { crypto, payment -> crypto || payment } + return combine(cryptoMode, paymentMode) { crypto, payment -> + val isEnabled = crypto || payment + TangemLogger.i("$TAG: final combine crypto=$crypto, payment=$payment, result=$isEnabled") + isEnabled + } .distinctUntilChanged() } @@ -90,5 +115,6 @@ class IsAccountsModeEnabledUseCase( private companion object { const val PAYMENT_STATUS_SYNC_TIMEOUT_MS = 1_000L + const val TAG = "IsAccountsModeEnabledUseCase" } } \ No newline at end of file diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt index 2e62f7190e..370eb2d543 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt @@ -97,13 +97,29 @@ class TangemPayMainScreenCustomerInfoUseCase( operator fun invoke( userWalletId: UserWalletId, ): Flow> { + logger.i("invoke($userWalletId): flow requested") return state.mapNotNull { map -> map[userWalletId] } + .onStart { logger.i("invoke($userWalletId): flow subscribed (current state size=${state.value.size})") } + .onEach { value -> + logger.i( + "invoke($userWalletId): emit ${value.fold( + { "Left(${it.javaClass.simpleName})" }, + { "Right(${it.javaClass.simpleName})" }, + )}", + ) + } } private fun updateState( userWalletId: UserWalletId, either: Either, ) { + logger.i( + "updateState($userWalletId) -> ${either.fold( + { "Left(${it.javaClass.simpleName})" }, + { "Right(${it.javaClass.simpleName})" }, + )}", + ) state.update { currentMap -> currentMap.toMutableMap().apply { this[userWalletId] = either } } @@ -112,10 +128,14 @@ class TangemPayMainScreenCustomerInfoUseCase( private suspend fun proceedWithPaeraCustomerResult( userWalletId: UserWalletId, ): Either { - if (!onboardingRepository.isTangemPayInitialDataProduced(userWalletId)) { + logger.i("proceedWithPaeraCustomerResult($userWalletId) entry") + val isInitial = onboardingRepository.isTangemPayInitialDataProduced(userWalletId) + logger.i("proceedWithPaeraCustomerResult($userWalletId): isTangemPayInitialDataProduced=$isInitial") + if (!isInitial) { return TangemPayCustomerInfoError.RefreshNeededError.left() } val orderId = onboardingRepository.getOrderId(userWalletId) + logger.i("proceedWithPaeraCustomerResult($userWalletId): orderId=$orderId") return if (orderId != null) { proceedWithOrderId(userWalletId = userWalletId, orderId = orderId) } else { @@ -146,18 +166,25 @@ class TangemPayMainScreenCustomerInfoUseCase( userWalletId: UserWalletId, orderId: String, ): Either { + logger.i("proceedWithOrderId($userWalletId, orderId=$orderId) entry") return customerOrderRepository.getOrderData(userWalletId, orderId = orderId) .fold( ifLeft = { error -> + logger.e("proceedWithOrderId($userWalletId): getOrderData failed: ${error.javaClass.simpleName}") error.mapErrorForCustomer().left() }, ifRight = { orderData -> + logger.i("proceedWithOrderId($userWalletId): orderData.status=${orderData.status}") if (orderData.status in setOf(OrderStatus.COMPLETED, OrderStatus.UNKNOWN)) { onboardingRepository.clearOrderId(userWalletId) } onboardingRepository.getCustomerInfo(userWalletId = userWalletId) - .mapLeft { it.mapErrorForCustomer() } + .mapLeft { error -> + logger.e("proceedWithOrderId($userWalletId): getCustomerInfo failed: $error") + error.mapErrorForCustomer() + } .map { customerInfo -> + logger.i("proceedWithOrderId($userWalletId): got customerInfo") MainScreenCustomerInfo(info = customerInfo, orderStatus = orderData.status) } }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/AccountListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/AccountListSubscriber.kt index 2d7ba38899..4eff9de5fa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/AccountListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/AccountListSubscriber.kt @@ -13,6 +13,7 @@ import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.account.AccountDependencies import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.utils.coroutines.combine7 +import com.tangem.utils.logging.TangemLogger import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -21,6 +22,8 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart import java.math.BigDecimal /** @@ -41,38 +44,69 @@ internal class AccountListSubscriber @AssistedInject constructor( private val designFeatureToggles: DesignFeatureToggles, ) : BasicAccountListSubscriber() { - override fun create(coroutineScope: CoroutineScope): Flow<*> = combine7( - flow1 = getAccountStatusListFlow(), - flow2 = getAppCurrencyFlow(), - flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet), - flow4 = accountDependencies.isAccountsModeEnabledUseCase(), - flow5 = yieldSupplyApyFlow(), - flow6 = yieldSupplyGetShouldShowMainPromoFlow(), - flow7 = stakingAvailabilityFlow(), - ) { - accountList, appCurrency, expandedAccounts, isAccountMode, - yieldSupplyApyMap, shouldShowMainPromo, stakingAvailabilityMap, - -> - if (designFeatureToggles.isRedesignEnabled) { - updateState2( - accountList = accountList, - appCurrency = appCurrency, - expandedAccounts = expandedAccounts, - isAccountMode = isAccountMode, - yieldSupplyApyMap = yieldSupplyApyMap, - stakingAvailabilityMap = stakingAvailabilityMap, - shouldShowMainPromo = shouldShowMainPromo, - ) - } else { - updateState( - accountList = accountList, - appCurrency = appCurrency, - expandedAccounts = expandedAccounts, - isAccountMode = isAccountMode, - yieldSupplyApyMap = yieldSupplyApyMap, - stakingAvailabilityMap = stakingAvailabilityMap, - shouldShowMainPromo = shouldShowMainPromo, + override fun create(coroutineScope: CoroutineScope): Flow<*> { + val walletId = userWallet.walletId.stringValue + TangemLogger.i("$TAG[$walletId]: create() called, building combine7") + return combine7( + flow1 = getAccountStatusListFlow() + .onStart { TangemLogger.i("$TAG[$walletId]: flow1 accountStatusList subscribed") } + .onEach { list -> + val count = list.flattenCurrencies().size + TangemLogger.i("$TAG[$walletId]: flow1 accountStatusList emitted (currencies=$count)") + }, + flow2 = getAppCurrencyFlow() + .onStart { TangemLogger.i("$TAG[$walletId]: flow2 appCurrency subscribed") } + .onEach { TangemLogger.i("$TAG[$walletId]: flow2 appCurrency emitted=${it.code}") }, + flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet) + .onStart { TangemLogger.i("$TAG[$walletId]: flow3 expandedAccounts subscribed") } + .onEach { TangemLogger.i("$TAG[$walletId]: flow3 expandedAccounts emitted (size=${it.size})") }, + flow4 = accountDependencies.isAccountsModeEnabledUseCase() + .onStart { TangemLogger.i("$TAG[$walletId]: flow4 isAccountsModeEnabled subscribed") } + .onEach { TangemLogger.i("$TAG[$walletId]: flow4 isAccountsModeEnabled emitted=$it") }, + flow5 = yieldSupplyApyFlow() + .onStart { TangemLogger.i("$TAG[$walletId]: flow5 yieldSupplyApy subscribed") } + .onEach { TangemLogger.i("$TAG[$walletId]: flow5 yieldSupplyApy emitted (size=${it.size})") }, + flow6 = yieldSupplyGetShouldShowMainPromoFlow() + .onStart { TangemLogger.i("$TAG[$walletId]: flow6 shouldShowMainPromo subscribed") } + .onEach { TangemLogger.i("$TAG[$walletId]: flow6 shouldShowMainPromo emitted=$it") }, + flow7 = stakingAvailabilityFlow() + .onStart { TangemLogger.i("$TAG[$walletId]: flow7 stakingAvailability subscribed") } + .onEach { TangemLogger.i("$TAG[$walletId]: flow7 stakingAvailability emitted (size=${it.size})") }, + ) { + accountList, appCurrency, expandedAccounts, isAccountMode, + yieldSupplyApyMap, shouldShowMainPromo, stakingAvailabilityMap, + -> + TangemLogger.i( + "$TAG[$walletId]: combine7 transform fired — " + + "currencies=${accountList.flattenCurrencies().size}, " + + "appCurrency=${appCurrency.code}, " + + "expanded=${expandedAccounts.size}, " + + "isAccountMode=$isAccountMode, " + + "apyMap=${yieldSupplyApyMap.size}, " + + "promo=$shouldShowMainPromo, " + + "stakingMap=${stakingAvailabilityMap.size}", ) + if (designFeatureToggles.isRedesignEnabled) { + updateState2( + accountList = accountList, + appCurrency = appCurrency, + expandedAccounts = expandedAccounts, + isAccountMode = isAccountMode, + yieldSupplyApyMap = yieldSupplyApyMap, + stakingAvailabilityMap = stakingAvailabilityMap, + shouldShowMainPromo = shouldShowMainPromo, + ) + } else { + updateState( + accountList = accountList, + appCurrency = appCurrency, + expandedAccounts = expandedAccounts, + isAccountMode = isAccountMode, + yieldSupplyApyMap = yieldSupplyApyMap, + stakingAvailabilityMap = stakingAvailabilityMap, + shouldShowMainPromo = shouldShowMainPromo, + ) + } } } @@ -99,4 +133,8 @@ internal class AccountListSubscriber @AssistedInject constructor( interface Factory { fun create(userWallet: UserWallet): AccountListSubscriber } + + private companion object { + const val TAG = "AccountListSubscriber" + } } \ No newline at end of file