Updated on 2026-08-14
This commit is contained in:
parent
2a8e79ed67
commit
012792e586
7 changed files with 248 additions and 49 deletions
|
|
@ -46,7 +46,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
override suspend fun invoke(params: PaymentAccountStatusFetcher.Params): Either<Throwable, Unit> =
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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<AccountStatus.Payment>
|
||||
get() = AccountStatus.Payment(account = account, value = PaymentAccountStatusValue.Error.Unavailable).some()
|
||||
|
||||
override fun produce(): Flow<AccountStatus.Payment> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String, AccountStatus.Payment>
|
||||
internal typealias WalletIdWithPaymentStatusDM = Map<String, PaymentAccountStatusValueDM>
|
||||
|
||||
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<AccountStatus.Payment> {
|
||||
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) }
|
||||
|
|
|
|||
|
|
@ -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<AccountStatusList> = none()
|
||||
|
||||
override fun produce(): Flow<AccountStatusList> {
|
||||
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<AccountStatusList> = 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<Map<AccountCurrencyId, CryptoCurrency>> = MutableSharedFlow(
|
||||
replay = 1,
|
||||
|
|
@ -108,11 +121,20 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo
|
|||
)
|
||||
|
||||
val accountListFlow: StateFlow<AccountList> = 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<Account.CryptoPortfolio>()
|
||||
.map { account ->
|
||||
|
|
@ -242,14 +283,18 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo
|
|||
): Flow<Map<AccountCurrencyId, CryptoCurrencyStatus>> {
|
||||
val walletId = userWallet.walletId
|
||||
val networkStatusFlow: SharedFlow<Map<Network.ID, NetworkStatus>> = networkStatusFlow(walletId)
|
||||
.onEach { logger.i("flattenCurrencyStatusFlow[$walletId]: networkStatuses emitted size=${it.size}") }
|
||||
.shareIn(this, started = SharingStarted.Eagerly, replay = 1)
|
||||
val stakingBalanceFlow: SharedFlow<Map<StakingID, Set<StakingBalance>>> = stakingFlow(userWallet)
|
||||
.onEach { logger.i("flattenCurrencyStatusFlow[$walletId]: stakingBalances emitted stakingIds=${it.size}") }
|
||||
.shareIn(this, started = SharingStarted.Eagerly, replay = 1)
|
||||
val quoteStatusFlow: SharedFlow<Map<CryptoCurrency.RawID, QuoteStatus>> = 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<AccountCurrencyId, CryptoCurrency> = box.flattenCurrencyMap
|
||||
val networkStatusMap: Map<Network.ID, NetworkStatus> = 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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Boolean> {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
|
@ -97,13 +97,29 @@ class TangemPayMainScreenCustomerInfoUseCase(
|
|||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
): Flow<Either<TangemPayCustomerInfoError, MainCustomerInfoContentState>> {
|
||||
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<TangemPayCustomerInfoError, MainCustomerInfoContentState>,
|
||||
) {
|
||||
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<TangemPayCustomerInfoError, MainScreenCustomerInfo> {
|
||||
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<TangemPayCustomerInfoError, MainScreenCustomerInfo> {
|
||||
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)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue